3
$\begingroup$

I am currently attempting to solve a network problem that is not fully connected.Thus, I have attempted to do some preprocessing of data so as to form a set of tuples, e.g. $\{(a,b), (c,e),\ldots\}$, i.e. from $a$ to $b$, from $c$ to $e$.

I am able to declare binary decision variables with keys such as $(a,b)$, $(c,e)$ via using the set of tuples for indexing.

However, when I tried to use rules to declare constraints, with decision variables such as x[i][j], errors are thrown stating that $(a,b)$ is an invalid index.

Hence, I would like to ask if tuples can be used as indices for decision variables.

If not, is there a way to only declare the only decision variables that are needed, rather than declaring all, and then setting those unneeded to 0.

Thank you!

$\endgroup$
2
$\begingroup$

It is possible to use tuples as the indices of your variables. If the tuple like $(a_1, a_2)$ is not defined in the index set, errors will be thrown but you can skip those undefined indices by using:

Constraint.Skip

checking if the tuple is defined or not. An example of implementation would be as follow:

model.cons = ConstraintList()        
for i in model.nodes:
    for j in model.nodes:
        if [i,j] in tuples_list:
           model.cons.add("some expressions")
        else:
            Constraint.Skip
| improve this answer | |
$\endgroup$
  • $\begingroup$ Dear Oguz, thank you for your reply. I suppose what you have shown is for concrete models. Could you help me by showing one for abstract models? Thanm you! $\endgroup$ – Mike Jul 23 at 1:27
  • 1
    $\begingroup$ Thanks! I managed to resolve the issue by first iterating to create a set of tuples that will be used for indexing and then invoke the constraint rule via checking all tuples against the set of tuples created for indexing. $\endgroup$ – Mike Jul 24 at 2:41
  • 1
    $\begingroup$ Good job. When I mentioned tuple_list, I meant a predefined set of possible tuples... $\endgroup$ – Oguz Toragay Jul 24 at 2:46
  • $\begingroup$ @Mike if my answers to your questions were useful you can upvote them. This way others with a similar questions can easily find appropriate answers. $\endgroup$ – Oguz Toragay Jul 24 at 2:49
2
$\begingroup$

Yes. Totally doable. Here are 2 examples using either tuples in a pyomo set or just making some up on-the-fly and passing them to a rule-based constraint to make the appropriate number of sparse constraints (seen in the result).

# subsets in tuples

import pyomo.environ as pyo

mdl = pyo.ConcreteModel()

# sets
mdl.I = pyo.Set(initialize=range(4))
mdl.J = pyo.Set(initialize=range(3))
mdl.select_combos = pyo.Set(within = mdl.I * mdl.J, initialize = [(1,2), (3,1)])

# vars
mdl.X = pyo.Var(mdl.I, mdl.J, domain=pyo.NonNegativeReals)

# constraint with rule and tuples from pyomo Set
def c1(self, i, j):
    return mdl.X[i, j] <= 2
mdl.c1 = pyo.Constraint(mdl.select_combos, rule=c1)

# or make a set of tuples of interest on the fly
my_combos = {(i, j) for i in mdl.I for j in mdl.J if
                i <=2 and
                j >=2 }
def c2(self, i, j):
    return mdl.X[i, j] >= 1
mdl.C2 = pyo.Constraint(my_combos, rule=c2)

mdl.pprint()

Output:

6 Set Declarations
    C2_index : Dim=0, Dimen=2, Size=3, Domain=None, Ordered=False, Bounds=None
        [(0, 2), (1, 2), (2, 2)]
    I : Dim=0, Dimen=1, Size=4, Domain=None, Ordered=False, Bounds=(0, 3)
        [0, 1, 2, 3]
    J : Dim=0, Dimen=1, Size=3, Domain=None, Ordered=False, Bounds=(0, 2)
        [0, 1, 2]
    X_index : Dim=0, Dimen=2, Size=12, Domain=None, Ordered=False, Bounds=None
        Virtual
    select_combos : Dim=0, Dimen=2, Size=2, Domain=select_combos_domain, Ordered=False, Bounds=None
        [(1, 2), (3, 1)]
    select_combos_domain : Dim=0, Dimen=2, Size=12, Domain=None, Ordered=False, Bounds=None
        Virtual

