Skip to content
Advertisement

Creating Pyomo’s ConstraintList with a list of constraints rather than adding them individually?

I’m currently storing my Pyomo variables in a Pandas dataframe, and have been using that to generate arrays of constraints.

Is there a way I can add them to my model (e.g. by initialising a ConstraintList with it) rather than having to loop through them all and add them individually? I don’t think I’m able to use a rule to create the constraints because I’m indexing based on my Pandas dataframe.

This is how I’m storing my variables – I’m using Pandas because I find it really easy to index by values in my dataframe:

model.duid_bids = pe.Var(bid_df['DUID_BAND_DATETIME'], domain=pe.PositiveReals)

bid_df['PE_BIDS'] = bid_df['DUID_BAND_DATETIME'].apply(lambda x: model.duid_bids[x])

And I want to do something like this which does not work:

model.bid_volume = pe.Constraint(expr=bid_df['PE_BIDS'] <= bid_df['VOLUME'])

It works if I add them individually like this:

pe.Constraint(expr=bid_df['PE_BIDS'].iloc[0] <= bid_df['VOLUME'].iloc[0])

Thanks so much.

Advertisement

Answer

I think you are trying too hard to push pyomo into a pandas box. :). But that is just an opinion. I don’t see much advantage to doing this because you are not “vectorizing” any operations here as pyomo constraint construction isn’t vectorized.

I would suggest (others may differ) just doing the optimization in pyomo without putting any components into the df, but pulling constants out as needed for constraints. Jury is out on whether I’d put the index set you are using into a pyomo Set, which I think makes things easier to T/S, and pyomo is going to make a virtual set(s) internally anyhow that you can see in the first example below, but that is a side story.

Here are 2 cuts at your construct that I think are workable and disentangle a bit from pandas. This assumes that the datetime you have in your df is unique and can be made into the index for simplicity. (Actually it has to be unique as you are already using it as an indexing set…answered my own question)

import pyomo.environ as pe
import pandas as pd

data = {'DATETIME': [1,2,3],
        'VOLUME': [1000, 2000, 3000]}

df = pd.DataFrame(data)
df.set_index('DATETIME', inplace=True)
print(df.head())  # quick check...

model = pe.ConcreteModel()

model.duid_bids = pe.Var(df.index, domain=pe.PositiveReals)

# volume constraint
def vol_constraint(m, date):
    return model.duid_bids[date] <= df['VOLUME'].loc[date]
model.vol_constraint = pe.Constraint(df.index, rule=vol_constraint)

model.pprint()

############ alternate approach:  full pyomo... ?

model2 = pe.ConcreteModel()

# sets
model2.D = pe.Set(initialize=df.index)

# vars
model2.bid = pe.Var(model2.D, domain=pe.PositiveReals)

# constraint
def vol_constraint2(m, date):
    return model2.bid[date] <= df['VOLUME'][date]
model2.vol_constraint = pe.Constraint(model2.D, rule=vol_constraint2)

model2.pprint()

model2.obj = pe.Objective(expr=sum(model2.bid[date] for date in model2.D), sense=pe.maximize)

solver = pe.SolverFactory('glpk')
status = solver.solve(model2)
print(status)

# stuff the result into the dataframe
df['bid'] = pd.Series(model2.bid.get_values())
print(df)

Generates:

          VOLUME
DATETIME        
1           1000
2           2000
3           3000
2 Set Declarations
    duid_bids_index : Size=1, Index=None, Ordered=False
        Key  : Dimen : Domain : Size : Members
        None :     1 :    Any :    3 : {1, 2, 3}
    vol_constraint_index : Size=1, Index=None, Ordered=False
        Key  : Dimen : Domain : Size : Members
        None :     1 :    Any :    3 : {1, 2, 3}

1 Var Declarations
    duid_bids : Size=3, Index=duid_bids_index
        Key : Lower : Value : Upper : Fixed : Stale : Domain
          1 :     0 :  None :  None : False :  True : PositiveReals
          2 :     0 :  None :  None : False :  True : PositiveReals
          3 :     0 :  None :  None : False :  True : PositiveReals

1 Constraint Declarations
    vol_constraint : Size=3, Index=vol_constraint_index, Active=True
        Key : Lower : Body         : Upper  : Active
          1 :  -Inf : duid_bids[1] : 1000.0 :   True
          2 :  -Inf : duid_bids[2] : 2000.0 :   True
          3 :  -Inf : duid_bids[3] : 3000.0 :   True

4 Declarations: duid_bids_index duid_bids vol_constraint_index vol_constraint

model2 separated for clarity…

1 Set Declarations
    D : Size=1, Index=None, Ordered=Insertion
        Key  : Dimen : Domain : Size : Members
        None :     1 :    Any :    3 : {1, 2, 3}

1 Var Declarations
    bid : Size=3, Index=D
        Key : Lower : Value : Upper : Fixed : Stale : Domain
          1 :     0 :  None :  None : False :  True : PositiveReals
          2 :     0 :  None :  None : False :  True : PositiveReals
          3 :     0 :  None :  None : False :  True : PositiveReals

1 Constraint Declarations
    vol_constraint : Size=3, Index=D, Active=True
        Key : Lower : Body   : Upper  : Active
          1 :  -Inf : bid[1] : 1000.0 :   True
          2 :  -Inf : bid[2] : 2000.0 :   True
          3 :  -Inf : bid[3] : 3000.0 :   True

3 Declarations: D bid vol_constraint

Problem: 
- Name: unknown
  Lower bound: 6000.0
  Upper bound: 6000.0
  Number of objectives: 1
  Number of constraints: 4
  Number of variables: 4
  Number of nonzeros: 4
  Sense: maximize
Solver: 
- Status: ok
  Termination condition: optimal
  Statistics: 
    Branch and bound: 
      Number of bounded subproblems: 0
      Number of created subproblems: 0
  Error rc: 0
  Time: 0.010575056076049805
Solution: 
- number of solutions: 0
  number of solutions displayed: 0

          VOLUME     bid
DATETIME                
1           1000  1000.0
2           2000  2000.0
3           3000  3000.0
User contributions licensed under: CC BY-SA
10 People found this is helpful
Advertisement