Pyomo: TypeError: unhashable type: 'OrderedScalarSet' - python

Dears,
I am new on Python and Pyomo as well.
I'm creating an abstract model, below there are the sets, parameters and variables related to my error:
SETS:
SCUC.UP = Set()
SCUC.zone = Set()
from .dat file
"set UP := G1 G2 G3 G4 G5 G6;
set zone := Z1 Z2 Z3;"
PARAMETERS:
SCUC.Pmi = Param(SCUC.UP)
SCUC.zonal_UP = Param(SCUC.UP, SCUC.zone)
from .dat file
"param Pmi :=
G1 300.0
G2 200.0
G3 350.0
G4 210.0
G5 200.0
G6 240.0;
param zonal_UP :=
G1 Z1 1
G2 Z1 1
G3 Z1 0
G4 Z1 0
G5 Z1 0
G6 Z1 0
G1 Z2 0
G2 Z2 0
G3 Z2 1
G4 Z2 1
G5 Z2 0
G6 Z2 0
G1 Z3 0
G2 Z3 0
G3 Z3 0
G4 Z3 0
G5 Z3 1
G6 Z3 1;"
VARIABLES:
SCUC.UP_gz = Var(SCUC.zone)
SCUC.DPg_g = Var(SCUC.UP, within = Reals)
I'm trying to type three constraints where I need to multiply a vector of variables/parameters with a vector of parameters to obtain a scalar value.
Here the constraint formulation:
def zonal_gen_rule(SCUC,z):
return SCUC.UP_gz[z] == SCUC.Pmi[SCUC.UP] * SCUC.zonal_UP[SCUC.UP,z] + SCUC.zonal_UP[SCUC.UP,z] * SCUC.DPg_g[SCUC.UP]
SCUC.zonal_gen = Constraint(SCUC.zone, rule=zonal_gen_rule)
But when I lunch the instance construction it appears the following error:
TypeError: unhashable type: 'OrderedScalarSet'
It also tried to transpose the vectors with numpy but it didn't work.
I hope someone could help me.

You are getting that error because you are passing the entire set into your expression, instead of an element of the set. And as the whole set is "unhashable" you are getting the error
SCUC.UP_gz[z] == SCUC.Pmi[SCUC.UP] * ...
^
this is illegal... it is the whole set
It isn't clear what type of constraint you are trying to make from the context of your question... Meaning it isn't clear if you intend to sum across the members of SCUC.UP or make a constraint for each pair... So the example below shows "both ways" of doing this.
Also, a little standardization in use of caps will help you troubleshoot. Convention is that all variables are lower case, however, convention in set notation sometimes has caps for the set name and lower for members.... either way, consistency is key to troubleshooting.
from pyomo.environ import *
SCUC = ConcreteModel('example')
# SETS
SCUC.ups = Set(initialize=['G1', 'G2', 'G3'])
SCUC.zones = Set(initialize=['Z1', 'Z2'])
# PARAMS
SCUC.pmi = Param(SCUC.ups, initialize=2) # junk initialization...
SCUC.zonal_up = Param(SCUC.ups, SCUC.zones, initialize=3)
# VARIABLES
SCUC.u = Var(SCUC.zones)
SCUC.d = Var(SCUC.ups)
# CONSTRAINTS
# "for each" (up, zone) pair...
def zonal_gen_rule(SCUC, zone, up):
return SCUC.u[zone] == SCUC.pmi[up] * SCUC.zonal_up[up, zone] \
+ SCUC.zonal_up[up, zone] * SCUC.d[up]
SCUC.zonal_gen_1 = Constraint(SCUC.zones, SCUC.ups, rule=zonal_gen_rule)
# "for each zone, sum the ups"
def zonal_gen_rule_2(SCUC, zone):
return SCUC.u[zone] == sum(SCUC.pmi[up] * SCUC.zonal_up[up, zone] \
+ SCUC.zonal_up[up, zone] * SCUC.d[up] for up in SCUC.ups)
SCUC.zonal_gen_2 = Constraint(SCUC.zones, rule=zonal_gen_rule_2)
SCUC.pprint()
Yields:
...
2 Constraint Declarations
zonal_gen_1 : Size=6, Index=zonal_gen_1_index, Active=True
Key : Lower : Body : Upper : Active
('Z1', 'G1') : 0.0 : u[Z1] - (6 + 3*d[G1]) : 0.0 : True
('Z1', 'G2') : 0.0 : u[Z1] - (6 + 3*d[G2]) : 0.0 : True
('Z1', 'G3') : 0.0 : u[Z1] - (6 + 3*d[G3]) : 0.0 : True
('Z2', 'G1') : 0.0 : u[Z2] - (6 + 3*d[G1]) : 0.0 : True
('Z2', 'G2') : 0.0 : u[Z2] - (6 + 3*d[G2]) : 0.0 : True
('Z2', 'G3') : 0.0 : u[Z2] - (6 + 3*d[G3]) : 0.0 : True
zonal_gen_2 : Size=2, Index=zones, Active=True
Key : Lower : Body : Upper : Active
Z1 : 0.0 : u[Z1] - (6 + 3*d[G1] + 6 + 3*d[G2] + 6 + 3*d[G3]) : 0.0 : True
Z2 : 0.0 : u[Z2] - (6 + 3*d[G1] + 6 + 3*d[G2] + 6 + 3*d[G3]) : 0.0 : True

