Search code examples
pythonoptimizationpyomo

pyomo: how to index Variable in only part of a Set?


I am trying to keep track of SOCs in a pyomo optimization model. I have number of BEVs and I want to keept track of eachs SOC. The xpression I pass to pe.Objective looks like the following:

sum(sum(model.SOC[t+1, b] - model.SOC[t, b] for b in model.buses) for t in model.times)

model.buses and model.times are two Sets I have declared as pe.Set. The times go from (0, ...., 95). So in the last iteration for the model.times it tries to access model.SOC[96, b] what leads to a KeyError.

Is there a way to tell pyomo to leafe out the last element of the set to prevent this Error?

Somethin like:

sum(sum(model.SOC[t+1, b] - model.SOC[t, b] for b in model.buses) for t in model.times[0:-2])

which sadly also raises an Error:

IndexError: times indices must be integers, not slice

here is a minmal example that should reproduce the Error:

import pyomo.environ as pe

solver = pe.SolverFactory('glpk')
model = pe.ConcreteModel('Test')
model.times = pe.Set(initialize=list(range(96)))
model.buses = pe.Set(initialize=list(range(5)))
model.SOC = pe.Var(model.times*model.buses, domain=pe.PositiveReals)

def example_rule(model):
    return sum(sum(model.SOC[t+1, b] - model.SOC[t, b] for b in model.buses) for t in model.times)

model.obj = pe.Objective(rule=example_rule, sense=pe.maximize)

model.pprint()

Many thanks in advance!


Solution

  • Yes, there are a couple ways to do this. First, if the set that you want to index into is ordered (which is default), you can use the first, last, and prev methods on the set in various ways. (see my edits to your code below)

    Second, you can always construct your own subset and either place it in the model or not. Second model below shows construction of an arbitrarily complicated subset and puts it in the model. This set could be used as basis for an objective or constraint.

    This solution is similar to this answer

    import pyomo.environ as pe
    
    solver = pe.SolverFactory('glpk')
    model = pe.ConcreteModel('Test')
    model.times = pe.Set(initialize=list(range(5)), ordered=True)  # ordered is default, this is for clarity...
    model.buses = pe.Set(initialize=list(range(2)))
    model.SOC = pe.Var(model.times*model.buses, domain=pe.PositiveReals)
    
    def example_rule(model):
        return sum(sum(model.SOC[t+1, b] - model.SOC[t, b] for b in model.buses) for t in model.times if t != model.times.last())
    
    model.obj = pe.Objective(rule=example_rule, sense=pe.maximize)
    
    model.pprint()
    
    
    # making your own subset...
    times = 10
    model2 = pe.ConcreteModel("other")
    model2.times = pe.Set(initialize=range(times))
    # make a subset of the even values that are no more than 4 values close to the end....
    model2.times_subset = pe.Set(initialize=[t for t in model2.times if t%2==0 and t <= times-4])
    
    model2.pprint()
    

    Yields:

    3 Set Declarations
        SOC_index : Size=1, Index=None, Ordered=True
            Key  : Dimen : Domain      : Size : Members
            None :     2 : times*buses :   10 : {(0, 0), (0, 1), (1, 0), (1, 1), (2, 0), (2, 1), (3, 0), (3, 1), (4, 0), (4, 1)}
        buses : Size=1, Index=None, Ordered=Insertion
            Key  : Dimen : Domain : Size : Members
            None :     1 :    Any :    2 : {0, 1}
        times : Size=1, Index=None, Ordered=Insertion
            Key  : Dimen : Domain : Size : Members
            None :     1 :    Any :    5 : {0, 1, 2, 3, 4}
    
    1 Var Declarations
        SOC : Size=10, Index=SOC_index
            Key    : Lower : Value : Upper : Fixed : Stale : Domain
            (0, 0) :     0 :  None :  None : False :  True : PositiveReals
            (0, 1) :     0 :  None :  None : False :  True : PositiveReals
            (1, 0) :     0 :  None :  None : False :  True : PositiveReals
            (1, 1) :     0 :  None :  None : False :  True : PositiveReals
            (2, 0) :     0 :  None :  None : False :  True : PositiveReals
            (2, 1) :     0 :  None :  None : False :  True : PositiveReals
            (3, 0) :     0 :  None :  None : False :  True : PositiveReals
            (3, 1) :     0 :  None :  None : False :  True : PositiveReals
            (4, 0) :     0 :  None :  None : False :  True : PositiveReals
            (4, 1) :     0 :  None :  None : False :  True : PositiveReals
    
    1 Objective Declarations
        obj : Size=1, Index=None, Active=True
            Key  : Active : Sense    : Expression
            None :   True : maximize : SOC[1,0] - SOC[0,0] + SOC[1,1] - SOC[0,1] + SOC[2,0] - SOC[1,0] + SOC[2,1] - SOC[1,1] + SOC[3,0] - SOC[2,0] + SOC[3,1] - SOC[2,1] + SOC[4,0] - SOC[3,0] + SOC[4,1] - SOC[3,1]
    
    5 Declarations: times buses SOC_index SOC obj
    2 Set Declarations
        times : Size=1, Index=None, Ordered=Insertion
            Key  : Dimen : Domain : Size : Members
            None :     1 :    Any :   10 : {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
        times_subset : Size=1, Index=None, Ordered=Insertion
            Key  : Dimen : Domain : Size : Members
            None :     1 :    Any :    4 : {0, 2, 4, 6}
    
    2 Declarations: times times_subset
    [Finished in 553ms]