Gurobi with python dictionary key value error - python

I am using Gurobi 7 with Python 2.7 and want to implement the following linear optimization problem:
I have translated the above to Python and Gurobi using the following code:
T = range(1,17520)
# Create variables - defined as dictionaries
p = {} # power
s = {} # SOC
b = {} # buy
for t in T:
p[t] = m.addVar(vtype = GRB.CONTINUOUS, lb = -R, ub = R, name = "power_{}".format(t))
s[t] = m.addVar(vtype = GRB.CONTINUOUS, lb = 0, ub = E, name = "SOC_{}".format(t))
b[t] = m.addVar(vtype = GRB.CONTINUOUS, lb = 0, name = "Buy_{}".format(t))
# constraints
for t in T:
m.addConstr(b[t] == demand[t] + p[t], name = "balance_{}".format(t))
if t == 0:
m.addConstr(s[t] == p[t], name = "charge_{}".format(t))
else:
m.addConstr(s[t] == s[t-1] + p[t], name = "charge_{}".format(t))
# integrate variables and constraints
m.update()
# Objective function
obj = quicksum(
b[t]*SBP[t]
for t in T
)
m.setObjective(obj,GRB.MINIMIZE)
# start optimization
m.optimize
The error message I get (shown below) is probably due to the [t-1] index; however I do not see why this is not accepted by the compiler. Do I need to define this constraints in a different way?
I have not found any other examples of gurobi optimization problems being defined with this structure (variable is a function of the preceding variable etc.) but this is a very typical structure for LP problems.
Any help you can provide is greatly appreciated.

OK turns out I was confused with Python's zero-indexing; I have defined the set T as a range from 1 to 17520 and yet I subsequently define constraints for variables indexed in 0.
My problem was fixed by defining the set T as
T = range(0,17519)

Related

Error while writing optimization constraint in cplex python api

My goal is to write the following model using docplex.mp.model in python. which ptj takes binary variable {0,1}.
[summation from of Ptj from j=1 to t][t = 1,.....,8]
here is the code I wrote:
N = 8
(period_list = [t for t in range(1, no_of_period+1)])
(j = period_list)
p = Mode.binary_var_dict(period_list, name = 'p')
for t in period_list:
for j in range(1,t+1):
Model.add_constraints(Model.sum(p[t,j]) == 1)
but I got an error. Could anyone help me with this problem please?
Your code has numerous issues.
First, you need to create one instance of docplex.mp.model.Model to add constraints to: all your calls to Model.<fn> should be rewritten as mdl.<fn> as they are instance methods.
Second, the variable dict you create has periods as keys, that is, 1,2,..P
so querying p[t,j] is sure to crash with KeyError. If you need a square matrix of variables for each couple of periods, use Model.binary_var_matrix.
Third: Model.add_constraints (with a final S) expects an iterable, but you are passing one constraint, this is also sure to crash.
Lastly, using ranges starting at 1 is not the simplest nor the safest choice with Docplex.
Here is a code, freely derived from your sample, which I guess is close to what you need:
pr = range(1, no_of_period+1)
from docplex.mp.model import Model
m = Model()
p = m.binary_var_matrix(pr, pr, name = 'p')
m.add_constraints( (m.sum(p[t,j] for j in pr) == 1) for t in pr)
print(m.lp_string)
and the output is:
Minimize
obj:
Subject To
c1: p_1_1 + p_1_2 + p_1_3 = 1
c2: p_2_1 + p_2_2 + p_2_3 = 1
c3: p_3_1 + p_3_2 + p_3_3 = 1
[..snip..]

I'm getting a name error. "instance_dict is not defined"

I'm trying to implement tabu search algorithm, but I keep getting the following error. NameError: name 'instance_dict' is not defined.
def Objfun(instance_dict, solution, show = False):
dict = instance_dict
t = 0 #starting time
objfun_value = 0
for job in solution:
C_i = t + dict[job]["processing_time"]
d_i = dict[job]["due_date"]
T_i = max(0, C_i - d_i)
W_i = dict[job]["weight"]
objfun_value += W_i * T_i
t = C_i
if show == True:
print("The Objective function value for {} solution schedule is: {}".format(solution ,objfun_value))
return objfun_value
solution_1 = [1,2,5,6,8,9,10,3,4,7]
solution_2 = [2,3,5,10,6,8,9,4,7,1]
Objfun(instance_dict, solution_1, show=True)
Objfun(instance_dict, solution_2, show=True)
The last two lines of your code Objfun(instance_dict, solution_1, show=True) are referencing a variable, instance_dict, that is not defined anywhere. Thus the error, as you are trying to use an undefined variable.

Absolute value formulation for an optimization problem with PuLP

