How to multiply vectors in Gurobi using Python? - python

I am trying to write a linear constraint in Gurobi using Python API. Here in this picture in the first line.
As the picture can't be opened, the constraint is:
y_i≥(w_j a_i-γ_j )-M(1-x_ij ),i=1,…,m,j=1,…,k
import pandas as pd
import numpy as np
import gurobipy as gp
from gurobipy import GRB
A=np.array([[ 7.6 , 8 ],
[ 3 , 2.7],
[ 0 , 0 ],
[ 0.8 , 0.5],
[ 6.6, 7.4],
[ 6.7, 7.8],
[ 1.9 , 2.6],
[ 3.2 , 4.6],
[ 6.4, 6.3],
[10 , 10]])
m = A.shape[0]#number of rows in A
n = A.shape[1] #number of cols in A
M = 100000
k=2#cluster the data points into k clusters
# create model
model = gp.Model('hyperplane clustering')
# create variables
# Create a (m,k) array of binary variables
# x[i,j]=1 means that point ai is assigned to cluster j
x = model.addMVar((m,k), vtype=gp.GRB.BINARY,name="x")
y = model.addVars(m,lb=0.0, ub=gp.GRB.INFINITY, vtype=gp.GRB.CONTINUOUS, name="y")
w = {}
for i in range(k):
for j in range(n):
w[i,j] = model.addVar(lb=0.0, ub=1.0, vtype=gp.GRB.CONTINUOUS, name='w_%s_%s' %(i,j))
w = gp.tupledict(w)
gamma = model.addVars(k,vtype=gp.GRB.CONTINUOUS, name="gamma")
model.update()
for i in range(m):
for j in range(k):
wj = w.select(j,'*')
wjmat = np.mat(wj).T
Amat = np.mat(A[i,:])
model.addConstr(y[i] > (-np.dot(Amat,wjmat) +gamma[j])-M*(1-x[i,j]))
I am trying to write like this. But I always got the error' Incompatible vector dimensions'
Hope someone can help me solve this. Thanks!

As already mentioned in the comments, you can't use numpy methods like np.dot with Gurobi objects. And since the third constraint can't be modelled directly with MVars and Gurobi's matrix interface, I'd recommend using Vars.
Then, simply write the dot product as a sum of products:
import gurobipy as gp
from gurobipy import quicksum as qsum
# A = ...
m, n = A.shape
k = 2
M = 100_000
model = gp.Model('hyperplane clustering')
# Variables
x = model.addVars(m, k, vtype="B", name="x")
y = model.addVars(m, vtype="C", name="y")
w = model.addVars(k, n, ub=1.0, vtype="C", name="w")
γ = model.addVars(k, vtype="C", name="γ")
for i in range(m):
for j in range(k):
wdota = qsum(w[j, r] * A[i, r] for r in range(n))
# first constraint
model.addConstr(y[i] >= wdota - γ[j] - M*(1-x[i,j]))
# second constraint
model.addConstr(y[i] >= -1.0*wdota + γ[j] - M*(1-x[i,j]))

Related

Implementing a partial pivot If condition for Gaussian Elimination in Python

