binary variable multiplying by another variable in python
AnsweredHello everyone
I am quite new to Gurobi. I have a basic mathematical model for replenishment that I want to code in Python using Gurobi. However, in some part of the model and constraints I have to multiply binary variable to another positive variable which return error as : GurobiError: Invalid argument to QuadExpr addition
this error just happen in objective function.
I searched and found an answer from Gurobi that we can add
m.params.NonConvex = 2
m.setParam('NonConvex', 2)
to solve the problem but still it does not work an returns the same error.
my code is as below:
import math
import gurobipy as gp
from gurobipy import GRB
# Set data______________________________________________________________________________________________________________________
suppliers = [1]
warehouses = [1]
retailers = [1]
time_periods = list(range(1, 11))
# Parameter data________________________________________________________________________________________________________________
capacity = {'i': 600, 'j': 600}
capacity2= {'r':600}
cost = {(1, 1): 2}
cost2 = {(1, 1): 2}
setupcost1={(1,1):300}
setupcost2={(1,1):300}
# Create model
m = gp.Model('Profit_SC')
# setup cost for delivering from warehouse to retailer
for j in warehouses:
for r in retailers:
m.addVar(lb=setupcost2.get((j,r), 0), ub=setupcost2.get((j,r), 0), vtype=gp.GRB.CONTINUOUS, name="setupcost2_{}_{}".format(j,r))
#demand in retailer r at time t
def demand(r,t):
for r in retailers:
return (50*0.7*(8 * (100*0.01 / (math.e ** (0.1 * t)))))
for t in range(1, 11):
print("t =", t, "r=",r, "Demand =", demand(r,t))
# Add variables
#quantity of products delivers from supplier to warehouse
x = {}
for i in suppliers:
for j in warehouses:
for t in time_periods:
x [i,j,t] = m.addVar(vtype="C", name="x" )
#quantity of products delivers from warehouseto retailer
y = {}
for j in warehouses:
for r in retailers:
for t in time_periods:
y [j,r,t] = m.addVar(vtype="C", name="y" )
# binary variable equals to 1 ifdelivery between warehouse and retailer happens otherwise zero
gama2={}
for r in retailers:
for t in time_periods:
gama2[r,t] = m.addVar(vtype=gp.GRB.BINARY, name="gama2")
#inventory level at retailer
inv={}
for r in retailers:
for t in time_periods:
inv[r,t]=m.addVar(vtype="C", name="inventory" )
# Add constraints_______________________________________________________________________________________________________________
#constraints for capacity
m.addConstrs((gp.quicksum(x[i, j, t] for j in warehouses for i in suppliers for t in time_periods) <= capacity['i']
for i in suppliers for t in time_periods), name='supply')
m.addConstrs((gp.quicksum(y[j, r, t] for j in warehouses) <= capacity['j']*gama2[r,t]
for r in retailers for t in time_periods), name='supply2')
#constraints for binary variable
m.addConstr((gp.quicksum(gama2[r,t] for r in retailers for t in time_periods)<=1), name='binary variable 2')
#constraints for inventory
for r in retailers:
for t in time_periods:
if t>1:
m.addConstrs((inv[r, t] == inv[r,t-1]+(y[j,r,t]*gama2[r,t])-demand(r,t) for j in warehouses ), name='inventory')
m.addConstrs((inv[r,t]+ gp.quicksum(y[j,r,t]*gama2[r,t] for j in warehouses)<= demand(r, t) for r in retailers for t in time_periods) , name='inventory balance')
# Set objective function________________________________________________________________________________________________________
m.setObjective(gp.quicksum((y[j, r, t] * cost2[j, r]*gama2[r,t] for j in warehouses for r in retailers for t in time_periods )) +
gp.quicksum((x[i, j, t] * cost[i, j] for i in suppliers for j in warehouses for t in time_periods )) +
(setupcost2[j,r]*gama2[r,t] for j in warehouses for r in retailers for t in time_periods),
sense=gp.GRB.Minimize)
m.update()
# Solve the model
m.optimize()
# Print the results_____________________________________________________________________________________________________________
print('x values:',x)
for i in suppliers:
for j in warehouses:
for t in time_periods:
print(f"x({i}, {j}, {t}) = {x[i, j, t].X}")
print('y values:',y)
for j in warehouses:
for r in retailers:
for t in time_periods:
print(f"y({j}, {r}, {t}) = {y[j, r, t].X}")
print('inventory:',inv)
for r in retailers:
for t in time_periods:
print(f"inv({r}, {t}) = {inv[r, t].X}")
Also, I have found from your answers to this issue in previous questions that I can use big M technique. I tried to define that as below, however the model returns AttributeError: type object 'GRB' has no attribute 'Minimize'
the model is as below. I would highly appreciate it if you could help me with this issue
import math
import gurobipy as gp
from gurobipy import GRB
# Set data______________________________________________________________________________________________________________________
suppliers = [1]
warehouses = [1]
retailers = [1]
time_periods = list(range(1, 11))
M=[7000]
# Parameter data________________________________________________________________________________________________________________
capacity = {'i': 600, 'j': 600}
capacity2= {'r':600}
cost = {(1, 1): 2}
cost2 = {(1, 1): 2}
setupcost1={(1,1):300}
setupcost2={(1,1):300}
# Create model
m = gp.Model('Profit_SC')
# setup cost
for i in suppliers:
for j in warehouses:
m.addVar(lb=setupcost1.get((i,j), 0), ub=setupcost1.get((i,j), 0), vtype=gp.GRB.CONTINUOUS, name="setupcost1_{}_{}".format(i,j))
for j in warehouses:
for r in retailers:
m.addVar(lb=setupcost2.get((j,r), 0), ub=setupcost2.get((j,r), 0), vtype=gp.GRB.CONTINUOUS, name="setupcost2_{}_{}".format(j,r))
#demand_________________________________________________________________________________________________________________________
def demand(r,t):
for r in retailers:
return (50*0.7*(8 * (100*0.01 / (math.e ** (0.1 * t)))))
for t in range(1, 11):
print("t =", t, "r=",r, "Demand =", demand(r,t))
# Add variables_________________________________________________________________________________________________________________
#quantity of products delivers from supplier to warehouse
x = {}
for i in suppliers:
for j in warehouses:
for t in time_periods:
x [i,j,t] = m.addVar(vtype= GRB.CONTINUOUS, lb =0, name="x" )
#quantity of products delivers from warehouseto retailer
y = {}
for j in warehouses:
for r in retailers:
for t in time_periods:
y [j,r,t] = m.addVar(vtype= GRB.CONTINUOUS, lb =0, name="y" )
# binary variable equals to 1 ifdelivery between warehouse and retailer happens otherwise zero
gama2={}
for r in retailers:
for t in time_periods:
gama2[r,t] = m.addVar(vtype=gp.GRB.BINARY, name="gama2")
#inventory level at retailer
inv={}
for r in retailers:
for t in time_periods:
inv[r,t]=m.addVar(vtype= GRB.CONTINUOUS, lb =0, name="inventory" )
#new variable to linearize the equations
z={}
for j in warehouses:
for r in retailers:
for t in time_periods:
z[j,r,t]=m.addVar(vtype="C", name="new variable for linearization" )
# Add constraints_______________________________________________________________________________________________________________
#constraints for capacity
m.addConstrs((gp.quicksum(x[i, j, t] for j in warehouses for i in suppliers for t in time_periods) <= capacity['i'] for i in suppliers), name='supply')
m.addConstrs((gp.quicksum(y[j, r, t] for j in warehouses) <= capacity['j']*gama2[r,t]
for r in retailers for t in time_periods), name='supply2')
#constraints for binary variable
m.addConstr((gp.quicksum(gama2[r,t] for r in retailers for t in time_periods)<=1), name='binary variable 2')
#linearization process by z
for j in warehouses:
for r in retailers:
for t in time_periods:
m.addConstr((z[j,r,t]==gama2[r,t]*7000), name='linear 1')
for j in warehouses:
for r in retailers:
for t in time_periods:
m.addConstr((z[j,r,t]>=0), name='linear 2')
for j in warehouses:
for r in retailers:
for t in time_periods:
m.addConstr((z[j,r,t]<=gp.quicksum(y[j,r,t] for j in warehouses)), name='linear 3')
for j in warehouses:
for r in retailers:
for t in time_periods:
m.addConstr((z[j,r,t]>=y[j,r,t]-(1-gama2[r,t])*7000), name='linear 4')
#constraint for inventory
for r in retailers:
for t in time_periods:
if t>1:
m.addConstrs((inv[r, t] == inv[r,t-1]+(z[j,r,t])-demand(r,t) for j in warehouses ), name='inventory')
for r in retailers:
for t in time_periods:
m.addConstr((inv[r,t]+ gp.quicksum(z[j,r,t] for j in warehouses)<= demand(r, t)),name='inventory balance')
# Set objective function________________________________________________________________________________________________________
m.setObjective(gp.quicksum((z[j,r,t] for j in warehouses for r in retailers for t in time_periods ))*2 +
gp.quicksum((x[i, j, t] for i in suppliers for j in warehouses for t in time_periods ))*2 +
(gp.quicksum(gama2[r,t] for r in retailers for t in time_periods))*300,
sense=gp.GRB.Minimize)
m.update()
# Solve the model
m.optimize()
-
Hi Saina,
The capitalization matters here, i.e. use gp.GRB.MINIMIZE.
Based off the second code block, it looks like you solved your original problem?
- Riley
0 -
Many thanks for your reply
I tried the capital letters but still doesn’t work
I’m not sure if I did the linearisation correctly, I only tried to use the relations based on big M like this linkI was wondering if there is any way that I can run the model without converting the model into linear one (based on first model)
Sincere thanks0 -
Hi Saina,
When using gp.GRB.MINIMIZE the second code block you posted above runs without problems.
The model is infeasible - but the code is fine.
If you wish to understand why the model is infeasible you can compute an IIS.
You also have the option of not linearizing the model and asking Gurobi to solve a non-convex model. You may need to set the NonConvex parameter to 2 to allow this - the solver output will tell you.- Riley
0 -
Dear Riley
I am so thankful for your help. It was my mistake that only checked capital letters on my first block. But yes the second one works.
I only have one another question for the first block. As I need to develop my model later, it is easier to work with the first one. I tried to set Nonconvex parameter to 2 but it still returns error (
TypeError: unsupported operand type(s) for *: 'generator' and 'int'). my modified code is as below. I would be grateful if you could help me to correct this issue as well.Sincere thanks
import math
import gurobipy as gp
from gurobipy import GRB
# Set data______________________________________________________________________________________________________________________
suppliers = [1]
warehouses = [1]
retailers = [1]
time_periods = list(range(1, 11))
# Parameter data________________________________________________________________________________________________________________
capacity = {'i': 600, 'j': 600}
capacity2= {'r':600}
cost = {(1, 1): 2}
cost2 = {(1, 1): 2}
setupcost1={(1,1):300}
setupcost2={(1,1):300}
# Create model
m = gp.Model('Profit_SC')
m.params.NonConvex = 2
m.setParam('NonConvex', 2)
# setup cost for delivering from warehouse to retailer
for j in warehouses:
for r in retailers:
m.addVar(lb=setupcost2.get((j,r), 0), ub=setupcost2.get((j,r), 0), vtype=gp.GRB.CONTINUOUS, name="setupcost2_{}_{}".format(j,r))
#demand in retailer r at time t
def demand(r,t):
for r in retailers:
return (50*0.7*(8 * (100*0.01 / (math.e ** (0.1 * t)))))
for t in range(1, 11):
print("t =", t, "r=",r, "Demand =", demand(r,t))
# Add variables
#quantity of products delivers from supplier to warehouse
x = {}
for i in suppliers:
for j in warehouses:
for t in time_periods:
x [i,j,t] = m.addVar(vtype="C", name="x" )
#quantity of products delivers from warehouseto retailer
y = {}
for j in warehouses:
for r in retailers:
for t in time_periods:
y [j,r,t] = m.addVar(vtype="C", name="y" )
# binary variable equals to 1 ifdelivery between warehouse and retailer happens otherwise zero
gama2={}
for r in retailers:
for t in time_periods:
gama2[r,t] = m.addVar(vtype=gp.GRB.BINARY, name="gama2")
#inventory level at retailer
inv={}
for r in retailers:
for t in time_periods:
inv[r,t]=m.addVar(vtype="C", name="inventory" )
# Add constraints_______________________________________________________________________________________________________________
#constraints for capacity
m.addConstrs((gp.quicksum(x[i, j, t] for j in warehouses for i in suppliers for t in time_periods) <= capacity['i']
for i in suppliers for t in time_periods), name='supply')
m.addConstrs((gp.quicksum(y[j, r, t] for j in warehouses) <= capacity['j']*gama2[r,t]
for r in retailers for t in time_periods), name='supply2')
#constraints for binary variable
m.addConstr((gp.quicksum(gama2[r,t] for r in retailers for t in time_periods)<=1), name='binary variable 2')
#constraints for inventory
for r in retailers:
for t in time_periods:
if t>1:
m.addConstrs((inv[r, t] == inv[r,t-1]+(y[j,r,t]*gama2[r,t])-demand(r,t) for j in warehouses ), name='inventory')
m.addConstrs((inv[r,t]+ gp.quicksum(y[j,r,t]*gama2[r,t] for j in warehouses)<= demand(r, t) for r in retailers for t in time_periods) , name='inventory balance')
# Set objective function________________________________________________________________________________________________________
m.setObjective(gp.quicksum(((y[j, r, t]*gama2[r,t] for j in warehouses for r in retailers for t in time_periods )*2 )) +
gp.quicksum(((x[i, j, t] for i in suppliers for j in warehouses for t in time_periods ) * 2 )) +
((gama2[r,t] for r in retailers for t in time_periods)*300 ),
sense=gp.GRB.MINIMIZE)
m.update()
# Solve the model
m.optimize()
# Print the results_____________________________________________________________________________________________________________
print('x values:',x)
for i in suppliers:
for j in warehouses:
for t in time_periods:
print(f"x({i}, {j}, {t}) = {x[i, j, t].X}")
print('y values:',y)
for j in warehouses:
for r in retailers:
for t in time_periods:
print(f"y({j}, {r}, {t}) = {y[j, r, t].X}")
print('inventory:',inv)
for r in retailers:
for t in time_periods:
print(f"inv({r}, {t}) = {inv[r, t].X}")
0 -
Hi Saina,
Let's have a look at the objective that is causing you the problem
m.setObjective(gp.quicksum(((y[j, r, t]*gama2[r,t] for j in warehouses for r in retailers for t in time_periods )*2 )) +
gp.quicksum(((x[i, j, t] for i in suppliers for j in warehouses for t in time_periods ) * 2 )) +
((gama2[r,t] for r in retailers for t in time_periods)*300 ),
sense=gp.GRB.MINIMIZE)and compare it to the other objective which works fine:
m.setObjective(gp.quicksum((z[j,r,t] for j in warehouses for r in retailers for t in time_periods ))*2 +
gp.quicksum((x[i, j, t] for i in suppliers for j in warehouses for t in time_periods ))*2 +
(gp.quicksum(gama2[r,t] for r in retailers for t in time_periods))*300,
sense=gp.GRB.Minimize)One works, but one doesn't. Can you spot the difference (noting that your error message specifically highlights the * operator)?
- Riley
0 -
I got it, it works now
Thanks
0
Please sign in to leave a comment.
Comments
6 comments