I shared below a simplified version of the problem I'm trying to solve. There must be something wrong in my formulation, perhaps regarding the decision variables. All of the flow is sent to Destination1 by the model, but I am attempting to build a model that would evenly distribute the flow. When I force Destination2 to receive flow with an additional constraint, the objective value improves, so I'm not sure why such a solution is not found instead of the less optimal.
I appreciate your thoughts and am happy to answer any questions about this model.
Warehouses = ["A","B","C","D"]
origin_supply = {"A": 53, "B": 62, "C": 45, "D": 65}
Destinations = ['Destination1','Destination2']
Routes = [(o,d) for o in origin_supply for d in destinations]
model = LpProblem("Testing-absolute-value-objective", LpMinimize)
supply = [53,62,45,65]
destination_mean = sum(supply) / len(destinations)
# decision variables
route_vars = LpVariable.dicts("Route",(Warehouses,Destinations),cat = "Integer", lowBound = 0)
sum_for_diff = LpVariable.dicts("sum",(Destinations),cat = "Continuous")
sum_for_diff_abs = LpVariable.dicts("sum_abs",(Destinations),cat = "Continuous", lowBound = 0)
# objective function is to minimize the absolute value of the difference supplied to the two destinations
obj_func = lpSum(sum_for_diff_abs)
# constraints
# absolute value constraints for the difference
for d in destinations:
model += sum_for_diff_abs[d] >= sum_for_diff[d]
model += sum_for_diff_abs[d] >= -sum_for_diff[d]
# The supply constraints (in this case all supply must be sent)
for w in Warehouses:
model += lpSum([route_vars[w][d] for d in Destinations]) == origin_supply[w]
# calculate the difference from the average amount sent to each destination
# the reasoning is that in the full model there will be many destinations, so this logic could scale
for d in Destinations:
model += sum_for_diff[d] == lpSum( route_vars[w][d] for w in Warehouses) - destination_mean
model.solve()
print(LpStatus[model.status])
print(pulp.value(obj_func))
for v in model.variables():
print (v.name + " = " + str(v.varValue))
You are not setting the objective function.
This line
obj_func = lpSum(sum_for_diff_abs)
should be
model+= lpSum(sum_for_diff_abs)

Python CPLEX API: Conditional iteration on binary variables

I'm working on a graph-theoretical problem. Suppose we want to find a Graph G=(V,E), such that there exists a partition X of V containing at most k equivalence classes. A variable p_S takes value 1 exactly when S is a member of partition X, and zero otherwise. So we have a constraint that the sum over all variables p_S is at most k, for all subsets S of V.
So what I want to do is to iterate over all p_S that have value 1 and define more constraints based on the elements I draw out of S. These constraints would preserve that members of an equivalence class share some mutual property.
Is it possible to access the p_S variables that way and how could I do it?
ALternatively I know I can do without iterating on my binary variables if I'm allowed to use binary variables as coefficients in my constraints. Is that possible?
Thanks in advance!
The CPLEX Python API is index based. To iterate over all binary variables with a solution value set to 1 we need to query the variables types and the solution values and filter accordingly. Here is a simple example:
import sys
import cplex
def main(modelfile):
# Read in a model file.
c = cplex.Cplex()
c.read(modelfile)
# Solve the model and print the solution and status.
c.solve()
print("Solution value:", c.solution.get_objective_value())
print("Solution status: {0} ({1})".format(
c.solution.get_status_string(),
c.solution.get_status()))
# Display all binary variables that have a solution value of 1.
types = c.variables.get_types()
nvars = c.variables.get_num()
binvars = [idx for idx, typ
in zip(range(nvars), c.variables.get_types())
if typ == c.variables.type.binary]
inttol = c.parameters.mip.tolerances.integrality.get()
binvars_at_one = [idx for idx, val
in zip(binvars, c.solution.get_values(binvars))
if abs(val - 1.0) <= inttol]
print("Binary variables with a solution value equal to one:")
for varname in c.variables.get_names(binvars_at_one):
print(" ", varname)
if __name__ == "__main__":
if len(sys.argv) != 2:
raise ValueError("usage: {0} <model>".format(sys.argv[0]))
main(sys.argv[1])
For more, see the documentation for Cplex.variables and Cplex.solution.
linearization example:
from docplex.mp.model import Model
mdl = Model(name='binaryproduct')
x = mdl.binary_var(name='x')
y = mdl.binary_var(name='y')
z = mdl.binary_var(name='z')
# z==x*y
mdl.add_constraint(x+y<=1+z, 'ct1')
mdl.add_constraint(z<=x, 'ct2')
mdl.add_constraint(z<=y, 'ct3')
#end of z==x*y
mdl.solve()
for v in mdl.iter_binary_vars():
print(v," = ",v.solution_value)