I've figured out how to code a function such that you can row reduce and solve linear algebra problems, the only issue I'm running into is setting up the if condition that does the partial pivoting when the constant that is used to row reduce is equal to 0. I've attempted it below and the logic makes sense but am struggling to understand why my solution doesn't work.
import numpy as np
def gaussElim(A,B):
M = np.concatenate((A,B), axis=1)# Combines the two matrices (assuming they have the same number of rows and matrix B has been )
nr, nc = M.shape
for r in range (nr):
const = M[r][r]
if const == 0: # **This is the condition that is tripping me up**
for i in range (nr-1):
M[r][i]=M[r+1][i]
M[r+1][i] = M[r][i]
const = M[r][r]
for c in range (r,nc):
M[r][c] = M[r][c]/const
for rr in range(nr):
if rr!= r :
const = M[rr][r]
for c in range(r,nc):
M[rr][c] = M[rr][c] - const * M[r][c]
return M[:, nc-1]
Mrx = np.array([ [1.0,3,2,4,3,1], [-4,0,3,2,3,4], [3,-1,3,2,2,5], [3,3,12,2,-
6,-4], [-1,-2,-3,7,6,4], [7,5,0,0,4,2] ])
Rhs = np.array([[ 4, 5, 6, 10, 6, -8 ]]) # This is a row vectorv
RhsT = Rhs.T # Rhs.T is transpose of Rhs and a column vector
S = gaussElim(Mrx,RhsT)
print(S)
A1 = np.array([[2.0,1,-1],[2,1,-2],[1,-1,1]])
b1 = np.array([[1.0],[-2],[2]])
S1 = gaussElim(A1,b1)
print (S1)
x = np.linalg.solve(A1,b1)
print(x)
Yes I have looked at other people's solutions to Gaussian elimination but I want to understand why more specifically my solution to partial pivoting isn't working. Thank you!
Imputing A1, b1 into my function gives me
[1, 0.8, 1.8]
The correct answer is
[1, 2, 3]
The print statements were so I could see if my function was working as intended.
One issue is this code:
for i in range (nr-1):
M[r][i]=M[r+1][i] # line 1
M[r+1][i] = M[r][i] # line 2
const = M[r][r] # line 3
The line I've commented as line 2 simply undoes the work of line 1. If you're attempting to swap values, try replacing lines 1 and 2 with this:
M[r][i], M[r+1][i] = M[r+1][i], M[r][i]
... or, if you prefer to really be explicit about the swap:
temp = M[r][i]
M[r][i]=M[r+1][i] # line 1
M[r+1][i] = temp # line 2
A second (probably benign) issue in your code is that line 3 above (const = M[r][r]) does not need to be inside the loop as it currently is, and I believe you can outdent one level with no change in the ultimate result.
A third (benign) issue is that M[r][c] = M[r][c]/const can be simplified to M[r][c] /= const, assuming the original arrays A and B (and thus M) are floats.
Similarly, M[rr][c] = M[rr][c] - const * M[r][c] can be simplified to M[rr][c] -= const * M[r][c].
Putting it all together (most importantly, correcting the first issue above):
import numpy as np
def gaussElim(A,B):
M = np.concatenate((A,B), axis=1)# Combines the two matrices (assuming they have the same number of rows and matrix B has been )
nr, nc = M.shape
for r in range (nr):
const = M[r][r]
if const == 0: # **This is the condition that is tripping me up**
for i in range (nr-1):
M[r][i], M[r+1][i] = M[r+1][i], M[r][i]
const = M[r][r]
for c in range (r,nc):
M[r][c] /= const
for rr in range(nr):
if rr!= r :
const = M[rr][r]
for c in range(r,nc):
M[rr][c] -= const * M[r][c]
return M[:, nc-1]
Mrx = np.array([ [1.0,3,2,4,3,1], [-4,0,3,2,3,4], [3,-1,3,2,2,5], [3,3,12,2,-
6,-4], [-1,-2,-3,7,6,4], [7,5,0,0,4,2] ])
Rhs = np.array([[ 4, 5, 6, 10, 6, -8 ]]) # This is a row vectorv
RhsT = Rhs.T # Rhs.T is transpose of Rhs and a column vector
S = gaussElim(Mrx,RhsT)
print(S)
A1 = np.array([[2.0,1,-1],[2,1,-2],[1,-1,1]])
b1 = np.array([[1.0],[-2],[2]])
S1 = gaussElim(A1,b1)
print (S1)
x = np.linalg.solve(A1,b1)
print(x)
Output:
[-0.97124946 2.88607869 -1.80198876 3.47492434 -6.16688284 4.51794207]
[0.33333333 1.33333333 1. ]
[[1.]
[2.]
[3.]]

OpenMDAO cache_linear_solution not updating initial guess

