Having a simplified problem: I'd like to assign an instance ID anywhere in in the instance_map. The goal is to have the ID's uniquely distributed over the instance_map, so each ID should occur exatcly once.
Pyomo in turn raises that this task is unfeasbile and most surprisingly started assigning with floats in an integer domain. Here's the code
import pyomo.environ as pe
model = pe.ConcreteModel()
model.rows = pe.RangeSet(1, 2)
model.cols = pe.RangeSet(1, 5)
model.instances = pe.RangeSet(1, 5)
model.n_instances = pe.Var(initialize=5)
model.n_cols = pe.Var(initialize=5)
model.n_rows = pe.Var(initialize=2)
model.instances_map = pe.Var(model.rows, model.cols, within=pe.Integers, initialize=0, bounds=(0, model.n_instances.value))
def unique_instances_check(model, instance):
if instance == 0:
return sum(model.instances_map[i,j] == instance for i in model.rows for j in model.cols) >= 0
else:
return sum(model.instances_map[i,j] == instance for i in model.rows for j in model.cols) == 1
model.C1 = pe.Constraint(model.instances, rule=unique_instances_check)
def objective(model):
return sum(model.instances_map[1,j] for j in model.cols)
model.obj = pe.Objective(rule=objective, sense=pe.minimize)
opt = pe.SolverFactory("ipopt").solve(model)
model.instances_map.pprint()
When running it I get the the following output for the last code line
WARNING: Loading a SolverResults object with a warning status into
model.name="unknown";
- termination condition: infeasible
- message from solver: Ipopt 3.14.5\x3a Converged to a locally
infeasible point. Problem may be infeasible.
instances_map : Size=10, Index=instances_map_index
Key : Lower : Value : Upper : Fixed : Stale : Domain
(1, 1) : 0 : 5.000000049983252 : 5 : False : False : Integers
(1, 2) : 0 : 5.000000049983252 : 5 : False : False : Integers
(1, 3) : 0 : 5.000000049983252 : 5 : False : False : Integers
(1, 4) : 0 : 5.000000049983252 : 5 : False : False : Integers
(1, 5) : 0 : 5.000000049983252 : 5 : False : False : Integers
(2, 1) : 0 : 5.000000049983252 : 5 : False : False : Integers
(2, 2) : 0 : 5.000000049983252 : 5 : False : False : Integers
(2, 3) : 0 : 5.000000049983252 : 5 : False : False : Integers
(2, 4) : 0 : 5.000000049983252 : 5 : False : False : Integers
(2, 5) : 0 : 5.000000049983252 : 5 : False : False : Integers
I was expecting many 0 assignments but 1,2,3,4,5 only once.
I'm honestly not sure where to go from here
First, your problem is not converging to a feasible point, so there is no guarantee that the returned solution respects any constraints or bounds.
More importantly, ipopt is a continuous interior point solver and ignores discrete domains. If you look at the solver output (by adding tee=True' to the solve call), you should see:
==> Warning: Treating __ binary and __ integer variables as continous.
at the top of the solver output log.
Related
I am having trouble creating multiple constraints with a single rule. The problem is the following:
I have "n" decision variables in my problem and I have "m" constraints formed by the sum of some of the decision variables, if for example (n=7) and (m=3), the constraints could be the following:
n1+n2+n3+n4=m1
n3+n4+n5=m2
n5+n6+n7=m3
The index of the decision variables I have it in a list and m value of each constraint I have it in a dictionary.
N = [1,2,3,4,5,6,7]
M = {1:20,2:12,3:18}
I define the variables
model.N = Var(N, within=NonNegativeReals)
The variables that I have to add in each constraint I have them stored in a dictionary, so that the key of each element of the dictionary represents the constraint m and the value is a list formed by the decision variables that are part of the constraint.
d = {1: [1,2,3,4], \
2: [3,4,5], \
3: [5,6,7],}
I have tried two different codes. The first one is shown below
def node_limit_rule (model,m):
# We extract the list that defines each constraint.
constraint_list = d.values()
for element in constraint_list:
ConcreteConstraint=element
return sum(model.N[cc] for cc in ConcreteConstrain) <= d[cc] for cc in ConcreteConstrains)
model.node_limit = Constraint(mydataWFLP.M, rule=node_limit_rule)
Using this code what I get is always the first constraint repeated m times
Key : Lower : Body : Upper : Active
1 : -Inf : N[1] + N[2] + N[3] + N[4] : 20.0 : True
2 : -Inf : N[1] + N[2] + N[3] + N[4] : 20.0 : True
3 : -Inf : N[1] + N[2] + N[3] + N[4] : 20.0 : True
When in fact it should be as follows
Key : Lower : Body : Upper : Active
1 : -Inf : N[1] + N[2] + N[3] + N[4] : 20.0 : True
2 : -Inf : N[3] + N[4] + N[5] : 12.0 : True
3 : -Inf : N[5] + N[6] + N[7] : 18.0 : True
What am I doing wrong? How can I fix it?
The second code I have tried is the following
constraint_list = d.values()
for element in constraint_list:
ConcreteConstraint=element
for m in M:
def node_limit_rule (model):
return sum(model.N[cc] for cc in ConcreteConstrain) <= d[cc] for cc in ConcreteConstrains)
model.node_limit = Constraint(mydataWFLP.M,rule=node_limit_rule)
But in this case I get only get one equation. Specifically the third one
Key : Lower : Body : Upper : Active
None : -Inf : N[5] + N[6] + N[7] : 18 : True
I think I should store each iteration of the for loop in a variable. Something similar to what is shown below but I don't know how to do it.
model.node_limit_1
model.node_limit_2
model.node_limit_3
I am new to Pyomo.
I wrote this constraint in Pyomo written below as shown in this equation:
model.amount_of_energy_con = pe.ConstraintList()
for t in model.time:
for b in model.boats:
for s in model.chargers:
lhs = model.charge_energy[b, t, s]
rhs = model.c_rating[s] * model.boat_battery_capacity * model.boats_availability[b][t] * model.charging[b, t, s]
model.amount_of_energy_con.add(expr= (lhs <= rhs))
For the Constraint above, I think my constraint should be something like this in the model object
Key : Lower : Body : Upper : Active
1 : -Inf : charge_energy[1,0,SC] : 15.75*charging[1,0,SC] : True
2 : -Inf : charge_energy[1,0,FC] : 126*charging[1,0,FC] : True
But I was getting this below using model.amount_of_energy_con.pprint()
Key : Lower : Body : Upper : Active
1 : -Inf : charge_energy[1,0,SC] - 15.75*charging[1,0,SC] : 0.0 : True
2 : -Inf : charge_energy[1,0,FC] - 126*charging[1,0,FC] : 0.0 : True
Note: The 0 in the equation was added as bounds when setting up the model.charge_energy Variable model.charge_energy = pe.Var(model.boats, model.time, model.chargers, bounds=(0, None)) and I still don't understand why my Lower is -Inf.
What am I doing wrong?
I am just starting with Pyomo and I have a big problem. I want to create an Abstract Model and use AMPL data format to feed it.
The question is a classic transportation problem. I need to find the optimal solution for cost. M means if the shipment is impossible between a given source and destination, a large cost of M is entered. I need to convert it into AMPL data. Apart from this, I do not know how to create this abstract model. The code for this table and model are shown below. Also after reading this problem, I created the mathematical model as follows.
[the mathematical model that I created][1]
[the classic transportation problem tabel][2]
from __future__ import division
from pyomo.environ import *
model = AbstractModel()
model.I = Set()
model.J = Set()
model.a = Param(model.I)
model.b = Param(model.J)
model.cost = Param(model.I,model.J)
model.supply = Var(model.I,model.J)
def obj_expression(model):
return sum(model.supply[i,j] * model.cost[i,j] for i in model.I for j in model.J)
model.OBJ = Objective(rule=obj_expression)
def ax_constraint_rule_1(model, i):
return sum(model.supply[i,j] for j in model.J )<= model.a[i]
def ax_constraint_rule_2(model, j):
return sum(model.supply[i,j] for i in model.I )>= model.b[j]
model.AxbConstraint = Constraint(model.I, rule=ax_constraint_rule_1)
model.AxbConstraint_2 = Constraint(model.J, rule=ax_constraint_rule_2)
pyomo solve --solver=glpk test.py transportation_data.dat
model.pprint()
set I := D1 D2 D3 ;
set J := S1 S2 S3 ;
param cost :=
S1 D1 3
S1 D2 1
S2 D1 4
S2 D2 2
S2 D3 4
S3 D2 3
S3 D3 3
;
param b :=
D1 7
D2 3
D3 5 ;
param a:=
S1 5
S2 7
S3 3
;
Any help with this code? Really need help with the model creation and AMPL data construction.
Thanks anyway
===============================================
The result
File "E:/pycharm_project/test.py", line 28
pyomo solve --solver=glpk test.py transportation_data.dat
^
SyntaxError: invalid syntax```
[1]: https://i.stack.imgur.com/DoWXA.png
[2]: https://i.stack.imgur.com/Fwmjb.png
Well, you are close, I think. You have a few things to clean up.
You do NOT need model.m and model.n I'm not sure what you are trying to do there.
For the sets, I and J, just list them as Set(), because you are providing values for them in your AMPL data. Like:
model.I = Set()
model.J = Set()
In your formulation you are double indexing c[i,j] but in your formulation and data, c is only indexed by model.I
Similarly, in your model you are only single-indexing a[i], but you have a double index on it in your data and formulation.
In your constraints, the definitions should only hold a variable for the "for each" part, not the variable you are summing over.
Clean that stuff up, give it a whirl, comment me back if it is still broke.
Edit: A couple more items.....
I'd recommend naming your parameters and sets intuitively, such as:
model.supply, model.cost, etc. Makes it MUCH easier to read & troubleshoot. :)
============
Edit #2: Your code cleanup is vastly improved. A couple cleanup items remain:
In your constraints, you only need to pass variable for the "for each" side of the equation if you are summing over the other variable. You are making model.I constraints here, so this is appropriate:
def ax_constraint_rule_1(model, i): # note removal of j
return sum(model.supply[i,j] for j in model.J ) <= model.a[i]
Note that the summation here is over j for each i so I changed your for loop also.
flip that around for the other constraint.
your a, b, cost, supply don't line up with your data names. Check them all. In your data, a appears to be cost[i, j]
your cost data is also missing some values!
In AMPL syntax, set is not capitalized. If you get it running, it will barf and call out that error.
Here's my cut:
from pyomo.environ import *
model = AbstractModel()
# model.m = Param(within=NonNegativeIntegers)
# model.n = Param(within=NonNegativeIntegers)
model.S = Set() # Sources
model.D = Set() # Destinations
model.cost = Param(model.S, model.D) # cost from S->D
model.supply = Param(model.S) # supply at source S
model.demand = Param(model.D) # demad at destination D
model.x = Var(model.S, model.D, domain=NonNegativeReals)
### OBJECTIVE FUNCTION ###
# calculate total cost of decisions
def obj_expression(model):
return sum(model.x[s, d] * model.cost[s, d] for s in model.S for d in model.D)
model.OBJ = Objective(rule=obj_expression)
### CONSTRAINTS ###
# ensure that supply constraint is met for each source in model.S
def supply_constraint(model, s):
return sum(model.x[s, d] for d in model.D ) <= model.supply[s]
# ensure that demand constraint is met for each destination in model.D
def demand_constraint(model, d):
return sum(model.x[s, d] for s in model.S ) >= model.demand[d]
model.sup_constraint = Constraint(model.S, rule=supply_constraint)
model.dem_constraint = Constraint(model.D, rule=demand_constraint)
model.pprint()
Data file
set D := D1 D2 D3 ;
set S := S1 S2 S3 ;
param cost :=
S1 D1 3
S1 D2 1
S1 D3 10
S2 D1 4
S2 D2 2
S2 D3 4
S3 D1 10
S3 D2 3
S3 D3 3
;
param demand :=
D1 7
D2 3
D3 5 ;
param supply :=
S1 5
S2 7
S3 3
;
Output:
% pyomo solve --solver=glpk transpo_model.py transpo.dat --summary
[ 0.00] Setting up Pyomo environment
[ 0.00] Applying Pyomo preprocessing actions
4 Set Declarations
D : Dim=0, Dimen=1, Size=0, Domain=None, Ordered=False, Bounds=None
Not constructed
S : Dim=0, Dimen=1, Size=0, Domain=None, Ordered=False, Bounds=None
Not constructed
cost_index : Dim=0, Dimen=2, Size=0, Domain=None, Ordered=False, Bounds=None
Virtual
x_index : Dim=0, Dimen=2, Size=0, Domain=None, Ordered=False, Bounds=None
Virtual
3 Param Declarations
cost : Size=0, Index=cost_index, Domain=Any, Default=None, Mutable=False
Not constructed
demand : Size=0, Index=D, Domain=Any, Default=None, Mutable=False
Not constructed
supply : Size=0, Index=S, Domain=Any, Default=None, Mutable=False
Not constructed
1 Var Declarations
x : Size=0, Index=x_index
Not constructed
1 Objective Declarations
OBJ : Size=0, Index=None, Active=True
Not constructed
2 Constraint Declarations
dem_constraint : Size=0, Index=D, Active=True
Not constructed
sup_constraint : Size=0, Index=S, Active=True
Not constructed
11 Declarations: S D cost_index cost supply demand x_index x OBJ sup_constraint dem_constraint
[ 0.29] Creating model
[ 0.32] Applying solver
[ 0.33] Processing results
Number of solutions: 1
Solution Information
Gap: 0.0
Status: feasible
Function Value: 46.0
Solver results file: results.json
==========================================================
Solution Summary
==========================================================
Model unknown
Variables:
x : Size=9, Index=x_index
Key : Lower : Value : Upper : Fixed : Stale : Domain
('S1', 'D1') : 0 : 5.0 : None : False : False : NonNegativeReals
('S1', 'D2') : 0 : 0.0 : None : False : False : NonNegativeReals
('S1', 'D3') : 0 : 0.0 : None : False : False : NonNegativeReals
('S2', 'D1') : 0 : 2.0 : None : False : False : NonNegativeReals
('S2', 'D2') : 0 : 3.0 : None : False : False : NonNegativeReals
('S2', 'D3') : 0 : 2.0 : None : False : False : NonNegativeReals
('S3', 'D1') : 0 : 0.0 : None : False : False : NonNegativeReals
('S3', 'D2') : 0 : 0.0 : None : False : False : NonNegativeReals
('S3', 'D3') : 0 : 3.0 : None : False : False : NonNegativeReals
Objectives:
OBJ : Size=1, Index=None, Active=True
Key : Active : Value
None : True : 46.0
Constraints:
sup_constraint : Size=3
Key : Lower : Body : Upper
S1 : None : 5.0 : 5.0
S2 : None : 7.0 : 7.0
S3 : None : 3.0 : 3.0
dem_constraint : Size=3
Key : Lower : Body : Upper
D1 : 7.0 : 7.0 : None
D2 : 3.0 : 3.0 : None
D3 : 5.0 : 5.0 : None
[ 0.33] Applying Pyomo postprocessing actions
[ 0.33] Pyomo Finished
This is the hole Error:
ERROR: Rule failed when generating expression for objective FObj: KeyError:
"Index '4' is not valid for indexed component 'y'"
ERROR: Constructing component 'FObj' from data=None failed:
KeyError: "Index '4' is not valid for indexed component 'y'"
I've proved everything, checking every RangeSet and it's ok so I don't why it doesn't work well. Thanks for reading this, if anyone could help...
from pyomo.environ import *
from pyomo.opt import SolverFactory
from pyomo.core.base.PyomoModel import AbstractModel
from pyomo.core.base.constraint import Constraint
from pyomo.core.base.set import RangeSet
#import pyomo.dae
import numpy as np
import logging
logging.getLogger('pyomo.core').setLevel(logging.ERROR)
model = AbstractModel()
model.personas = RangeSet(0, 29)
model.sabados = RangeSet(0,3)
model.y = Var(model.personas,model.sabados, within = Binary)
def ObjFunction(model):
return sum(model.y[i][s] for i in model.personas for s in model.sabados)
model.FObj= Objective(rule=ObjFunction, sense = maximize)
Problem discovered. I think you must have just changed the model type to Abstract as when I change it back to Concrete the problem with y shows up.
You are indexing model.y with double indexing (Python standard). Pyomo ... for whatever reason ... uses comma separated indices for multiple indexing. Note the change in my code below. If this is a head-hurter, I've built models and put the indices in a tuple just to keep myself sane. Such as: model.y[(i, s)] which is unnecessary, but works and makes it look more distinct for pyomo.
Couple other notes...
I removed some of the unnecceary imports. One was causing some kind
of warning.
I chopped down your indices just to see a smaller printout
from pyomo.environ import *
from pyomo.opt import SolverFactory
#from pyomo.core.base.PyomoModel import AbstractModel
#from pyomo.core.base.constraint import Constraint
#from pyomo.core.base.set import RangeSet
#import pyomo.dae
import numpy as np
import logging
#logging.getLogger('pyomo.core').setLevel(logging.ERROR)
model = ConcreteModel()
model.personas = RangeSet(0, 3)
model.sabados = RangeSet(0,2)
model.y = Var(model.personas,model.sabados, within = Binary)
def ObjFunction(model):
return sum(model.y[i,s] for i in model.personas for s in model.sabados)
model.FObj= Objective(rule=ObjFunction, sense = maximize)
model.pprint()
Yields:
1 Set Declarations
y_index : Dim=0, Dimen=2, Size=12, Domain=None, Ordered=True, Bounds=None
Virtual
2 RangeSet Declarations
personas : Dim=0, Dimen=1, Size=4, Domain=Integers, Ordered=True, Bounds=(0, 3)
Virtual
sabados : Dim=0, Dimen=1, Size=3, Domain=Integers, Ordered=True, Bounds=(0, 2)
Virtual
1 Var Declarations
y : Size=12, Index=y_index
Key : Lower : Value : Upper : Fixed : Stale : Domain
(0, 0) : 0 : None : 1 : False : True : Binary
(0, 1) : 0 : None : 1 : False : True : Binary
(0, 2) : 0 : None : 1 : False : True : Binary
(1, 0) : 0 : None : 1 : False : True : Binary
(1, 1) : 0 : None : 1 : False : True : Binary
(1, 2) : 0 : None : 1 : False : True : Binary
(2, 0) : 0 : None : 1 : False : True : Binary
(2, 1) : 0 : None : 1 : False : True : Binary
(2, 2) : 0 : None : 1 : False : True : Binary
(3, 0) : 0 : None : 1 : False : True : Binary
(3, 1) : 0 : None : 1 : False : True : Binary
(3, 2) : 0 : None : 1 : False : True : Binary
1 Objective Declarations
FObj : Size=1, Index=None, Active=True
Key : Active : Sense : Expression
None : True : maximize : y[0,0] + y[0,1] + y[0,2] + y[1,0] + y[1,1] + y[1,2] + y[2,0] + y[2,1] + y[2,2] + y[3,0] + y[3,1] + y[3,2]
5 Declarations: personas sabados y_index y FObj
[Finished in 2.6s]
I have a problem with formulating constraints for 3d indexed variables with Pyomo:
I have the following variable list:
1 Var Declarations
E : Size=6, Index=N
Key : Lower : Value : Upper : Fixed : Stale : Domain
(0, 0, 2) : 0 : 10 : None : False : False : NonNegativeReals
(0, 0, 3) : 0 : 10 : None : False : False : NonNegativeReals
(0, 2, 0) : 0 : 10 : None : False : False : NonNegativeReals
(0, 3, 0) : 0 : 10 : None : False : False : NonNegativeReals
(1, 3, 1) : 0 : 10 : None : False : False : NonNegativeReals
(1, 4, 1) : 0 : 10 : None : False : False : NonNegativeReals
they are essentially values in a 3D array (2x5x5) which can take a value other then 0. I try to optimize them, with some constraints:
- the sum value of the variables in a row should be maximized
- the sum value of the variables in a column should take a certain value
My question is regarded to both constraints: I tried to formulate the first constraint like this:
def max_perf_rule(model, a, b):
return sum(model.E[a,b,c] for c in range(5) if (a,b,c) in model.N) <= H[a,b]
model.max_perf = Constraint(range(2), range(5), rule = max_perf_rule)
, where model.N= [(0, 0, 2), (0, 0, 3), (0, 2, 0), (0, 3, 0), (1, 3, 1), (1, 4, 1)]
The variables are originally given by model.N (list of 3d tuples) but I need the two "range(2)" and "range(5)" as inputs in this constraint in order to be able to refer to the proper row.
No matter what I try I cannot create the desired constraints. They should look something like this:
max_perf : Size=10, Index=max_perf_index, Active=True
(0, 0) : E[0,0,2] + E[0,0,3] : <= 0.0
(0, 2) : E[0,2,0] : <= 2688.0
(0, 3) : E[0,3,0] : <= 896.0
(1, 3) : E[1,3,1] : <= 448.0
(1, 4) : E[1,4,1] : <= 9999999.0
...but I keep getting the following error:
"ERROR: Constructing component 'max_perf' from data=None failed: ValueError:
Invalid constraint expression. The constraint expression resolved to a
trivial Boolean (True) instead of a Pyomo object. Please modify your rule
to return Constraint.Feasible instead of True.
Error thrown for Constraint 'max_perf[0,1]'"
I have no idea what this is; I even tried to reproduce the situation with a dictionary instead of model.E and it worked nicely.
Do you have any solution for the problem?
Thanks in advance!
The problem is that with the way you set up your indexing sets, not every combination of range(2) x range(5) x range(5) appears in model.N. For some combinations the sum in the constraint rule will not have any terms and therefore evaluate to a constant value of 0. The easiest way to get around this would be to add a check in your constraint rule to make sure the sum is not empty:
def max_perf_rule(model, a, b):
temp = sum(model.E[a,b,c] for c in range(5) if (a,b,c) in model.N)
if type(temp) is int: # This will be true if the sum was empty
return Constraint.Skip
return temp <= H[a,b]
model.max_perf = Constraint(range(2), range(5), rule = max_perf_rule)