1 Var Declarations
    X : Size=12, Index=X_index
        Key    : Lower : Value : Upper : Fixed : Stale : Domain
        (0, 0) :     0 :  None :  None : False :  True : NonNegativeReals
        (0, 1) :     0 :  None :  None : False :  True : NonNegativeReals
        (0, 2) :     0 :  None :  None : False :  True : NonNegativeReals
        (1, 0) :     0 :  None :  None : False :  True : NonNegativeReals
        (1, 1) :     0 :  None :  None : False :  True : NonNegativeReals
        (1, 2) :     0 :  None :  None : False :  True : NonNegativeReals
        (2, 0) :     0 :  None :  None : False :  True : NonNegativeReals
        (2, 1) :     0 :  None :  None : False :  True : NonNegativeReals
        (2, 2) :     0 :  None :  None : False :  True : NonNegativeReals
        (3, 0) :     0 :  None :  None : False :  True : NonNegativeReals
        (3, 1) :     0 :  None :  None : False :  True : NonNegativeReals
        (3, 2) :     0 :  None :  None : False :  True : NonNegativeReals

2 Constraint Declarations
    C2 : Size=3, Index=C2_index, Active=True
        Key    : Lower : Body   : Upper : Active
        (0, 2) :   1.0 : X[0,2] :  +Inf :   True
        (1, 2) :   1.0 : X[1,2] :  +Inf :   True
        (2, 2) :   1.0 : X[2,2] :  +Inf :   True
    c1 : Size=2, Index=select_combos, Active=True
        Key    : Lower : Body   : Upper : Active
        (1, 2) :  -Inf : X[1,2] :   2.0 :   True
        (3, 1) :  -Inf : X[3,1] :   2.0 :   True

9 Declarations: I J select_combos_domain select_combos X_index X c1 C2_index C2
[Finished in 2.5s]
| improve this answer | |
$\endgroup$
  • $\begingroup$ I guess the initialized set in mdl.select_combos = pyo.Set(within = mdl.I * mdl.J, initialize = [(1,2), (3,1)]) would be similar to the tuple set generating for loop in my code. $\endgroup$ – Mike Jul 24 at 6:22
  • 1
    $\begingroup$ Great. If you found any of these answers helpful, it helps to "accept" them with the checkmark to show them as complete, including on the linked question on other site. $\endgroup$ – AirSquid Jul 24 at 15:49
  • $\begingroup$ Dear Jeff, I have already done so before your message. However, as my reputation points are too low, they are not reflected publicly. Thanks. $\endgroup$ – Mike Jul 24 at 16:51
  • $\begingroup$ All good. You should still see a shadowed "check mark" to accept the answer as the original asker. None of these answers appears to have been accepted yet. You only need points to up/down, not to "accept". And yeah, I did find out how that you could change username, so I upgraded....lol $\endgroup$ – AirSquid Jul 24 at 16:53
  • 1
    $\begingroup$ Dear Jeff, thank you for the reminder. Have done so by clicking on the checkmarks. $\endgroup$ – Mike Jul 24 at 17:34
1
$\begingroup$

An example is as follows:

##First, create the set of tuples needed for filtering


#Op_Machine: set of (operation, machine) tuples created to avoid redundancy in decision variable declaration Op_Machine=list() for machine_id, op_proctime in Machine_Op_Time.items():
    for op in op_proctime.keys():
        print(Op_Machine)
        print((op,machine_id))
        Op_Machine.append((op,machine_id))
        print(Op_Machine)

##Next, invoke the rule using the if statement to filter across all possible indices accepting those combinations that are aligned with the tuples within the set
##Use Constraint.Skip to Skip creating constraints that do not belong to the set of tuples


def F1_rule(model,i,k):
    if (i,k) in Op_Machine:
        ##print(i,k)
        return model.Cmax>=model.completion_time[i,k]
    else:
        return Constraint.Skip            
            
#model.makespan= Constraint(model.op_set, model.mach_set, rule=Cmax_rule) model.F1= Constraint(Operation_Set, Machine_Set, rule=F1_rule)

Note that the sets Operation_Set, Machine_Set function as the universal set as it comprises all combinations of operations and machines. Hence the statement model.F1= Constraint(Operation_Set, Machine_Set, rule=F1_rule) can be thought a for loop that iterates over all combinations while the if statement within the def function acts a filter to generate the needed constraints.

| improve this answer | |
$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.