Mixed-Integer Quadratic Programming in Python - python

I would like to solve in Python the following Mixed-Integer Quadratic Programming in Python. Nevertheless, I'm not familiar with the optimization
toolboxes of Python.
Can someone provide an example of code with the vectors X1, X2, X3, X4 given as below ?
X1 = np.array([3,10,20,10])
X2 = np.array([5,1,3,4])
X3 = np.array([2,3,1,4])
X4 = np.array([10,0,1,2])
The MIQP is written as :
I tried to solve it with CVXPY but i encoutered problem with the boolean
variable x = cp.Variable(1, boolean=True):
import numpy
import numpy as np
import cvxpy as cp
X1 = np.array([3,10,20,10])
X2 = np.array([5,1,3,4])
X3 = np.array([2,3,1,4])
X4 = np.array([10,0,1,2])
M = 100
x = cp.Variable(1, boolean=True)
Y1 = cp.Parameter(4)
Y2 = cp.Parameter(4)
a = cp.Parameter(1)
b = cp.Parameter(1)
c = cp.Parameter(1)
d = cp.Parameter(1)
delta = cp.Variable(1)
constraints = [Y1 <= X1 - a,
Y1 <= X2 - b,
Y1 >= X1 - a - M*delta,
Y1 >= X2 - b - M*(1-delta),
Y2 <= X3 - c,
Y2 <= X4 - d,
Y2 >= X3 - c - M*delta,
Y2 >= X4 - d - M*(1-delta),
0 <= a, a <= 10,
0 <= b, b <= 5,
0 <= c, c <= 5,
0 <= d, d <= 10,
delta == x]
obj = cp.Minimize(cp.sum_squares(Y1-Y2))
prob = cp.Problem(obj, constraints)
print(prob.solve())

In cvxpy, parameter is something you have a value to set to it. In your problem, basically all symbols other than the X1 to X4 are variables. So do a global replace of cp.Parameter to cp.Variable will work.
Then, I found the result to be
$ python3 cvxtest.py
69.99998471073722

Gekko with the APOPT solver can handle MIQP problems in addition to more general Nonlinear Mixed Integer Programming (MINLP). The solution is:
---------------------------------------------------
Solver : APOPT (v1.0)
Solution time : 2.610000000277068E-002 sec
Objective : 70.0000000000000
Successful solution
---------------------------------------------------
x: 1.0
obj: 70.0
Here is the Python script:
import numpy as np
from gekko import GEKKO
m = GEKKO()
X1 = m.Param([3,10,20,10])
X2 = m.Param([5,1,3,4])
X3 = m.Param([2,3,1,4])
X4 = m.Param([10,0,1,2])
M = 100
p = m.Array(m.FV,4,lb=0,ub=10); a,b,c,d=p
b.upper = 5; c.upper = 5
for pi in p:
pi.STATUS=1
x = m.FV(lb=0,ub=1,integer=True); x.STATUS=1
Y1,Y2 = m.Array(m.Var,2)
delta = m.FV(); delta.STATUS=1
m.Equations([Y1 <= X1 - a,
Y1 <= X2 - b,
Y1 >= X1 - a - M*delta,
Y1 >= X2 - b - M*(1-delta),
Y2 <= X3 - c,
Y2 <= X4 - d,
Y2 >= X3 - c - M*delta,
Y2 >= X4 - d - M*(1-delta),
delta == x])
m.Minimize((Y1-Y2)**2)
m.options.IMODE=2
m.options.SOLVER=1
m.solve()
print('x: ', x.value[0])
print('obj: ', m.options.OBJFCNVAL)

Related

Multivariate curve fit in python

