I am currently trying to solve this problem. I need to maximize the profit of this company.
That s the code I currently have:
from pyomo.environ import *
from pyomo.opt import *
opt = solvers.SolverFactory("ipopt")
model = ConcreteModel()
model.x1 = Var(within=NonNegativeIntegers)
model.x2 = Var(within=NonNegativeIntegers)
model.y1 = Var(within=NonNegativeIntegers)
model.y2 = Var(within=NonNegativeIntegers)
model.b1 = Var(within=Boolean)
model.b2 = Var(within=Boolean)
model.c1 = Constraint(expr = model.x1 + model.x2 + model.y1 + model.y2 <= 7000)
model.c2 = Constraint(expr = 2*model.x1 + 2*model.x2 + model.y1 + model.y2 <= 10000)
model.c3 = Constraint(expr = model.x1 <= 2000)
model.c4 = Constraint(expr = model.x2 <= 1000)
model.c5 = Constraint(expr = model.y1 <= 2000)
model.c6 = Constraint(expr = model.y2 <= 3000)
model.z = Objective(expr= (150*model.x1 + 180*model.x2*model.b1 + 100*model.y1 + 110*model.y2*model.b2), sense=maximize)
results = opt.solve(model)
This is the code I tried to write for my constraint which is then only using the first slope as long as it does not exceed 2000 products:
def ObjRule(model):
if model.x1 >= 2000:
return model.b1==1
if model.x2 >= 2000:
return model.b2 == 1`
If someone would have a hint, how I could proceed that would be great.
thank you in advance,
Patrick
In Pyomo, rules are not callbacks sent to a solver. They are called once for each index to obtain a static set of expressions. This set of expressions is what is sent to a solver. Any if-logic you use inside of rules should not involve the values of variables (unless it is based on the initial value of a variable, in which case you would wrap the variable in value() wherever you use it outside of the main expression that is returned).
If you want to model a piecewise function, you need to apply some kind of modeling trick to do so. In some cases this involves introducing discrete variables (see examples for the Piecewise component), in other cases it does not (for instance when maximizing a piecewise function that can be expressed as the min of a finite number of affine functions).
Related
I am using Microsoft Solver Foundation version 3.0.2.10889 Express Edition for linear programming. I have no problems when using LP solver. However I am unable to set two interval constraints for one Decision at one time. What I would like is to set "D_1 == 0" when "lowerbound <= D_1 <= upperbound" was not satisfied.
I have done some search and found this:
Microsoft Solver Foundation for semi-integer
I tried to implement it, please see simplified code below. When I set the lowerbound for all decisions = 1, all decisions are resolved at least with value 1. To test the model more I set the lowerbound for all decisions = 5, hoping that I will get some decisions with result = 0. But the model is now infeasable.
It seems that the model does not work as I expected. lowerbound in the model still acts only as minimum value. Not in such a way that when lowerbound is infeasible, return 0. It implies binary does not have an effect on the model.
SolverContext context = SolverContext.GetContext();
context.ClearModel();
Model model = context.CreateModel();
Decision D_1 = new Decision(Domain.RealNonnegative, "D_1");
Decision D_2 = new Decision(Domain.RealNonnegative, "D_2");
model.AddDecisions(D_1, D_2);
Decision binary = new Decision(Domain.IntegerRange(0, 1), "binary");
model.AddDecisions(binary);
Term woodproduction = 0.5 * D_1 + 0.7 * D_2;
model.AddConstraint("constraint_woodproduction", woodproduction == 20.5);
Term lowerbound = 10;
Term upperbound = 100;
Term C_1 = lowerbound * binary <= D_1 <= upperbound * binary;
model.AddConstraint("constraint_1", C_1);
Term C_2 = lowerbound * binary <= D_2 <= upperbound * binary;
model.AddConstraint("constraint_2", C_2);
model.AddGoal("cost", GoalKind.Minimize, lpgoal);
Solution solution = context.Solve(new SimplexDirective
{
IterationLimit = -1,
GetInfeasibility = true, //GetSensitivity = true
});
Thank you for any feedback,
Zdenek
I have a question regarding the correct formulation of a piecewise step function in pyomo. I want to include in my model a single piecewise function of the form:
/ 1 , 0 <= X(t) <= 1
Z(X) = \ 0 , 1 <= X(t) <= 2
Where X is being fit to data over taken over a time domain and Z acts like a binary variable. The most similar example in pyomo documentation is the step.py example using INC. However, when solving with this formulation I observe the problem of the domain variable x ‘sticking’ to the breakpoint at x=1. I assume this is because (as noted in the documentation) Z can solve to the entire vertical line if continuous or is doubly feasible at both 0 and 1 if binary. Other formulations offered via the piecewise function (i.e. dlog, dcc, log, etc.) experience similar issues (in fact, based on the output to GAMS I’m pretty sure they don’t support binary/integer variables at all).
Is there a ‘correct’ way to formulate a piecewise function in pyomo that avoids the multiple-feasibility issue at the breakpoint, thus avoiding the domain variable converging to the breakpoint? I am using BARON with solvers cplex and ipopt, however my gut tells me this formulation issue can’t be solved by simply changing solvers.
I can also send a document illustrating my observations on why the current pyomo piecewise formulations don’t support binary variables, if it would help.
Here's some sample code where we try to minimise the sum of the step function Z.
model = ConcreteModel()
model.A = Set(initialize=[1,2,3])
model.B = Set(initialize=['J', 'K'])
model.x = Var(model.A, model.B, bounds=(0, 2))
model.z = Var(model.A, model.B, domain = Binary)
DOMAIN_PTS = [0,1,1,2]
RANGE_PTS = [1,1,0,0]
model.z_constraint = Piecewise(
model.A, model.B,
model.z, model.x,
pw_pts=DOMAIN_PTS,
pw_repn='INC',
pw_constr_type = 'EQ',
f_rule = RANGE_PTS,
unbounded_domain_var = True)
def objective_rule(model):
return sum(model.z[a,b] for a in model.A for b in model.B)
model.objective = Objective(rule = objective_rule, sense=minimize)
If you set sense = minimize above, the program will solve and give x = 1 for each index value. If you set sense = maximize, the program will solve and give x = 0 for each index value. I'm not too sure what you mean by stickiness, but I don't think this program does it. and it implements the step function.
This assumes that your z is not also indexed by time. If so, I would need to edit this answer:
model.t = RangeSet(*time*)
model.x = Var(model.t, bounds=(0, 2))
model.z = Var(domain=Binary)
model.d = Disjunction(expr=[
[0 <= model.x[t] for t in model.t] + [model.x[t] <= 1 for t in model.t],
[1 <= model.x[t] for t in model.t] + [model.x[t] <= 2 for t in model.t]
])
TransformationFactory('gdp.bigm').apply_to(model)
SolverFactory('baron').solve(model)
Does anyone know what is a good way to indicate whether a model variable is bounded between certain values? For example, indicator1 = 1 when 0<= variable x <=200 else 0, indicator2 = 1 when 200<= variable x <= 300.
One use case of this is to calculate weight dependent shipping cost, e.g. if the shipment weighs less than 200 lbs then it costs $z/lb; if the shipment weighs more than 200lb and less than 300 lbs then it costs $y/lb.
Minimize W1*z + W2*y
Weight = W1 + W2
0 <= W1 <= 200*X1
200*X2 <= W2 <= 300*X2
X1+ X2 = 1
X1, X2 binary
Weight, W1, W2 >= 0
Above is the formulation I came up with for this situation. However, now I have more than 200 buckets of values to check, so this formulation does not seem efficient enough. I am wondering whether there are better ways to model this?
This problem can also be modeled as a Generalized Disjunctive Program (GDP). It's more verbose, but more descriptive.
from pyomo.environ import *
from pyomo.gdp import *
m = ConcreteModel()
m.total_weight_cost = Var(domain=NonNegativeReals)
m.weight = Var(domain=NonNegativeReals)
m.weight_buckets = RangeSet(2)
m.weight_bucket_lb = Param(m.weight_buckets, initialize={1: 0, 2: 200})
m.weight_bucket_ub = Param(m.weight_buckets, initialize={1: 200, 2: 300})
m.weight_bucket_cost = Param(m.weight_buckets, initialize={1: z, 2: y})
m.weight_bucket_disjunction = Disjunction(expr=[
[m.total_weight_cost == m.weight_bucket_cost[bucket] * m.weight,
m.weight_bucket_lb[bucket] <= m.weight,
m.weight <= m.weight_bucket_ub[bucket]
for bucket in m.weight_buckets]
])
TransformationFactory('gdp.bigm').apply_to(m)
SolverFactory('gurobi').solve(m, tee=True)
m.display()
I haven't been able to find particular solutions to this differential equation.
from sympy import *
m = float(raw_input('Mass:\n> '))
g = 9.8
k = float(raw_input('Drag Coefficient:\n> '))
v = Function('v')
f1 = g * m
t = Symbol('t')
v = Function('v')
equation = dsolve(f1 - k * v(t) - m * Derivative(v(t)), 0)
print equation
for m = 1000 and k = .2 it returns
Eq(f(t), C1*exp(-0.0002*t) + 49000.0)
which is correct but I want the equation solved for when v(0) = 0 which should return
Eq(f(t), 49000*(1-exp(-0.0002*t))
I believe Sympy is not yet able to take into account initial conditions. Although dsolve has the option ics for entering initial conditions (see the documentation), it appears to be of limited use.
Therefore, you need to apply the initial conditions manually. For example:
C1 = Symbol('C1')
C1_ic = solve(equation.rhs.subs({t:0}),C1)[0]
print equation.subs({C1:C1_ic})
Eq(v(t), 49000.0 - 49000.0*exp(-0.0002*t))
I am trying to solve a set of M simultaneous eqns with M variables. I input a M X 2 matrix in as an initial guess to my function and it returns a M X 2 matrix, where each entry would equal zero if my guess was correct. Thus my function can be represented as f_k(u1,u2,...uN) = 0 for k=1,2,...N. Below is the code for my function, (for simplicities sake I have left out the modules that go with this code, i.e. p. or phi. for instance. I was more wondering if anyone else has had this error before)
M = len(p.x_lat)
def main(u_A):
## unpack u_A
u_P = u_total[:,0]
u_W = u_total[:,1]
## calculate phi_A for all monomeric species
G_W = exp(-u_W)
phi_W = zeros(M)
phi_W[1:] = p.phi_Wb * G_W[1:]
## calculate phi_A for all polymeric species
G_P = exp(-u_P)
G_P[0] = 0.
G_fwd = phi.fwd_propagator(G_P,p.Np,0) #(function that takes G_P and propagates outward)
G_bkwd = phi.bkwd_propagator(G_P,p.Np,0) #(function that takes G_P and propagates inward)
phi_P = phi.phi_P(G_fwd,G_bkwd,p.norm_graft_density,p.Np) #(function that takes the two propagators and combines them to calculate a segment density at each point)
## calculate u_A components
u_intW = en.u_int_AB(p.chi_PW,phi_P,p.phi_Pb) + en.u_int_AB(p.chi_SW,p.phi_S,p.phi_Sb) #(fxn that calculates new potential from the new segment densities)
u_intW[0] = 0.
u_Wprime = u_W - u_intW
u_intP = en.u_int_AB(p.chi_PW,phi_W,p.phi_Wb) + en.u_int_AB(p.chi_PS,p.phi_S,p.phi_Sb) #(fxn that calculates new potential from the new segment densities)
u_intP[0] = 0.
u_Pprime = u_P - u_intP
## calculate f_A
phi_total = p.phi_S + phi_W + phi_P
u_prime = 0.5 * (u_Wprime + u_Pprime)
f_total = zeros( (M, 2) )
f_total[:,0] = 1. - 1./phi_total + u_prime - u_Wprime
f_total[:,1] = 1. - 1./phi_total + u_prime - u_Pprime
return f_total
I researched ways of solving nonlinear equations such as this one using python. I came across the scipy.optimize library with the several options for solvers http://docs.scipy.org/doc/scipy-0.13.0/reference/optimize.nonlin.html. I first tried to use the newton_krylov solver and received the following error message:
ValueError: Jacobian inversion yielded zero vector. This indicates a bug in the Jacobian approximation.
I also tried broyden1 solver and it never converged but simply stayed stagnant. Code for implementation of both below:
sol = newton_krylov(main, guess, verbose=1, f_tol=10e-7)
sol = broyden1(main, guess, verbose=1, f_tol=10e-7)
My initial guess is given below here:
## first guess of u_A(x)
u_P = zeros(M)
u_P[1] = -0.0001
u_P[M-1] = 0.0001
u_W = zeros(M)
u_W[1] = 0.0001
u_W[M-1] = -0.0001
u_total = zeros( (M,2) )
u_total[:,0] = u_P
u_total[:,1] = u_W
guess = u_total
Any help would be greatly appreciated!