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..]
Related
My goal is to write the following constraint with the doxplex.mp.model with Python API:
P[t,j] >= s[t-j+1] - sum(s[k=t-j+2] from k to t) for t = 1,....,N, j = 1,...,t
my code.
from docplex.mp.model import Model
clsp = Model(name = 'capacitated lot sizing problem')
no_of_period = 8
period_list = [t for t in range(1, no_of_period+1)]
s_indicator = clsp.binary_var_dict(period_list, name = 's_indicator')
p_indicator = clsp.binary_var_matrix(period_list, period_list, name = 'p_indicator')
m_8 = clsp.add_constraints(p_indicator[t,j] >= s_indicator[t-j+1] - clsp.sum(s_indicator[t-j+2] for j in range(1,t+1))
for j in t for t in period_list )
Output: Keyerror 0
Any help would be appreciated
Your code extract is not correct Python (for j in t). I had to modify it to make it run:
m_8 = clsp.add_constraints\
(p_indicator[t,j] >= s_indicator[t-j+1] - clsp.sum(s_indicator[t-j+2] for j in range(1,t+1))
for j in period_list for t in period_list )
Which gives ma a KeyError: 9 exception.
To fix this, remember that binary_var_matrix creates a Python dictionary, whose keys are the first argument, here period_list, ranging from 1 to 8.
To investigate this I wrote this small code to investigate all possible keys generated by your code:
ke = 0
for t in period_list:
for j in period_list:
ix = t-j+2
if ix not in period_list:
ke += 1
print(f"** Key error[{ke}], t={t},j={j}, t-j+2={t-j+2}")
Prints 22 key errors, for example t=8, j=1 computes (t-j+2)=9 which is outside the dictionary key set.
To summarize: check your indices w.r.t the keys of the variable dictionaries in your model.
I have the following code(python 3) for adding constraints to pulp(v 2.3). It needs to add up to 400000 constraints(100^2 S, 4 A).
def linearProgram(self, error = 1e-12):
lp_problem = p.LpProblem('best-Vpi', p.LpMinimize)
#create problem variables
V = p.LpVariable.dicts("V",range(self.S), cat = "Continuous")
#objective function
for i in range(self.S):
self.v.append(V[i])
lp_problem += p.lpSum(self.v)
#constraints
for s in range(self.S):
for a in range(self.A):
pv = p.LpAffineExpression([(V[x],self.T[s][a][x]) for x in range(self.S)])
constraint = p.lpSum([self.PR[s][a], self.gamma*pv ])
lp_problem += V[s] >= constraint
status = lp_problem.solve(p.PULP_CBC_CMD(msg = 0)) #solve
I can't seem to be able to optimise it further..
I even tried multiprocessing, but it gave a lot of errors-
def __addconstraints(self, S0, S1, lp_problem):
for s in range(S0, S1):
for a in range(self.A):
pv= p.lpDot(self.T[s][a],self.v)
lp_problem += self.v[s] >= p.lpSum([self.PR[s][a], self.gamma*pv])
..................
#in linearProgram
if self.S%4:
s0, s1 = 0, self.S//3
else:
s0, s1 = 0, self.S//4
incr = s1
processes = []
for x in range(4):
proc = multiprocessing.Process(target=self.__addconstraints, args=(s0, s1, lp_problem))
processes.append(proc)
proc.start()
s0 = s1
s1 = min(s1+incr, self.S)
for proc in processes:
proc.join()
hard code for episodic? no need (due to initialization of mdp)
if self.mdptype=="episodic":
for state in self.end:
lp_problem += V[state] == 0
I am new to both pulp and multiprocessing, so I don't really have an idea what I'm doing :p
Any kind of help is appreciated.
In your code, you first build a p.LpAffineExpression, then you apply a p.lpSum and finally you do a third operation on the result V[s] >= constraint. The two last operations may increase the time because the expression is being copied each time.
From my experience, the fastest times I've gotten are doing the following:
# _vars_tup is a list of (key, value) pairs where each key is a variable and each value is a coefficient.
# it's like initializing a dictionary.
# CONSTANT is a python number (not a pulp variable)
model += p.LpAffineExpression(_vars_tup, constant=CONSTANT) >= 0
The idea is to reduce the number of times you do operations with p.LpAffineExpression objects, because a copy is done at each operation. So, build the list of variables and coefficients (_vars_tup) for ALL the variables present in the constraint and then at the last step create the p.LpAffineExpression and compare it with a constant.
An equivalent way would be (although I haven't tried it):
const = p.LpConstraint(e=p.LpAffineExpression(_vars_tup, constant=_constant), sense = p.LpConstraintGE, rhs = -CONSTANT)
model.addConstraint(other)
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)
I've build a pyomo model, and via following I am writing the lp file of the model:
# write LP file
filename = os.path.join(os.path.dirname(__file__), 'model.lp')
model.write(filename, io_options={'symbolic_solver_labels': True})
I am getting the model.lp file in the folder. And it looks like following:
\* Source Pyomo model name=urbs *\
min
obj:
+1 costs(Environmental)
+1 costs(Fixed)
+1 costs(Fuel)
+1 costs(Invest)
+1 costs(Variable)
s.t.
c_e_res_vertex(1_Mid_Biomass_Stock)_:
+1 e_co_stock(1_Mid_Biomass_Stock)
-1 e_pro_in(1_Mid_Biomass_plant_Biomass)
= 0
c_e_res_vertex(1_Mid_Coal_Stock)_:
+1 e_co_stock(1_Mid_Coal_Stock)
-1 e_pro_in(1_Mid_Coal_plant_Coal)
= 0
My problem is, I would like to also save the variable values of the model.
Is there a way to force solver to write values of the variables of the model into the lp file?
or something, which does the same thing with different manner?
Two ways comes to my mind.
Good old search and replace
With your LP file, do a search and replace. For example, the variable x with indices 2 and 'productA' (in Pyomo: model.x[2,'productA']) is written in the LP file as x(2_productA). Knowing this, for each variable and for each of their indices, generate their name in the LP format, and search all occurences of these in the LP file, to replace them with their value.
If lpFileContent is the string that is contained in your LP file, this will look like:
for v in model.component_objects(Var, active=True):
varName = str(v)
varObject = getattr(model, varName)
for index in varObject:
indexStr = str(index)
# Convert your index string:
indexStr.replace(",","_")
indexStr.replace(" ","_")
indexStr.replace("'","") # Add more as you need.
#Replace by value:
lpFileContent.replace(varName + "(" + indexStr + ")", varObject[index].value)
with open("output.txt", "w") as outputFile
outputFile.write(lpFileContent)
Using exressions
When defining constraints, it is comon to do it this way (from Pyomo doc):
model.A = RangeSet(1,10)
model.a = Param(model.A, within=PositiveReals)
model.ToBuy = Var(model.A)
def bud_rule(model, i):
return model.a[i]*model.ToBuy[i] <= i
aBudget = Constraint(model.A, rule=bud_rule)
Then, it is always possible to retrieve the expression of this constraint by doing this little trick:
model.A = RangeSet(1,10)
model.a = Param(model.A, within=PositiveReals)
model.ToBuy = Var(model.A)
def bud_rule(model, i):
print(str(model.a[i]*model.ToBuy[i]) + " <= " + str(i))
return model.a[i]*model.ToBuy[i] <= i
aBudget = Constraint(model.A, rule=bud_rule)
which will yield something like
1 * model.ToBuy[1] <= 1
2 * model.ToBuy[2] <= 2
3 * model.ToBuy[3] <= 3
4 * model.ToBuy[4] <= 4
... #It goes on
10 * model.ToBuy[10] <= 10
I believe that this is also something you can use (with search and replace or by printing variable values while building your constraints again but after solving). It grants more ability to customize your output, is easy to debug, but will be extremely slow if the expression is long (like with a summation on thousands of elements).
I need to turn following equation into a python function.
k = people[i]
i = people[j]
costs[i][j]
costs[j][k]
change = -costs[i][k] - costs[j][l] + costs[i][l] + cost[j][k]
I think what you're looking for is:
def change(i,j,costs,people):
k = people[i]
l = people[j] # was originally i = people[j] but unsure where l comes from otherwise
result = -costs[i][k] - costs[j][l] + costs[i][l] + cost[j][k]
return result
(and then call with:
mychange = change(i,j,costs,people)
)
Note that if my assumption on where l comes from is wrong, change that 3rd line back to i = people[j] and pass in l as well.
Also note that using l as a variable is a bad idea as it's rather hard to tell apart from 1 (and also, using i,j,k,l is bad when you could use a more descriptive value to make it clearer what this means)