First reason: This type of error occurs when you try to insert a mutable type object as a key in a dict. Mutable objects are those objects whose value can be changed on run time for eg: Lists are mutable objects.
Second reason: you have implemented __eq__ method in your class because of which hashing no longer works on your class, you can fix this by implementing __hash__ method in your class.
In your case it looks like your object is unhashable. Try to implement __hash__ method in your class.
you can learn more about these methods here: https://docs.python.org/3/reference/datamodel.html

Related

Create different restrictions with a single rule

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

How to understand this Pyomo Constraint (rewriting the constraint)

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?

Using BigM equations to minimize a variable

I am trying to minimize the following equation:
P_ch_max = min(22, E_need*m_int) where E_need*m_int can be bigger or lower than 22 depending on the data.
I am using the following equations in pyomo to do it:
m.C6 = ConstraintList()
for t in m.ts2:
m.C6.add(expr = m.char_power - m.var_E_need[0,t]*m_int <= 100*m.Y[t])
m.C6.add(expr = m.var_E_need[0,t]*m_int - m.char_power <= 100 * (1-m.Y[t]))
m.C6.add(expr = m.var_P_ch_max[0,t] <= m.var_E_need[0,t]*m_int )
m.C6.add(expr = m.var_P_ch_max[0,t] <= m.char_power)
m.C6.add(expr = m.var_P_ch_max[0,t] >= m.var_E_need[0,t]*m_int - 100*(1-m.Y[t]))
m.C6.add(expr = m.var_P_ch_max[0,t] >= m.char_power - 100*m.Y[t])
m.char_power = 22; m.Y is a boolean; 100 is my big` in this case
When I substitute the values of Y manually, these equations make sense:
When Y=0 I get that P_ch_max<= 22 and P_ch_max>= 22 which would make P_ch_max == 22.
When Y=1 I get that P_ch_max<= E_need*m_int and P_ch_max>= E_need*m_int which would make P_ch_max = E_need*m_int.
However, when I run the code in pyomo it says it's unfeasible or unbounded and I don't understand why. Is there any other way to do this? Or can you tell me if I am doing something wrong pls?
It's pretty difficult to unwind your equations and figure out why it is infeasible. But you can do a couple things rather quickly to tackle this.
First, you can start to "comment out" constraints and see if you can get the model breathing (such that the solver doesn't complain about infeasibility), and then investigate from there.
Second, if you think you know a feasible solution (as you suggest in your comment about plugging in), then just plug in your values by assigning them and then display your model and it should stand out very quickly which constraints are violated. For example:
import pyomo.environ as pyo
m = pyo.ConcreteModel()
m.x = pyo.Var()
m.c1 = pyo.Constraint(expr=m.x >= 5)
m.x = 4
m.display()
Yields:
Model unknown
Variables:
x : Size=1, Index=None
Key : Lower : Value : Upper : Fixed : Stale : Domain
None : None : 4 : None : False : False : Reals
Objectives:
None
Constraints:
c1 : Size=1
Key : Lower : Body : Upper
None : 5.0 : 4 : None
[Finished in 210ms]

Pyomo: Create Abstract model and AMPL data

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

Cannot add variable to number Python [duplicate]

This question already has answers here:
Why does the division get rounded to an integer? [duplicate]
(13 answers)
Closed 5 years ago.
↑
Yes, it does.
Python 2.7.13
I want to input 0 for the first prompt, then .37 for then next, so it comes out to .481
For some reason, and I know I've messed up, I cannot add the 'second' variable defined above, and the 'overallheight' value is not working:
u1 = 12.5
first = .481
u2 = 2
length = u1 * 12
second = u2 / 64
overallheight = first - second #this line is not subtracting
height_multiply = overallheight / .3075
width_multiply = length / 108
def calc():
x = float(raw_input("first prompt"))
y = float(raw_input("second prompt"))
y1 = (y - .0625) * height_multiply
x1 = x * width_multiply
y2 = y1 + second #this is the 'second' that needs to be added
print("(%s,%s)") % (x1, y2)
while 1>0:
calc()`
You are using Python 2, so / used with integers will do an integer division.
second = u2 / 64 with u2 = 2 is 2 / 64 which is 0.
To have float divistion, you can use from __future__ import division or use floats explicitely : u2 = 2.0.

Categories