I want to save time on expensive linear solves for my optimization by using the previous linear solutions as initial guesses for the subsequent iteration in an optimization. I'm looking through OpenMDAO's example for the cache_linear_solution feature which seems to have been developed for this purpose (here) and code shown below:
from distutils.version import LooseVersion
import numpy as np
import scipy
from scipy.sparse.linalg import gmres
import openmdao.api as om
class QuadraticComp(om.ImplicitComponent):
"""
A Simple Implicit Component representing a Quadratic Equation.
R(a, b, c, x) = ax^2 + bx + c
Solution via Quadratic Formula:
x = (-b + sqrt(b^2 - 4ac)) / 2a
"""
def setup(self):
self.add_input('a', val=1.)
self.add_input('b', val=1.)
self.add_input('c', val=1.)
self.add_output('states', val=[0,0])
self.declare_partials(of='*', wrt='*')
def apply_nonlinear(self, inputs, outputs, residuals):
a = inputs['a']
b = inputs['b']
c = inputs['c']
x = outputs['states'][0]
y = outputs['states'][1]
residuals['states'][0] = a * x ** 2 + b * x + c
residuals['states'][1] = a * y + b
def solve_nonlinear(self, inputs, outputs):
a = inputs['a']
b = inputs['b']
c = inputs['c']
outputs['states'][0] = (-b + (b ** 2 - 4 * a * c) ** 0.5) / (2 * a)
outputs['states'][1] = -b/a
def linearize(self, inputs, outputs, partials):
a = inputs['a'][0]
b = inputs['b'][0]
c = inputs['c'][0]
x = outputs['states'][0]
y = outputs['states'][1]
partials['states', 'a'] = [[x**2],[y]]
partials['states', 'b'] = [[x],[1]]
partials['states', 'c'] = [[1.0],[0]]
partials['states', 'states'] = [[2*a*x+b, 0],[0, a]]
self.state_jac = np.array([[2*a*x+b, 0],[0, a]])
def solve_linear(self, d_outputs, d_residuals, mode):
if mode == 'fwd':
print("incoming initial guess", d_outputs['states'])
if LooseVersion(scipy.__version__) < LooseVersion("1.1"):
d_outputs['states'] = gmres(self.state_jac, d_residuals['states'], x0=d_outputs['states'])[0]
else:
d_outputs['states'] = gmres(self.state_jac, d_residuals['states'], x0=d_outputs['states'], atol='legacy')[0]
elif mode == 'rev':
if LooseVersion(scipy.__version__) < LooseVersion("1.1"):
d_residuals['states'] = gmres(self.state_jac, d_outputs['states'], x0=d_residuals['states'])[0]
else:
d_residuals['states'] = gmres(self.state_jac, d_outputs['states'], x0=d_residuals['states'], atol='legacy')[0]
p = om.Problem()
indeps = p.model.add_subsystem('indeps', om.IndepVarComp(), promotes_outputs=['a', 'b', 'c'])
indeps.add_output('a', 1.)
indeps.add_output('b', 4.)
indeps.add_output('c', 1.)
p.model.add_subsystem('quad', QuadraticComp(), promotes_inputs=['a', 'b', 'c'], promotes_outputs=['states'])
p.model.add_design_var('a', cache_linear_solution=True)
p.model.add_constraint('states', upper=10)
p.setup(mode='fwd')
p.run_model()
print(p['states'])
derivs = p.compute_totals(of=['states'], wrt=['a'])
print(derivs['states', 'a'])
p['a'] = 4
derivs = p.compute_totals(of=['states'], wrt=['a'])
print(derivs['states', 'a'])
The above code gives the following print out:
[-0.26794919 -4. ]
incoming initial guess [0. 0.]
[[-0.02072594]
[ 4. ]]
incoming initial guess [0. 0.]
[[-0.02072594]
[ 4. ]]
From the print out of this example it doesn't look like the initial guess for the linear guess is actually being updated. Am I missing something? I've also tried running the code with the cache_linear_solution set to False and the result seems to be the same.
Currently, the caching of linear solutions only happens when the total derivatives are computed during the run of a driver, so if you want to check to make sure it's happening during your optimization (in the run_driver call), change
derivs = p.compute_totals(of=['states'], wrt=['a'])
to
derivs = p.driver._compute_totals(of=['states'], wrt=['a'], global_names=False)
When I do that with your code, I get the following output:
[-0.26794919 -4. ]
incoming initial guess [0. 0.]
[[-0.02072594]
[ 4. ]]
incoming initial guess [-0.02072594 4. ]
[[-0.02072594]
[ 4. ]]
Note that the global_names=False arg is only needed if you use promoted names for your of and wrt variables.
I will update our example code to reflect the correct way to do this.

