Solve Python Pulp without variables - python

I have a python pulp linear program which is minimizing costs. In the degenerate case where there are no ways to reduce costs I would like it to return the fixed cost. However pulp seems to add a __dummy variable in the case of no variables, which has a value of None. I have added a minimal working example below.
from pulp import *
model = LpProblem("Degenerate_Model",LpMinimize)
fixed_cost = 10
model += fixed_cost
print(model) #Prints MINIMIZE 10
model.solve()
print(model.objective) #prints 0*__dummy + 10
print(value(model.objective)) #returns None. Desired output is 10
My desired output in the above example would be to return 10. Any help is greatly appreciated

You're absolutely right. This happens because __dummy has a varValue of None, while you didn't expect it to be included at all. I would file a bug report to ask them to exclude dummy variables from LpAffineExpression.value() - since pulp.value(model.objective) is a shortcut for model.objective.value().
For now, I'd use the following workaround: model.objective.valueOrDefault().

You could declare the fixed cost as a variable with a fixed value.
>>> model = LpProblem("Degenerate_Model",LpMinimize)
>>> fixed_cost = LpVariable('fixed cost', lowBound=10, upBound=10)
>>> model += fixed_cost
>>> model.solve()
>>> print(value(model.objective))
10.0

Related

Variable definition as constraint in pyomo

