sos over 1 dimension

132 views
Skip to first unread message

Wiet Mazairac

unread,
Feb 21, 2019, 9:20:21 AM2/21/19
to Pyomo Forum
Hi,

I have this snippet of code...
model = pmo.ConcreteModel()
model
.A = pmo.Set(initialize = range(7), ordered = True)
model
.B = pmo.Set(initialize = range(3), ordered = True)
model
.x = pmo.Var(model.A, model.B, domain=pmo.Binary, initialize = 0)


model
.c_sos = pmo.SOSConstraint(var = model.x, sos = 1)

The result is this ....
(0, 0) : 1.0
(0, 1) : -0.0
(0, 2) : -0.0
(1, 0) : -0.0
(1, 1) : -0.0
(1, 2) : -0.0

However I want to result to be like this ...
(0, 0) : 1.0
(0, 1) : -0.0
(0, 2) : -0.0
(1, 0) : 1.0
(1, 1) : -0.0
(1, 2) : -0.0

How to apply the sos constraint to every row separately instead of applying is to the full matrix?
Is it possible to use a rule when setting up a sos constraint, similar to using rules when setting up normal constraints?



David Woodruff

unread,
Feb 21, 2019, 1:55:18 PM2/21/19
to pyomo...@googlegroups.com
Hello,
   This is supposed to be a way to do this, but there seems to be a bug. I submitted a bug report, but if are in a hurry you will have to suffer the pain of breaking up your Var to be one row per Var, I think.
   Dave

--
You received this message because you are subscribed to the Google Groups "Pyomo Forum" group.
To unsubscribe from this group and stop receiving emails from it, send an email to pyomo-forum...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
Message has been deleted

Miguel Muñoz

unread,
Mar 10, 2021, 9:30:46 AM3/10/21
to Pyomo Forum
Hello, 

I have the same issue. I couldn't make the standard SOSConstraint work. It seems there is a bug as mentioned by DLWoodruff (https://github.com/Pyomo/pyomo/issues/875). In the meantime I manged to come up with a work around. I created this function (working in Pyomo 5.7.3):

def add_sos_constraint_to_array_var(var, sos, weights=None, constraint_index='first', cl_name='con_sos'):

    from itertools import product

    model = var.parent_block()
    first, second = var._index.subsets() # First and second index of the variable
    weight_dict = None

    if constraint_index == 'first':
        for i, idx in enumerate(first):
            set_idx = set(product((idx,), set(second.keys())))
            if weights:
                weight_dict = {ii: weights[ii[1]] for ii in set_idx}
            exec(f'model.{cl_name}_{i} = pe.SOSConstraint(index=set_idx, var=var, sos=sos, weights=weight_dict)')

    elif constraint_index == 'second':
        for i, idx in enumerate(second):
            set_idx = set(product(set(first.keys()), (idx,)))
            if weights:
                weight_dict = {ii: weights[ii[0]] for ii in set_idx}
            exec(f'model.{cl_name}_{i} = pe.SOSConstraint(index=set_idx, var=var, sos=sos, weights=weight_dict)')
    else:
        raise ValueError('Invalid constrain index. Select first or second.')


Then you can do:

add_sos_constraint_to_array_var(var=model.x, sos=1, constrain_index='first')

In your case this will create 7 constraints named con_sos_0 to con_sos_6:

model.con_sos_0.pprint()

   con_sos_0 : Size=1 
Type=1
Weight : Variable
1 : x[0,1]
2 : x[0,0]
3 : x[0,2]

To obtain the opposite result:

add_sos_constraint_to_array_var(var=model.x, sos=1, constrain_index='second')

model.con_sos_0.pprint()

   c_sos_0 : Size=1 
Type=1
Weight : Variable
1 : x[0,0]
2 : x[3,0]
3 : x[6,0]
4 : x[2,0]
5 : x[5,0]
6 : x[1,0]
7 : x[4,0]

Note that the weights of the variables are not ordered as one may expect. Therefore is always advisable to indicate the weights:

add_sos_constraint_to_array_var(var=model.x, sos=1, cl_name='cc_sos', weights={0: 2, 1: 4, 2: 6})

model.cc_sos_1.pprint()

   cc_sos_1 : Size=1 
Type=1
Weight : Variable
6 : x[1,2]
2 : x[1,0]
4 : x[1,1]
Reply all
Reply to author
Forward
0 new messages