Python Optimization - Unable to meet multiple constrains

I am trying to minimize the weight as close to average as possible and meet both constrain of w>0 and Aw=b. However, with help, I was able to meet the second constrain (Aw=b) almost 100% but my w still return negative and at the same time not as close to average. As you can see the result below returns two large negative number (-39.99771255,-2.9709434) and one large position number (43.82670431) that are out of bound, which defeat the purpose of the exercise to minimize the weight. I even tried to divide my data set to randomly different groups as well but no optimized solution.
Please let me know if there are any math or better python suggestions as well as any methodology that could help lead to the most optimized solution. I am expecting the number to be as close as 0.2. Any numerical suggestion and advise are very welcome.
Question: Find the minimized weight that are close to average and at
the same time meet the target as close as possible and weight must be larger
than 0
My math right now is
**min⁡(w-mean(w))**
**s.t.** Aw-b=0, w>=0
**bound** 0.2'<'w<0.5
Data:
variable1 variable2 variable3 weight
1.49E+03 9.65E+07 2.27E+08 w1
1.52E+03 1.02E+08 2.20E+08 w2
1.54E+03 1.11E+08 2.23E+08 w3
1.49E+03 9.73E+07 2.18E+08 w4
1.60E+03 1.05E+08 2.38E+08 w5
1.57E+03 1.01E+08 2.25E+08 w6
1.59E+03 1.06E+08 2.30E+08 w7
1.49E+03 9.15E+07 2.20E+08 w8
1.54E+03 1.02E+08 2.20E+08 w9
1.54E+03 1.01E+08 2.28E+08 w10
1.57E+03 1.08E+08 2.25E+08 w11
1.54E+03 1.00E+08 2.25E+08 w12
1.57E+03 9.97E+07 2.26E+08 w13
1.49E+03 9.64E+07 2.13E+08 w14
1.53E+03 1.05E+08 2.36E+08 w15
1.53E+03 1.09E+08 2.23E+08 w16
1.55E+03 1.00E+08 2.45E+08 w17
1.52E+03 1.07E+08 2.17E+08 w18
1.50E+03 9.62E+07 2.07E+08 w19
1.57E+03 9.91E+07 2.32E+08 w20
Target
8531 429386951 1079115532
Current Result:
('x: ', array([ 0.28601612, 0.28601614, 43.82670431, 0.28601614, 0.28601613, 0.28601614, 0.28601614, -2.9709434 ,
0.28601614, 0.28601613, 0.28601615, 0.28601613, 0.28601613, 0.28601614, 0.28601614, 0.28601618,
-39.99771255, 0.28601618, 0.28601614, 0.28601612]))
Python Code:
# -*- coding: utf-8 -*-
"""
Created on Wed Nov 9 13:15:49 2017
#author: zkmkq7a
"""
import numpy as np
import scipy.optimize as spo
#from __future__ import print_function
import csv
import os
import sys
import operator
import itertools
import random
import numpy as np
from array import array
import matplotlib.pyplot as plt
from scipy.optimize import nnls, minimize
from scipy.sparse import coo_matrix
import pandas as pd
from sklearn.utils import shuffle
import networkx as nx
np.set_printoptions(linewidth=120)
np.random.seed(1)
""" Test Solver with random data """
#M, N = 2, 3
#A = np.random.random(size=(M,N))
#x_hidden = np.random.random(size=N)
#b = A.dot(x_hidden) # target
#n = N
#
#print('Original A')
#print(A)
#print('hidden x: ', x_hidden)
#print('target: ', b)
A = np.array(
[
[1486,1522,1536,1485,1598,1570,1593,1491,1540,1544,1566,1544,1573,1490,1530,1526,1546,1518,1498,1567],
[96454395,101615856,110933285,97323661,104973593,101499747,106069432,91496414,101843454,101040852,107795438,100260356,99722283,96419402,104875509,108908675,100158114,107298576,96209051,99065264],
[226553304,219597259,223410668,217613414,237752337,225150384,230103384,219982453,219726185,227791091,225452565,225279979,225682678,213304290,236148563,223027694,244961198,216856884,207345788,231758040]
]
)
b = np.array([8531., 1079115532., 429386951.])
n = 20
""" Optimize as LP """
def solve(A, b, n):
print('Reformulation')
am, an = A.shape
# Introduce aux-vars
# 1: y = mean
# n: z = x - mean
# n: abs(z)
n_plus_aux_vars = 3*n + 1
# Equality constraint: y = mean
eq_mean_A = np.zeros(n_plus_aux_vars)
eq_mean_A[:n] = 1. / n
eq_mean_A[n] = -1.
eq_mean_b = np.array([0])
print('y = mean A:')
print(eq_mean_A)
print('y = mean b:')
print(eq_mean_b)
# Equality constraints: Ax = b
eq_A = np.zeros((am, n_plus_aux_vars))
eq_A[:, :n] = A[:, :n]
eq_b = np.copy(b)
print('Ax=b A:')
print(eq_A)
print('Ax=b b:')
print(eq_b)
# Equality constraints: z = x - mean
eq_mean_A_z = np.hstack([-np.eye(n), np.ones((n, 1)), + np.eye(n), np.zeros((n, n))])
eq_mean_b_z = np.zeros(n)
print('z = x - mean A:')
print(eq_mean_A_z)
print('z = x - mean b:')
print(eq_mean_b_z)
# Inequality constraints: absolute values -> x <= x' ; -x <= x'
ineq_abs_0_A = np.hstack([np.zeros((n, n)), np.zeros((n, 1)), np.eye(n), -np.eye(n)])
ineq_abs_0_b = np.zeros(n)
ineq_abs_1_A = np.hstack([np.zeros((n, n)), np.zeros((n, 1)), -np.eye(n), -np.eye(n)])
ineq_abs_1_b = np.zeros(n)
# Bounds
# REMARK: Do not touch anything besides the first bounds-row!
bounds = [(-50., 50.) for i in range(n)] + \
[(None, None)] + \
[(None, None) for i in range(n)] + \
[(0, None) for i in range(n)]
# Objective
c = np.zeros(n_plus_aux_vars)
c[-n:] = 1
A_eq = np.vstack((eq_mean_A, eq_A, eq_mean_A_z))
b_eq = np.hstack([eq_mean_b, eq_b, eq_mean_b_z])
A_ineq = np.vstack((ineq_abs_0_A, ineq_abs_1_A))
b_ineq = np.hstack([ineq_abs_0_b, ineq_abs_1_b])
print('solve...')
result = spo.linprog(c, A_ineq, b_ineq, A_eq, b_eq, bounds=bounds, method='interior-point')
print(result)
x = result.x[:n]
print('x: ', x)
print('residual Ax-b: ', A.dot(x) - b)
print('residual Ax-b %: ', np.divide(A.dot(x)-b,b))
print('mean: ', result.x[n])
print('x - mean: ', x - result.x[n])
print('l1-norm(x - mean) / objective: ', np.linalg.norm(x - result.x[n], 1))
solve(A, b, n)

