Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How can I add constraints that include two indices simultaneously ? #57

Open
Amoozegar opened this issue Jul 31, 2023 · 6 comments
Open
Assignees
Labels
documentation Improvements or additions to documentation

Comments

@Amoozegar
Copy link

I need to add constraints that include two indices on a same variable. Here is an example:

image

@Amoozegar Amoozegar changed the title In Gurobipy-pandas ,how can I add constraints that include two indices simultaneously ? How can I add constraints that include two indices simultaneously ? Jul 31, 2023
@simonbowly
Copy link
Member

Hi @Amoozegar, for a continuous index you can use pandas' shift method to align the left and right hand sides of your constraint on the same index:

import pandas as pd
import gurobipy as gp
from gurobipy import GRB
import gurobipy_pandas as gppd

J = 5
model = gp.Model()

F = gppd.add_vars(model, pd.RangeIndex(1, J+1), name="F")

index = pd.RangeIndex(1, J)      # 1 .. J-1 index for constraints
constraints = gppd.add_constrs(
    model,
    F.shift(-1).loc[index],      # Shift F[j+1] term onto index j
    GRB.LESS_EQUAL,
    F.loc[index]
)

After updating the model you can check the result as follows:

>>> model.update()
>>> constraints.apply(model.getRow)
1    -1.0 F[1] + F[2]
2    -1.0 F[2] + F[3]
3    -1.0 F[3] + F[4]
4    -1.0 F[4] + F[5]
dtype: object
>>> constraints.gppd.Sense
1    <
2    <
3    <
4    <
dtype: object
>>> constraints.gppd.RHS
1    0.0
2    0.0
3    0.0
4    0.0
dtype: float64

@rrandall1471
Copy link

rrandall1471 commented Jul 31, 2023

@Amoozegar I would do it a bit differently than @simonbowly

If I started with the following df/series of variables:

image

I would do it with the following pandas .assign and .shift to do it all in one command, with the built in gurobipy-pandas accessor to add the constraint:

(
    df.assign(f_j_plus_1=lambda df: df["f_j"].shift(-1))
    .dropna()
    .gppd.add_constrs(
        model, "f_j_plus_1", grb.GRB.LESS_EQUAL, "f_j", name="constr_name"
    )
)

Which yields the following constraints:

Subject To
 constr_name[0]: - f[0] + f[1] <= 0
 constr_name[1]: - f[1] + f[2] <= 0
 constr_name[2]: - f[2] + f[3] <= 0
 constr_name[3]: - f[3] + f[4] <= 0
 constr_name[4]: - f[4] + f[5] <= 0
 constr_name[5]: - f[5] + f[6] <= 0
 constr_name[6]: - f[6] + f[7] <= 0
 constr_name[7]: - f[7] + f[8] <= 0
 constr_name[8]: - f[8] + f[9] <= 0

@Amoozegar
Copy link
Author

Thanks for the response. How about formulating "Fi,j+1,z <= Fi,j,z" ?

@rrandall1471
Copy link

Sure. You have to use a groupby then a shift to do that. Let's say we start with the following variables over i, j, and z

image

I can create a new column that contains the shifted variables using the following code:

df.assign(f_ij_plus_1z=lambda df: df["f_ijz"].groupby(['i', 'z']).shift(-1)).dropna()

which would yield the following DataFrame.

image

Then finally I can take that same code and using the gurobipy-pandas accessor can create the constraints:

(
    df.assign(f_ij_plus_1z=lambda df: df["f_ijz"].groupby(['i', 'z']).shift(-1))
    .dropna()
    .gppd.add_constrs(
        model, "f_ij_plus_1z", grb.GRB.LESS_EQUAL, "f_ijz", name="constr_name"
    )
)

And you can see it in the LP file written out:

Subject To
 constr_name[0,0,0]: - f[0,0,0] + f[0,1,0] <= 0
 constr_name[0,0,1]: - f[0,0,1] + f[0,1,1] <= 0
 constr_name[0,0,2]: - f[0,0,2] + f[0,1,2] <= 0
 constr_name[0,1,0]: - f[0,1,0] + f[0,2,0] <= 0
 constr_name[0,1,1]: - f[0,1,1] + f[0,2,1] <= 0
 constr_name[0,1,2]: - f[0,1,2] + f[0,2,2] <= 0
 constr_name[0,2,0]: - f[0,2,0] + f[0,3,0] <= 0
 constr_name[0,2,1]: - f[0,2,1] + f[0,3,1] <= 0
 constr_name[0,2,2]: - f[0,2,2] + f[0,3,2] <= 0
 constr_name[1,0,0]: - f[1,0,0] + f[1,1,0] <= 0
 constr_name[1,0,1]: - f[1,0,1] + f[1,1,1] <= 0
 constr_name[1,0,2]: - f[1,0,2] + f[1,1,2] <= 0
 constr_name[1,1,0]: - f[1,1,0] + f[1,2,0] <= 0
 constr_name[1,1,1]: - f[1,1,1] + f[1,2,1] <= 0
 constr_name[1,1,2]: - f[1,1,2] + f[1,2,2] <= 0
 constr_name[1,2,0]: - f[1,2,0] + f[1,3,0] <= 0
 constr_name[1,2,1]: - f[1,2,1] + f[1,3,1] <= 0
 constr_name[1,2,2]: - f[1,2,2] + f[1,3,2] <= 0
 constr_name[2,0,0]: - f[2,0,0] + f[2,1,0] <= 0
 constr_name[2,0,1]: - f[2,0,1] + f[2,1,1] <= 0
 constr_name[2,0,2]: - f[2,0,2] + f[2,1,2] <= 0
 constr_name[2,1,0]: - f[2,1,0] + f[2,2,0] <= 0
 constr_name[2,1,1]: - f[2,1,1] + f[2,2,1] <= 0
 constr_name[2,1,2]: - f[2,1,2] + f[2,2,2] <= 0
 constr_name[2,2,0]: - f[2,2,0] + f[2,3,0] <= 0
 constr_name[2,2,1]: - f[2,2,1] + f[2,3,1] <= 0
 constr_name[2,2,2]: - f[2,2,2] + f[2,3,2] <= 0

@simonbowly simonbowly added the documentation Improvements or additions to documentation label Oct 2, 2023
@simonbowly simonbowly self-assigned this Oct 2, 2023
@simonbowly
Copy link
Member

I think it's worth adding these to the documentation as examples. Probably a time-indexed formulation of some kind is the logical place to showcase it.

@rrandall1471
Copy link

I think it's worth adding these to the documentation as examples. Probably a time-indexed formulation of some kind is the logical place to showcase it.

That makes sense.

@simonbowly simonbowly added this to the Version 1.1 milestone Oct 16, 2023
@simonbowly simonbowly removed this from the 1.1.0 release milestone Nov 2, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
documentation Improvements or additions to documentation
Projects
None yet
Development

No branches or pull requests

3 participants