Pyomo KeyError: "Error accessing indexed component: Index '('student_5', 'company_3', 'meetingtime_1')' is not valid for array component 'var_X'"

I have a Pyomo model that seeks to maximize the fit-score for meetings between students and companies. I use a 3-dimensional variable for student-company-meetingtime combinations.
I am a beginner in using pyomo and I am using it with SolverStudio in Excel.
As long as I list all possible combinations in the range for model.var_X, the model is working fine. If I do not list all possible combinations, I get the following error message:
ERROR: Rule failed when generating expression for constraint company_meetingtime_capa_constraint with index ('company_3', 'meetingtime_1'):
KeyError: "Error accessing indexed component: Index '('student_5', 'company_3', 'meetingtime_1')' is not valid for array component 'var_X'"
I do not want to include all possible combinations, because the number is too high to handle with excel and not all combinations are feasible anyway.
Is there a way to not list all combinations and stil be able to solve it?
from pyomo.environ import * # For Pyomo 4.0 & later
model = AbstractModel()
## Define sets
model.idx_students = Set()
model.idx_companies = Set()
model.idx_meetingtimes = Set()
model.idx_s_c = Set(within=model.idx_students*model.idx_companies)
model.idx_s_m = Set(within=model.idx_students*model.idx_meetingtimes)
model.idx_c_m = Set(within=model.idx_companies*model.idx_meetingtimes)
model.idx_s_c_m =
Set(within=model.idx_students*model.idx_companies*model.idx_meetingtimes)
## Define parameters
model.prm_studentsMin = Param(model.idx_students)
model.prm_studentsMax = Param(model.idx_students)
model.prm_company_meetingtime_capa = Param(model.idx_c_m, default=0)
model.prm_student_meetingtime = Param(model.idx_s_m, within=Binary,
default=0)
model.prm_fit = Param(model.idx_s_c, default=0)
model.prm_s_c_m_locked = Param(model.idx_s_c_m, within=Binary, default=0)
## Define variables
model.var_X = Var(model.idx_s_c_m, within=Binary)
## Define objective function
def maxFit(model):
return sum(model.var_X[n]*model.prm_fit[m]
for (n) in model.idx_s_c_m
for (m) in model.idx_s_c)
model.SolverResults = Objective(rule=maxFit, sense=maximize)
## Capacity for companies during meeting-times
def company_meetingtime_capa_rule(model,c,m):
return sum(model.var_X[s,c,m] for s in model.idx_students) <=
model.prm_company_meetingtime_capa[c,m]
model.company_meetingtime_capa_constraint = Constraint(model.idx_c_m, rule =
company_meetingtime_capa_rule)
## Number of meetings for students and companies
def TerminstudentscompaniesRule(model, s, c):
return sum(model.var_X[s,c,m] for m in model.idx_meetingtimes) <= 1
model.TerminstudentscompaniesConstraint = Constraint(model.idx_s_c,
rule=TerminstudentscompaniesRule)
## meetingtime availability of students
def studentsmeetingtimeRule(model, s,m):
return sum(model.var_X[s,c,m] for c in model.idx_companies) <=
model.prm_student_meetingtime[s,m]
model.studentsmeetingtimeConstraint = Constraint(model.idx_s_m,
rule=studentsmeetingtimeRule)
## locked meetings
def lockedeTermineRule(model, s,c,m):
return (model.var_X[s,c,m]) >= model.prm_s_c_m_locked[s,c,m]
model.lockedeTermineConstraint = Constraint(model.idx_s_c_m,
rule=lockedeTermineRule)
## Min number of meetings for students
def minTerminestudentsRule(model,s):
return sum(model.var_X[s,c,m] for c in model.idx_companies for m in
model.idx_meetingtimes) >= model.prm_studentsMin[s]
model.minTerminestudentsConstraint = Constraint(model.idx_students,
rule=minTerminestudentsRule)
## Max number of meeting for students
def maxTerminestudentsRule(model,s):
return sum(model.var_X[s,c,m] for c in model.idx_companies for m in
model.idx_meetingtimes) <= model.prm_studentsMax[s]
model.maxTerminestudentsConstraint = Constraint(model.idx_students,
rule=maxTerminestudentsRule)
Really appreciate your help!
The easiest solution is to just sum over the variables that do exist in the Var with something like:
model.var_X = Var(model.idx_s_c_m, within=Binary)
## Capacity for companies during meeting-times
def company_meetingtime_capa_rule(model,c,m):
return sum(model.var_X[s,c,m] for s in model.idx_students
if (s,c,m) in model.idx_s_c_m) \
<= model.prm_company_meetingtime_capa[c,m]
model.company_meetingtime_capa_constraint = Constraint(
model.idx_c_m, rule = company_meetingtime_capa_rule)

Categories

Resources