Recursive function (Chapman-Kolmogorov eq.) for Transition Probabilities

I'm stuck with building a recursive function which is best illustrated through a quick example.
Take a Markov process with 2 states, State 1 and State 2. The notation p_ij represents the probability of transitioning to state j given that the current state is i. In this example,
p_11 = 0.8 (probability of staying in State 1 given current state is State 1)
p_12 = 0.2
p_21 = 0.6
p_22 = 0.4
And the transition probability matrix is:
import numpy as np
pij = np.array([[.8, .2], [.6, .4]])
print(pij)
# [[ 0.8 0.2]
# [ 0.6 0.4]]
The n-step transition probability, denoted r_ij(n), represents the probability that the state after n time periods will be j, given that the current state is i. r_ij(n) can be found using the Chapman-Kolmogorov equation,
with the initial condition
m is the total number of states. [From Bertsekas/Tsitsiklis, 2008.]
I'm trying to build r_ij(n). The first 5 steps should look like this:
My start:
def r(p, n):
m = np.sqrt(p.size) # or p.shape[0]
if n == 1:
return p
elif n > 1:
res = []
for k in range(m):
for i in p:
for j in i:
# This line is patently wrong...
# Not sure how to reference i
return r(n - 1) * p[k, j]
return np.sum(res)
p0 = np.array([[.8, .2], [.6, .4]])
print(r(p0, n=5))
# [[.7501, .2499],
# [.7498, .2502]]
But I am a bit lost with the notation.
You don't necessarily need a recursive function for this. matrix_power is essentially rij you are looking for:
def rij(pij, n):
return matrix_power(pij, n)
pij = np.array([[.8, .2], [.6, .4]])
from numpy.linalg.linalg import matrix_power
matrix_power(pij, 2)
#array([[ 0.76, 0.24],
# [ 0.72, 0.28]])
matrix_power(pij, 3)
#array([[ 0.752, 0.248],
# [ 0.744, 0.256]])
matrix_power(pij, 4)
#array([[ 0.7504, 0.2496],
# [ 0.7488, 0.2512]])
matrix_power(pij, 5)
#array([[ 0.75008, 0.24992],
# [ 0.74976, 0.25024]])
To define a recursive function, np.dot will make the task easier:
def rij(pij, n):
if n == 1:
return pij
else:
return np.dot(rij(pij, n-1), pij)
rij(pij, 5)
#array([[ 0.75008, 0.24992],
# [ 0.74976, 0.25024]])

