How to define constraints in Pyomo using sets and variables

I am trying to model the transportation problem of Dantzig in Pyomo (see the GAMS code here https://www.gams.com/latest/gamslib_ml/libhtml/gamslib_trnsport.html or the description here https://www.math.uh.edu/~rohop/fall_06/Chapter1.pdf).

I have problem defining the constraints for the supply using sets and variables. So basically what I want to do is to add the constraints: For all set_plants Sum over all set_markets x(set_plants, set_markets) <= param_capacityOfPlant (set_plants)

in GAMS it is this line

supply(i).. sum(j, x(i,j)) =l= a(i);

and in the description (https://www.math.uh.edu/~rohop/fall_06/Chapter1.pdf) it is equation 1.2

I am struggeling to implement this in Pyomo. I tried different things and I always get the error "TypeError: Cannot apply a Set operator to an indexed Var component (variable_x)"

Here you can see my code in which the lines at the very bottom are problematic (after #Constraints):

# -*- coding: utf-8 -*-
"""
Transport problem in Pyomo

Created on Mon Feb 15 09:55:06 2021

"""

import pyomo.environ as pyo

#Define the model

model = pyo.ConcreteModel()

#Define the sets
model.set_plants = pyo.Set(initialize=['Seattle', 'San_Diego'])
model.set_markets = pyo.Set(initialize=['New_York', 'Chicago', 'Topeka'])

# Parameters

valuesForCapacity = {'Seattle':350, 'San_Diego':600}
valuesForDemand = {'New_York': 325, 'Chicago': 300, 'Topeka': 275}

model.param_capacityOfPlants = pyo.Param(model.set_plants, initialize=valuesForCapacity)
model.param_demandAtMarkets = pyo.Param(model.set_markets, initialize=valuesForDemand)

model.param_capacityOfPlants.pprint()
model.param_demandAtMarkets.pprint()

#Parameter entry as table

valuesForDistance =  {('Seattle', 'New_York'): 2.5, ('Seattle', 'Chicago'): 1.7, ('Seattle', 'Topeka'): 1.8,
('San_Diego', 'New_York'): 2.5, ('San_Diego', 'Chicago'): 1.8, ('San_Diego', 'Topeka'): 1.4}

model.param_distances = pyo.Param(model.set_plants, model.set_markets, initialize=valuesForDistance)

model.param_distances.pprint()

#Scalar
freightCostsPerUnitPerThousandMiles = 90

#Variables

model.variable_x = pyo.Var(model.set_plants,model.set_markets, within=pyo.NonNegativeReals)
model.variable_totalCosts = pyo.Var()

model.variable_x.pprint()

#Constraints

def supplyConstraintRule(model):
#First try
# return pyo.summation(variable_x)<=model.param_capacityOfPlants
#Second try
#return sum(variable_x for j in model.set_markets)<=model.param_capacityOfPlants
# Third try
return sum(variable_x(i,j) for j in model.set_markets)<=model.param_capacityOfPlants(i)

model.constraint_supply = pyo.Constraint (model.variable_x, rule=supplyConstraintRule)

Do you know how I have to implement this? I'd appreciate every comment from you.

• Would you see this link? Feb 15 '21 at 12:26

Replace the Def and last line of your code with the following lines:

model.constraint_supply = pyo.ConstraintList()
for i in model.set_plants:
model.constraint_supply.add(sum(model.variable_x[i, j] for j in model.set_markets) <= model.param_capacityOfPlants[i])
model.constraint_supply.pprint()

The output will be as follow:

constraint_supply : Size=2, Index=constraint_supply_index, Active=True
Key : Lower : Body                                                                                          : Upper : Active
1 :  -Inf :       variable_x[Seattle,New_York] + variable_x[Seattle,Chicago] + variable_x[Seattle,Topeka] : 350.0 :   True
2 :  -Inf : variable_x[San_Diego,New_York] + variable_x[San_Diego,Chicago] + variable_x[San_Diego,Topeka] : 600.0 :   True

Instead of using Def I used for loop for constraint definitions. If the constraints are not correct you can play with the for loop mentioned here. Generally there is no difference in the output of these two approaches in defining the constraints.

Edit: the following changes in your code solve the problem of using Def:

def supplyConstraintRule(model,i):
# First try
# return pyo.summation(variable_x)<=model.param_capacityOfPlants
# Second try
# return sum(variable_x for j in model.set_markets)<=model.param_capacityOfPlants
# Third try
return sum(model.variable_x[i, j] for j in model.set_markets) <= model.param_capacityOfPlants[i]

model.constraint_supply = pyo.Constraint(model.set_plants, rule=supplyConstraintRule)
• Thanks for your answer Oguz. I do you not use the def operator and rather use ConstraintList()? Most of the Pyomo code (especially in tutorials) use the def operator to define a function for a constraint. What is the difference between a pyo.Constraint and a pyo.ConstraintList? Feb 15 '21 at 17:37
• In pyo.ConstraintList you generate a block of constraint type objects to which you can add constraint inside a for loop using pyo.ConstraintList.add('your constraint'). But in pyo.Constraint you will define a single constraint for which you can use Def by passing the necessary indices for your constraint. Generally there is no difference between the generated constraints either by using def or using ConstraintList. Feb 15 '21 at 17:42
• Thanks a lot Oguz for your answer and effort. I really appreciate it. How would this look like when just using the pyo.Constraint command? Can you tell me that if it is not too timeconsuming for you? Or would you generally advice me to always use teh pyo.ConstraintList object? Feb 15 '21 at 17:56
• I edited my answer and included what would be the code while using the Def. Good luck Feb 15 '21 at 18:10
• @PeterBe it’s all about Pyomo’s syntax. Feb 16 '21 at 8:53