This question is related to my previous question found here. I have managed to solve this problem (big thanks to #AirSquid!) My objective function is something like:
So the avgPrice_n variable is indexed by n. However, it is actually defined as
Meaning that it is indexed by n and i.
So at the moment my objective function is very messy as I have three sums. It looks something like (I expanded the brackets in the objective function and added each component separately, so the avgPrice_n*demand_n looks like):
expr += sum(sum(sum((1/12)*model.c[i]*model.allocation[i,n] for i in model.MP[t]) for t in model.M)*model.demand_n[n] for n in model.N)
And while this works, debugging was quite difficult because the terms are very long. So intead of using the actual definition of avgPrice_n, I was wondering if it would be possible to create a avgPrice_n variable, use this in the objective function and then create a constraint where I define avgPrice_n as I showed above.
The issue I am having is that I created my decision variable, x_{i,n}, as a variable but apparently I can't create a avgPrice_n as a variable where I index it by x_{i,n} as this results in a TypeError: Cannot apply a Set operator to an indexed Var component (allocation) error.
So as of now my decision variable looks like:
model.x = Var(model.NP_flat, domain = NonNegativeReals)
And I tried to create:
model.avg_Price = Var(model.x, domain = NonNegativeReals)
Which resulted in the above error. Any ideas or suggestions would be much appreciated!
You have a couple options. Realize you do not need the model.avg_price variable because you can construct it from other variables and you would have to make some constraints to constrain the value, etc. etc. and pollute your model.
The basic building blocks in the model are pyomo expressions, so you could put in a little "helper function" to build expressions (the cost function shown, which is dependent on n) which are not defined within the model, but just pop out an expression...totally legal). You can also "break up" large expressions into smaller expressions (like the other_stuff below) and then just kludge them all together in the objective (or where needed) this gives you the opportunity to evaluate them independently. I've made several models with an objective function that has a "cost" component and a "penalty" component by dividing it into 2 expressions.... Then when solved, you can inspect them independently.
My suggestion (if you don't like the triple sum in your current model) is to make an avg_cost(n) function to build the expression similar to what is done in the nonsensical function below, and use that as a substitute for a new variable.
Note: the initialization of the variables here is generally unnecessary. I just did it to "simulate solving" or they would be None...
Code:
import pyomo.environ as pyo
m = pyo.ConcreteModel()
m.N = pyo.Set(initialize=[0,1,2])
m.x = pyo.Var(m.N, initialize = 2.0)
def cost(n):
return m.x[n] + 2*m.x[n+1]
m.other_stuff = 3 * m.x[1] + 4 * m.x[2]
m.costs = sum(cost(n) for n in {0,1})
m.obj_expr = m.costs + m.other_stuff
m.obj = pyo.Objective(expr= m.obj_expr)
# inspect cost at a particular value of n...
print(cost(1))
print(pyo.value(cost(1)))
# inspect the pyomo expressions "other_stuff" and total costs...
print(m.other_stuff)
print(pyo.value(m.other_stuff))
print(m.costs)
print(pyo.value(m.costs))
# inspect the objective... which can be accessed by pprint() and display()
m.obj.pprint()
m.obj.display()
Output:
x[1] + 2*x[2]
6.0
3*x[1] + 4*x[2]
14.0
12.0
obj : Size=1, Index=None, Active=True
Key : Active : Sense : Expression
None : True : minimize : x[0] + 2*x[1] + x[1] + 2*x[2] + 3*x[1] + 4*x[2]
obj : Size=1, Index=None, Active=True
Key : Active : Value
None : True : 26.0

How to fix attribute Error in Pyomo model python

I am trying to write a pyomo model in python3, but I am facing this error that I can't seem to figure out - 'list' object has no attribute 'is_expression_type'. Below is my pyomo model, any help would be appreciated.
R_avg_tolist = [[0.00043159478649482775,
0.00045388639592182584,
0.0006735271301199177,
0.00044026758948786,
0.0037176592984565836]]
Cov_list = [[5.884677519869241e-05,
5.756542207262417e-05,
6.017027849080026e-05,
6.180151597797322e-05,
-0.0005074353586106837],
[5.756542207262417e-05,
6.0380562653096757e-05,
6.613608499966434e-05,
6.737370769879904e-05,
-0.0005362752804115953],
[6.017027849080026e-05,
6.613608499966434e-05,
8.206495000024503e-05,
8.01694525889321e-05,
-0.0005958716888916681],
[6.180151597797322e-05,
6.737370769879904e-05,
8.01694525889321e-05,
0.00010129901491226823,
-0.000608829853150321],
[-0.0005074353586106837,
-0.0005362752804115953,
-0.0005958716888916681,
-0.000608829853150321,
0.007373689071617548]]
import pyomo.environ as pyo
# Optimization Problem
def create_model(rho,R_avg,Cov):
m = pyo.ConcreteModel()
init_x = {}
m.idx = pyo.Set(initialize=[0,1,2,3,4])
for i in m.idx:
init_x[i] = 0
m.x = pyo.Var(m.idx,initialize=init_x,bounds=(0,None))
def Obj_func(m):
b = []
mult_result = 0
for i in m.idx:
a = 0
for j in m.idx:
a+= m.x[j]*Cov[j][i]
b.append(a)
for i in m.idx:
mult_result += b[i]*m.x[i]
return mult_result
m.OBJ = pyo.Objective(rule=Obj_func)
def constraint1(m):
sum=0
for i in m.idx:
sum+=m.x[i]
return sum ==100
m.C1 = pyo.Constraint(rule=constraint1(m))
def constraint2(m):
sum=0
for i in m.idx:
sum += R_avg_tolist[i]*m.x[i]
return sum >=0.08
m.C2 = pyo.Constraint(rule=constraint2(m))
return m
When I run model using below code, I face the attribute error - 'list' object has no attribute 'is_expression_type'.
rho = 0.0008
model1 = create_model(rho,R_avg_tolist,Cov_list)
solver = SolverFactory('ipopt')
results = solver.solve(model1, tee = True)
Probably not what you want to hear, but your model has many syntax probs. It's obviously a course assignment... Do you have somebody (instructor/TA) to go over this with who can advise a bit?
You didn't include enough info about which line of code caused the issue, but there are several problem areas. I've posted many simple pyomo examples if you scan through some of them, you'll get some ideas, along with the documentation and whatever you have from your course notes....
A few pointers may help:
Do NOT overwrite keywords/functions by using them as variables. When you write:
sum = 0
sum ....
you are nuking the python function sum by making that name a variable and assigning it the value of 0. You should be using sum in several of your functions with verbiage like:
sum(m.X[i] for i in m.idx) # or similar
You seem to be confused on making valid pyomo expressions. That is the core job of pyomo ... to make expressions and fill the model. For example, in your constraint1, you can just make an expression (without a function) and add it to your model. You can do a 1-liner there because the constraint is not a "for each". You could:
m.C1 = pyo.Constraint(expr=sum(m.x[i] for x in m.idx) == 100)
In general, when you are starting:
Add 1 thing to your model, and then print the model:
model.pprint()
See if it looks right, if not, fix it. Then repeat!

Using NEOS as a Pyomo solver

I have recently started in doing some OR, and have been trying to use Pyomo and NEOS to do some optimation problems. I have been following along with one of the UT Austin Pyomo lectures, and when my GLPT was being difficult to be installed, I moved on to NEOS. I am having some difficulty in now receiving a solved answer from NEOS.
What I have so far is this:
from pyomo import environ as pe
import os
os.environ['NEOS_EMAIL'] = 'my registered email'
model = pe.ConcreteModel()
model.x1 = pe.Var(domain=pe.Binary)
model.x2 = pe.Var(domain=pe.Binary)
model.x3 = pe.Var(domain=pe.Binary)
model.x4 = pe.Var(domain=pe.Binary)
model.x5 = pe.Var(domain=pe.Binary)
obj_expr = 3 * model.x1 + 4 * model.x2 + 5 * model.x3 + 8 * model.x4 + 9 * model.x5
model.obj = pe.Objective(sense=pe.maximize, expr=obj_expr)
con_expr = 2 * model.x1 + 3 * model.x2 + 4 * model.x3 + 5 * model.x4 + 9 * model.x5 <= 20
model.con = pe.Constraint(expr=con_expr)
solver_manager = pe.SolverManagerFactory('neos')
results = solver_manager.solve(model, solver = "minos")
print(results)
What I receive in return is number of solutions = 0, while I know for a fact that one exits. I also see that I don't have any bounds set, so how would I go about doing that? Once again, I am very new to this, and have not been able to find any sort of documentation regarding this elsewhere, or perhaps I just don't know how to look.
Thanks for any help!
This is a "problem" with the design of the current results object. For historical reasons, that field reports the number of solutions contained in the results object and is not the number of solutions generated by the solver. By default, Pyomo solvers directly load the solution returned by the solver into the original model (both for convenience and efficiency) and do not return it in the results object. You can change that behavior by providing load_solutions=False to the solve() call.
As for the bounds, what bounds are you referring to? Variable bounds are set using either the bounds= argument to the Var() declaration, or the domain= argument. For your example, because the variables are declared to be Binary, they all have bounds of [0..1]. Bounds on the objective are gathered by parsing the solver output. This is dependent on bother the solver that you are using (many do not report bounds information), and the interface used to parse the solver results.
As a final note, you are sending a MIP problem to a LP/NLP solver (minos). You will get fractional valies for your binary variables back from the solver.
To retrieve the solution from the model, you can use something like:
print(model.x1.value, model.x2.value, model.x3.value, model.x4.value, model.x5.value)
And using solver="cbc" you can avoid fractional values in this example.

How to call Python function in Pyomo

I have a python function which in turn has many other forton/c++ dlls calling to generate the output value. Now I want to call that function in Pyomo model as expression. Any help on that?
The example I have is:
def mult(a,b):
c = a * b
return(c)
model.a = Var(initialize=1)
model.y = Param(initialize = 6)
def add(model):
x = mult(value(model.a),3)
return(x)
model.value1 = Expression(rule=add)
modelinit_cond1 = Constraint(expr=(model.value1 == model.y))
opt = SolverFactory('ipopt');
results = opt.solve(model, tee=True)
results.write()
Expectation is; ipopt would try finding the value of model.a given that the constraint is satisfied.
Note: The code above is simpler in order simplify the explanation but the real problem on similar grounds.
Many Thanks for help in advance.

Python Gurobi: How can I implement a maximum value of a decision variable in the objective function?

Hopefully someone can help me out. I am developing an optimization model where I minimize electricity costs over time (t) and over different transactions (s). (where: standard power(p)*costs of electricity (c) = electricity costs).
Now I am trying to implement a cost component in the objective function that is based on the maximum power consumption that occurred (some alike: max(P[s,t])). However, np.max() returns an error because P[s,t] is an unsupported class for np.max(). Also the Gurobi function gp.max_(P[s,t]) also gives an unsupported class error. Is there someone who has a solution?
Code:
obj = gp.quicksum(p[s, t] * Cost_elect[t]e for t in range(T) for s in range(S)) + gp.max_(p_batt_ch[s,t]*fixed_cost for t in range(T) for s in range(S))
You need to assign the max constraint to a new auxiliary variable and the put this variable into the objective instead of the actual constraint.
maxobj = model.addVar()
max_constr = model.addConstr(maxobj == gp.max_(p_batt_ch[s,t] * fixed_cost
for t in range(T) for s in range(S)))
obj = gp.quicksum(p[s,t] * Cost_elect[t] for t in range(T) for s in range(S)) + maxobj)
Gurobi documentation

Categories