PyMC3 Multinomial Model doesn't work with non-integer observe data

I'm trying to use PyMC3 to solve a fairly simple multinomial distribution. It works perfectly if I have the 'noise' value set to 0.0. However when I change it to anything else, for example 0.01, I get an error in the find_MAP() function and it hangs if I don't use find_MAP().
Is there some reason that the multinomial has to be sparse?
import numpy as np
from pymc3 import *
import pymc3 as mc
import pandas as pd
print 'pymc3 version: ' + mc.__version__
sample_size = 10
number_of_experiments = 1
true_probs = [0.2, 0.1, 0.3, 0.4]
k = len(true_probs)
noise = 0.0
y = np.random.multinomial(n=number_of_experiments, pvals=true_probs, size=sample_size)+noise
y_denominator = np.sum(y,axis=1)
y = y/y_denominator[:,None]
with Model() as multinom_test:
probs = Dirichlet('probs', a = np.ones(k), shape = k)
for i in range(sample_size):
data = Multinomial('data_%d' % (i),
n = y[i].sum(),
p = probs,
observed = y[i])
with multinom_test:
start = find_MAP()
trace = sample(5000, Slice())
trace[probs].mean(0)
Error:
ValueError: Optimization error: max, logp or dlogp at max have non-
finite values. Some values may be outside of distribution support.
max: {'probs_stickbreaking_': array([ 0.00000000e+00, -4.47034834e-
08, 0.00000000e+00])} logp: array(-inf) dlogp: array([
0.00000000e+00, 2.98023221e-08, 0.00000000e+00])Check that 1) you
don't have hierarchical parameters, these will lead to points with
infinite density. 2) your distribution logp's are properly specified.
Specific issues:
This works for me
sample_size = 10
number_of_experiments = 100
true_probs = [0.2, 0.1, 0.3, 0.4]
k = len(true_probs)
noise = 0.01
y = np.random.multinomial(n=number_of_experiments, pvals=true_probs, size=sample_size)+noise
with pm.Model() as multinom_test:
a = pm.Dirichlet('a', a=np.ones(k))
for i in range(sample_size):
data_pred = pm.Multinomial('data_pred_%s'% i, n=number_of_experiments, p=a, observed=y[i])
trace = pm.sample(50000, pm.Metropolis())
#trace = pm.sample(1000) # also works with NUTS
pm.traceplot(trace[500:]);

Categories

Resources