Search code examples
pythonoptimizationpyomo

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.


Solution

  • 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