Can somebody please point me in the right direction...
I need to find the parameters a,b,c,d of two functions:
Y1 = ( (a * X1 + b) * p0 + (c * X2 + d) * p1 ) / (a * X1 + b + c * X2 + d)
Y2 = ( (a * X2 + b) * p2 + (c * X2 + d) * p3 ) / (a * X1 + b + c * X2 + d)
X1, X2 (independent variables) and Y1, Y2 (dependent variables) are observations, i.e. one-dimensional arrays with thousands of entries each.
p0, p1, p2, p3 are known constants (scalars).
I successfully solved the problem with the first function only with a curve-fit (see below), but how do i solve the problem for Y1 and Y2 ?
Thank you.
import numpy as np
import matplotlib.pyplot as plt
from scipy.optimize import curve_fit
X = [X1,X2]
def fitFunc(X, a,b,c,d):
X1, X2 = X
return ((a * X1 + b) * p0 + (c * X2 + d) * p1) / (a * X1 + b + c * X2 + d)
fitPar, fitCov = curve_fit(fitFunc, X, Y1)
print(fitPar)
One way would be to minimize both your functions together using scipy.optimize.minimze. In the example below, a function residual is passed a, b, c, and d as initial guesses. Using these guesses, Y1 and Y2 are evaluated, then the mean squared error is taken using the data and predicted values of respective functions. The error is returned as the mean error of the two functions. The optimized set of parameters is stored in res as res.x.
import numpy as np
from scipy.optimize import minimize
#p0 = ... known
#p1 = ... known
#p2 = ... known
#p3 = ... known
def Y1(X, a,b,c,d):
X1, X2 = X
return ((a * X1 + b) * p0 + (c * X2 + d) * p1) / (a * X1 + b + c * X2 + d)
def Y2(X, a,b,c,d):
X1, X2 = X
return ((a * X1 + b) * p2 + (c * X2 + d) * p3) / (a * X1 + b + c * X2 + d)
X1 = np.array([X1]) # your X1 array
X2 = np.array([X2]) # your X2 array
X = np.array([X1, X2])
y1_data = np.array([y1_data]) # your y1 data
y2_data = np.array([y2_data]) # your y2 data
def residual(x):
a = x[0]
b = x[1]
c = x[2]
d = x[3]
y1_pred = Y1(X,a,b,c,d)
y2_pred = Y2(X,a,b,c,d)
err1 = np.mean((y1_data - y1_pred)**2)
err2 = np.mean((y2_data - y2_pred)**2)
error = (err1 + err2) / 2
return error
x0 = [1, 1, 1, 1] # Initial guess for a, b, c, and d respectively
res = minimize(residual, x0, method="Nelder-Mead")
print(res.x)

How to use AddBoolXOr in OR-tools

I try to understand OR-tools. I want to solve this equations system in modulo 2:
x1 + x2 + x3 + 0 = 0
x1 + x2 + 0 + x4 = 1
x1 + 0 + x3 + x4 = 1
0 + x2 + x3 + x4 = 1
this equates because of the modulo 2 to:
x1 ^ x2 ^ x3 = 0
x1 ^ x2 ^ x4 = 1
x1 ^ x3 ^ x4 = 1
x2 ^ x3 ^ x4 = 1
using the bitwise xor (see here).
So I tried the following code:
from ortools.sat.python import cp_model
# Creates the model.
model = cp_model.CpModel()
# Creates the variables.
x1 = model.NewBoolVar('x1')
x2 = model.NewBoolVar('x2')
x3 = model.NewBoolVar('x3')
x4 = model.NewBoolVar('x4')
# Creates the constraints.
model.AddBoolXOr(x1 ^ x2 ^ x3 == 0)
model.AddBoolXOr(x1 ^ x2 ^ x4 == 1)
model.AddBoolXOr(x1 ^ x3 ^ x4 == 1)
model.AddBoolXOr(x2 ^ x3 ^ x4 == 1)
# Creates a solver and solves the model.
solver = cp_model.CpSolver()
status = solver.Solve(model)
if status == cp_model.OPTIMAL:
print('x1 = %i' % solver.Value(x1))
print('x2 = %i' % solver.Value(x2))
print('x3 = %i' % solver.Value(x3))
print('x4 = %i' % solver.Value(x4))
but I get:
'calling xor on a linear expression is not supported, '
NotImplementedError: calling xor on a linear expression is not supported, please use CpModel.AddBoolXor
If I use AddBoolXor instead of AddBoolXOr I get:
AttributeError: 'CpModel' object has no attribute 'AddBoolXor'
AddBoolXor takes an array of Boolean literals.
model.AddBoolXOr([x1, x2.Not(), x3])
The semantic of AddBoolXor(xi) is sum(xi) % 2 == 1
So, in your case
# Creates the constraints.
model.AddBoolXOr([x1, x2, x3, True])
model.AddBoolXOr([x1, x2, x4])
model.AddBoolXOr([x1, x3, x4])
model.AddBoolXOr([x2, x3, x4])

Attempting to do verlet integration

I have tried adapting euler method code, and am using euler to calculate the first value so there are two for me to use in verlet but when i plot the graph i just get two perpendicular straight lines.
this is the code:
for t in t_array:
if t == 0:
x0 = x
x1 = x0
a = -k * x1 / m
x2 = x1 + dt * v
v = v + dt * a
x_list.append(x2)
v_list.append(v)
else:
x2 = x1
x1 = x0
x2 = 2*x1 - x0 + dt**2*a
v = (1/dt)*(x2 - x1)
x_list.append(x2)
v_list.append(v)
and then i plot a graph using matplotlib.

Python scipy fsolve to solve a large number of nonlinear equations

