I'm new-ish to pyomo, and I was curious about how I could start to implement the following constraint in pyomo.
My constraint is over a set that is also indexed over a range-set k. There is no assumption that the amount of elements in the set for a specific k value is uniform across all k. I couldn't find a similar example to this in the documentation, that makes me question if this is even doable in pyomo.
Any suggestions and/or directions to sample codes would be greatly appreciated. Or a suggestion of how to repose this constraint so it would be "pyomo friendly" would be awesome too!
EDIT: As asked by a user - d is a known number that is unique to the given tuple in A_k for a given k value. To be precise for a given k, A_k can be defined as {(p_n_1,q_n_1,d_n_1), ....., (p_n_k,q_n_k,q_n_k)}. The given k value will determine the size of A_k.
I made some assumptions in making this as the specification is a bit incomplete, but I think you are looking to do something like this. Of course this gets huge quickly because you have a 6-tuple indexed variable.
Looking at this a second time, I think I made a wrong assumption in the first option below that y
was indexed by k
. If you intend to just gather the tuples associated with k
and k + 1
then the 2nd option is likely what you want.
# constraint over members of indexed set
import pyomo.environ as pyo
m = pyo.ConcreteModel()
m.T = pyo.Set(initialize=[1, 2, 3])
m.K = pyo.Set(initialize=[1, 2, 3])
m.I = pyo.Set(initialize=[4, 5, 6])
m.J = pyo.Set(initialize=[7, 8, 9])
m.P = pyo.Set(initialize=[10, 13, 22])
m.Q = pyo.Set(initialize=[11, 14, 24])
m.D = pyo.Set(initialize=[12, 15, 19])
m.A = pyo.Set(m.K, within=m.P*m.Q*m.D, initialize={ 1: [(10, 11, 12), (13, 14, 15)],
2: [(22, 24, 19),],
3: [(10, 11, 15),]})
m.y = pyo.Var(m.K, m.P, m.Q, m.I, m.J, m.T, domain=pyo.Binary)
# flatten out the nested reference to A_k...
m.A_k_flat = pyo.Set(dimen=4, initialize=[(k, p, q, d) for k in m.K for (p, q, d) in m.A[k] ])
@m.Constraint(m.A_k_flat)
def nested_constraint(m, k, p, q, d):
if k == m.K.last():
return pyo.Constraint.Skip
sum_1 = sum(m.y[k, p, q, i, j, t]*t + 1 for i in m.I for j in m.J for t in m.T)
sum_2 = sum(m.y[m.K.next(k), p, q, i, j, t]*t for i in m.I for j in m.J for t in m.T)
return sum_1 <= sum_2
m.pprint()
# constraint over members of indexed set
import pyomo.environ as pyo
m = pyo.ConcreteModel()
m.T = pyo.Set(initialize=[1, 2, 3])
m.K = pyo.Set(initialize=[1, 2, 3])
m.I = pyo.Set(initialize=[4, 5, 6])
m.J = pyo.Set(initialize=[7, 8, 9])
m.P = pyo.Set(initialize=[10, 13, 22])
m.Q = pyo.Set(initialize=[11, 14, 24])
m.D = pyo.Set(initialize=[12, 15, 19])
m.A = pyo.Set(m.K, within=m.P*m.Q*m.D, initialize={ 1: [(10, 11, 12), (13, 14, 15)],
2: [(22, 24, 19),],
3: [(10, 11, 15),]})
m.y = pyo.Var(m.P, m.Q, m.I, m.J, m.T, domain=pyo.Binary)
# flatten out the nested reference to A_k... and flatten again for k, k+1 capture
m.A_k_pairs_flat = pyo.Set(dimen=6, initialize=[(p, q, d, pp, qq, dd)
for k in m.K-{m.K.last(), } # subset of m.K without last element
for (p, q, d) in m.A[k] # the tuple for k
for (pp, qq, dd) in m.A[m.K.next(k)] ]) # the tuple for k+1
@m.Constraint(m.A_k_pairs_flat)
def nested_constraint(m, p, q, d, pp, qq, dd):
sum_1 = sum(m.y[p, q, i, j, t]*t + 1 for i in m.I for j in m.J for t in m.T)
sum_2 = sum(m.y[pp, qq, i, j, t]*t for i in m.I for j in m.J for t in m.T)
return sum_1 <= sum_2
m.A_k_pairs_flat.pprint()
A_k_pairs_flat : Size=1, Index=None, Ordered=Insertion
Key : Dimen : Domain : Size : Members
None : 6 : Any : 3 : {(10, 11, 12, 22, 24, 19), (13, 14, 15, 22, 24, 19), (22, 24, 19, 10, 11, 15)}
[Finished in 361ms]