I want to solve a system of 6 nonlinear equations using Python. I found that I can use scipy's fsolve pretty easily to solve a system of 3 nonlinear equations. However, when I expand this to a larger system, I find that the solution does not solve the system of equations. Is there something I can correct that will allow for the solution of 6 nonlinear equations?
import numpy as np
from scipy.optimize import fsolve
def system(z):
#arbitrary system of 3 nonlinear equations
x1 = z[0]
x2 = z[1]
x3 = z[2]
F = np.empty((3))
F[0] = 20* x1 + x2**2
F[1] = x2 - x1
F[2] = x3 + 5 - x1*x2
return F
def system2(z):
#arbitrary system of 6 nonlinear equations
x1 = z[0]
x2 = z[1]
x3 = z[2]
x4 = z[3]
x5 = z[4]
x6 = z[5]
F = np.empty((6))
F[0] = 20* x1 + x2**2
F[1] = x2 - x1
F[2] = x3 + 5 - x1*x2
F[3] = x3 + x2
F[4] = x5 + x4**2
F[5] = x6**2 + x1 - 20
return F
uInitial = np.array([1,1,1])
u = fsolve(system,uInitial)
print('Solution: ',u)
print('Solution check: ',system(u),'\n') #yields zeros as expected
vInitial = np.array([1,1,1,1,1,1])
v = fsolve(system2,vInitial)
print('Solution: ',v)
print('Solution check: ',system2(v)) #unexpectedly does not yield zeros. Equations not solved correctly.
When applying the given solution back into the system of equations, I should expect to receive zeros (or nearly zero). This would confirm that the computed solution solves the given set of equations. I tried checking with this method for both the system of 3 equations and the system of 6 equations, but only the system of 3 equations is solved correctly with this check. What can I do to solve the system of 6 nonlinear equations?
Your system is inconsistent and your initial guess is off. Try adding fourth equation to the first system of three equations:
F[0] = 20 * x1 + x2**2 # "first" equation
F[1] = x2 - x1 # "second" (=> x1 == x2)
F[2] = x3 + 5 - x1*x2 # "third"
F[3] = x3 + x2 # "fourth" equation (=> x3 == -x2)
First, let's solve first three equations. From the second equation it follows that x1 is equal to x2. Therefore the first equation can be re-written as:
F[0] = 20 * x1 + x1**2
which leads to x1 = -20 (and x2 = -20). Using this in the third equation leads to x3 = 395. Try to modify initial conditions for the first system to uInitial = np.array([-30, -30, 1]) - you should get the correct answer.
Now, let's solve all four equations. The third equation, using the fact that x2 == x1, can be re-written as:
F[2] = x3 + 5 - x1**2
From the fourth equation it follows that x3 == -x2 (and so x3 == -x1 as well). Therefore, this equation can be rewritten as x3 + 5 - x3**2 == 0 => x3 = 0.5 +(-) sqrt(21)/2 which is different from 395 that we got above using first three equations.
This shows that you have an inconsistent system of equations which has no solution.

How to I get Gurobi to give only integer solutions?

I'm trying to optimize the following problem in python using Gurobi and the answer comes out as a decimal. How do I get the output to solve for optimal integers?
from gurobipy import *
def main():
pass
if __name__ == '__main__':
main()
try:
#Create a new model
m = Model("Investment");
#Create variables
x1 = m.addVar(vtype=GRB.CONTINUOUS, name="x1")
x2 = m.addVar(vtype=GRB.CONTINUOUS, name="x2")
x3 = m.addVar(vtype=GRB.CONTINUOUS, name="x3")
x4 = m.addVar(vtype=GRB.CONTINUOUS, name="x4")
x5 = m.addVar(vtype=GRB.CONTINUOUS, name="x5")
#Intigrate new variables
m.update()
#Set Objective
m.setObjective(160*x1 + 160*x2 + 160*x3 + 75*x4 + 75*x5, GRB.MINIMIZE)
m.addConstr( x1 + x2 + x3 >= 3, "c0")
m.addConstr( x1 >= 1, "c1")
m.addConstr( x2 >= 0, "c2")
m.addConstr( x3 >= 1, "c3")
m.addConstr( x4 >= 0, "c4")
m.addConstr( x5 >= 0, "c5")
m.addConstr(40*x1 + 40*x2 + 40*x3 + 25*x4 + 25*x5 >= 365,"c6")
m.optimize()
for v in m.getVars():
print v.varName, v.x
print "Obj:", m.objVal
except GurobiError:
print "Error reported"
Use .addVar(vtype=GRB.INTEGER, ...).
See http://www.gurobi.com/documentation/5.6/reference-manual/py_model_addvar
vtype = GRB.INTEGER
For binary vtype = GRB.BINARY, total 5 variables types

Categories

Resources