How to implement this constraint in Python with Gurobi? - python-2.7

I have an expression given below and i was wondering if you can help me to formalize as an ILP constraint in order to solve by Gurobi optimizer (Python):
forall ( y in Y), forall (j in M), forall (x in X):
IF r[x][y] = 1 and c[y,j] = 1 THEN p[x,a] = 1 , forall (a in {U[j],...,W[j] - 1} )
Where:
r[x][y], c[y,j] and p[x,a] are 3 binary variables;
U[j] and W[j] are 2 positive integer variables, where U[j] + beta = W[j]
(beta is a positive constant)
I know that this constraint can be written as a logical implication in conjunctive normal form: x ∧ y → z
I have already tried this solution: z≥x+y−1 together with several other possibilities :(
But, i had an error with Gurobi solver
My Python code for this constraint is as follows:
for y in Y:
for j in M:
for x in X:
for a in range(int(U[j]),int(W[j])):
M1.addConstr(r[x][y] + c[y,j] - 1 <= p[x,a], 'TileRequirement_%s_%s_%s_%s'%(y,j,x,a))
I always get the error in this line: for a in range(int(U[j]),int(W[j])):, because both U[j] and W[j] are defined as positive integer variables
So, can someone help me ?
Thanks :)
Best regards
Khadija

You can't build constraints based on yet-to-optimize variables like in:
for a in range(int(U[j]),int(W[j])) # optimized value unknown # build-constr-time
Casting like that looks also dangerous and it solely depends on gurobipy, if that's possible in general (but not helping here).
Your question is hard to read and there is no information about the motivation for these constraints, but the general idea could be:
get rid of the range defined by U[j] and W[j]
formulate your constraint for the full-range
with one modification:
introduce one more activating-variable a:
(x^y)->z becomes: (a^x^y)->z == !a v !x v !y v z
as linear expression: (1-a) + (1-x) + (1-y) + z >= 1
now use the concept of indicator-variables to formulate your activating-variables
Yes, it's messy and because of this (and because information is sparse) i won't post a full solution.

# -*- coding: utf-8 -*-
#programmer: Khadija HS
#date: June 2017
#name: B-C-MCT PLNE Model (Khadija.HS,2017) <---> BCMCT1.py
"""
Solve the B-C-MCTP (fixed Z & min Delta) sub-pb of 3-PSDPP (K-HS et al.,2016), where:
X: list of input tiles (tile x)
Y: list of output tiles (tile y)
Ry: requirement relation between X & Y
<---> is a List of Y list, each sub List define the input tiles required by each y
<---> rxy: incidence matrix (0-1): Input Tiles/Output Tiles (Configuration of each output tile % input tile)
<---> Ry is a list of list where Row <--- x & Column <--- y
alpha: prefetches times (uniform)
beta: computations times (uniform)
Delta: the Total completion time (to be determined)
"""
from gurobipy import *
""" Find Yx: set of output tiles y that required the input tile x """
def OuputTileTe(Ry,X):
Yx=[]
for x in X:
Yx.append(OuputTileTex(Ry,x))
return Yx
""" Find B: List Ts for x """
def OuputTileTex(Ry,x):
B=[]
for y in range(len(Ry)):
if x in Ry[y]:
B.append(y)
return B
""" Find N: Max Value of N ( <---> sum(len(Ry),y in Y)) """
def NbPrefetchTile(S):
N=0
for k in range(0,len(S)):
N += len(S[k])
return N
""" BCMCT1 - Model"""
def BCMCT1(X,Y,Z,Ry,alpha,beta):
# DET VBLES: M,N,Z1,T,K,L
M=list(range(len(Y))) # List of Computation steps
nb=NbPrefetchTile(Ry) # Number of prefetches (Big Value of N)
N=range(nb) # List of Prefetches steps
ListZ=range(Z) # List of Buffers
T=range(alpha*len(X) + beta*len(Y)) # List of Start Date times (Computation+Prefetches)
K=range(alpha) # Interval Time of a prefetch step
L=range(beta) # Interval Time of a compute step
# DET VBLES: A,T1,B,Yx
A=alpha*nb + beta*len(Y) # Big Value of Total Completion Time
T1=range(A) # List of Start Date times (Computation+Prefetches)
minLen=min([len(elt) for elt in Ry]) #1,alpha+1
B=alpha*minLen + beta*len(Y) # Value of LB2
Yx=OuputTileTe(Ry,X) # List of output tile y, for x, x in X
# MODEL
M1=Model("BCMCT1")
# CONSTANT VARIABLES
r=[[0]*len(Y) for i in range(len(X))]
for x in X:
for y in Y:
if x in Ry[Y.index(y)]:
r[x][y]=1
# DECISION VARIABLES
c,p,q,U,W,a={},{},{},{},{},{}
for y in Y:
for j in M:
c[y,j]=M1.addVar(vtype=GRB.BINARY,name="c[%s,%s]"%(y,j)) #obj=beta,
for x in X:
for t in T:
p[x,t]=M1.addVar(vtype=GRB.BINARY,name="p[%s,%s]"%(x,t)) #obj=1,
for x in X:
for t in T:
q[x,t]=M1.addVar(vtype=GRB.BINARY,name="q[%s,%s]"%(x,t)) #obj=1,
for j in M:
U[j]=M1.addVar(vtype='I',name="U_%s"%j)
W[j]=M1.addVar(obj=1,vtype='I',name="W_%s"%j)
for j in M:
a[j]=M1.addVar(vtype=GRB.BINARY,name="a[%s]"%j)
# MODEL UPDATE
M1.update()
# OBJECTIVE
Obj=W[len(M)-1]
M1.setObjective(Obj, GRB.MINIMIZE)
# CONSTRAINTS
""" (1): Computation's Assignement Constraints """
""" (a) """
for j in M:
M1.addConstr(quicksum(c[y,j] for y in Y)==1,'ComputeAssign1_%s'%j)
""" (b) """
for y in Y:
M1.addConstr(quicksum(c[y,j] for j in M)==1,'ComputeAssign2_%s'%y)
""" (2): Buffer's Constraints """
for t in T:
M1.addConstr(quicksum(p[x,t] for x in X) <= Z,'BufferNb_%s'%t)
""" 3): Computation/Prefetch's Constraints """
""" (a) """
for t in T:
M1.addConstr(quicksum(q[x,t] for x in X) <= 1,'PrefetchTileA_%s'%t)
""" (b) """
for x in X:
for t in T[1:]:
for k in K:
M1.addConstr(p[x,t] - p[x,t-1] <= q[x,t-k],'PrefetchTileB_%s_%s_%s'%(x,t,k))
""" (c) """
for y in Y:
for j in M:
for x in X:
for t in T:
M1.addConstr(3 - r[x][y] - c[y,j] - a[j] + p[x,t] >= 1, 'TileRequirement_%s_%s_%s_%s'%(y,j,x,t))
""" (5): Computation Time's Constraint """
""" (a) """
for j in M:
M1.addConstr(W[j] == U[j] + beta,'ComputeTime1_%s'%j)
""" (b) """
for j in M[1:]:
M1.addConstr(W[j-1] <= U[j],'ComputeTime2_%s'%j)
# SOLUTION
M1.__data=c,p,q,U,W,a
return M1
Please find attached my detailed ILP
May be, it will be easier to understand my question about constraint number 17
where,
L = range(beta)
K=range(alpha)
\Lambda (Big M)=alpha*Z*Y+beta*Y
r[x][y]= 1 if x in Ry and 0 otherwise (forall x in X & forall y in Y) : incidence matrix given as input data
I will give you an example that is very simple to understand more my problem as follows:
let:
X=[X1,X2,X3,X4]
Y=[Y1,Y2,Y3]
Ry=[(X1,X2,X3), (X2,X4),(X1,X3,X4)]
Z=3
alpha=2, beta=4
The objective is to find a computation sequence for computing Y1,Y2 & Y3 in order to minimize Delta (total completion time)
An optimal solution is: Y2, Y3, Y1 (or Y2,Y1,Y3) with \Delta=17
ILP Formulation

Related

Implementation of Karger's Algorithm in Python Taking too Long

Wondering if you can help me understand where the critical flaw may be with my attempt at implementing Karger's algorithm in python. My program appears to take far too long to run and my computer starts to overwork running large sets of vertices. The purpose of the program is to output the minimum cut of the graph.
from random import choice
from statistics import mode
import math
fhand = open("mincuts.txt", "r")
vertices = fhand.readlines()
d = {}
for index,line in enumerate(vertices):
d["{0}".format(index+1)] = line.split()
def randy(graph, x):
y = str(choice(list(graph)))
if x == y:
y = randy(graph, x)
return y
count = 0
def contract(graph):
global count
if len(graph) == 2:
a = list(graph.keys())[0]
b = list(graph.keys())[1]
for i in range(1, len(graph[a])):
if graph[a][i] in graph[b]:
count = count + 1
#print(graph)
return
x = str(choice(list(graph)))
y = randy(graph, x)
#print(x)
#print(y)
graph[x] = graph[x] + graph[y]
graph.pop(y)
#remove self loops
for key in graph:
#method to remove duplicate entries in the arrays of the vertices. Source: www.w3schools.com
graph[key] = list(dict.fromkeys(graph[key]))
contract(graph)
N = len(d)
runs = int(N*N*(math.log(N)))
outcomes = []
for i in range(runs):
e = d.copy()
count = 0
contract(e)
outcomes.append(count)
print(outcomes)
#returns most common minimum cut value
print(mode(outcomes))
Below is a link to the graph I am running in mincuts.txt:
https://github.com/BigSoundCode/Misc-Algorithm-Implementations/blob/main/mincuts.txt

Find maximum and minimum of multivariable function in sympy

I have the following function:
f = x**2 + y**2
I would like to use sympy to find the maximum of and minimum value in the unit square [0,1] in x and [0,1] in y.
The expected outcome would be 0 for point [0,0] and 2 for point [1,1]
Can this be achieved?
I did something clunky, but appears to work [although not fast]:
def findMaxMin(f):
# find stationary points:
stationary_points = sym.solve([f.diff(x), f.diff(y)], [x, y], dict=True)
# Append boundary points
stationary_points.append({x:0, y:0})
stationary_points.append({x:1, y:0})
stationary_points.append({x:1, y:1})
stationary_points.append({x:0, y:1})
# store results after evaluation
results = []
# iteration counter
j = -1
for i in range(len(stationary_points)):
j = j+1
x1 = stationary_points[j].get(x)
y1 = stationary_points[j].get(y)
# If point is in the domain evalute and append it
if (0 <= x1 <= 1) and ( 0 <= y1 <= 1):
tmp = f.subs({x:x1, y:y1})
results.append(tmp)
else:
# else remove the point
stationary_points.pop(j)
j = j-1
# Variables to store info
returnMax = []
returnMin = []
# Get the maximum value
maximum = max(results)
# Get the position of all the maximum values
maxpos = [i for i,j in enumerate(results) if j==maximum]
# Append only unique points
append = False
for item in maxpos:
for i in returnMax:
if (stationary_points[item] in i.values()):
append = True
if (not(append)):
returnMax.append({maximum: stationary_points[item]})
# Get the minimum value
minimum = min(results)
# Get the position of all the minimum values
minpos = [i for i,j in enumerate(results) if j==minimum ]
# Append only unique points
append = False
for item in minpos:
for i in returnMin:
if (stationary_points[item] in i.values()):
append = True
if (not(append)):
returnMin.append({minimum: stationary_points[item]})
return [returnMax, returnMin]

Netwon's method without pre-built functions of Python: Calculation of gradient and Hessian

I am trying to write the basic Newton's method without pre-built solvers.
This is the function:
## definition of variables
x_1, x_2 = sym.symbols("x_1 x_2")
a_T=np.array([[0.3],[0.6],[0.2]])
b_T=np.array([5,26,3])
c_T=np.array([40,1,10])
u= x_1-0.8
v= x_2-(a_T[0]+a_T[1]*u**2*(1-u)**(1/2)-a_T[2]*u)
alpha= -b_T[0]+(b_T[1]*u**2)*(1+u)**(1/2)+(b_T[2])*u
beta= c_T[0]*v**2*(1-c_T[1]*v)/(1+c_T[2]*u**2)
## function
f = alpha**(-beta)
I calculated the gradient and the Hessian and defined the other parameters:
## gradient
gradient_cal = sym.Matrix(1,2,sym.derive_by_array(f, (x_1, x_2)))
## hessian
hessian_cal = sym.Matrix(2, 2, sym.derive_by_array(gradient_cal, (x_1, x_2)))
# initial guess
x_A= Matrix([[1],[0.5]])
xk = x_A
#tolerance
epsilon= 1e-10
#maximum iterations
max_iter=100
And the function itself:
def newton(gradient_cal,hessian_cal,xk,epsilon,max_iter):
for k in range(0,max_iter):
fxk = gradient_cal.evalf(subs={x_1:xk[0], x_2:xk[1]})
if fxk.norm() < epsilon:
print('Found solution after',k,'iterations.')
return xk
Dfxk = hessian_cal.evalf(subs={x_1: xk[0], x_2: xk[1]})
if Dfxk == 0:
print('Zero derivative. No solution found.')
return None
A=hessian_cal.evalf(subs={x_1: xk[0], x_2: xk[1]})
B=gradient_cal.evalf(subs={x_1: xk[0], x_2: xk[1]})
pk= (A.inv().dot(B))
xk = np.subtract(xk, pk)
print('Exceeded maximum iterations. No solution found.')
return None
approx = newton(gradient_cal,hessian_cal,x_A,epsilon,max_iter)
print(approx)
The following error shows up:
TypeError: Shape should contain integers only.
I checked it and saw that the Hessian contains "I" values. Therefore I am not sure if the calculations of the gradient and the Hessian are correct.
Does anyone have a better solution to calculate the gradient and the Hessian for such a complex function?
The jacobian-batteries are already included in SymPy:
>>> from sympy.abc import x, y
>>> f = x/y + x*y**2
>>> Matrix([f]).jacobian((x,y))
Matrix([[y**2 + 1/y, 2*x*y - x/y**2]])
>>> _.jacobian((x,y)) # Hessian
Matrix([
[ 0, 2*y - 1/y**2],
[2*y - 1/y**2, 2*x + 2*x/y**3]])
So you could try
x_1, x_2 = sym.symbols("x_1 x_2")
xx = x_1, x_2
a_T=[0.3,0.6,0.2]
b_T=[5,26,3]
c_T=[40,1,10]
u= x_1-0.8
v= x_2-(a_T[0]+a_T[1]*u**2*(1-u)**(1/2)-a_T[2]*u)
alpha= -b_T[0]+(b_T[1]*u**2)*(1+u)**(1/2)+(b_T[2])*u
beta= c_T[0]*v**2*(1-c_T[1]*v)/(1+c_T[2]*u**2)
## function
f = alpha**(-beta)
jac = Matrix([f]).jacobian(xx)
hes = jac.jacobian(xx)

Working with coordinates/arrays

I have a text file with coordinates
x1 y1 z1
x2 y2 z2
Now I want to know at which y-coordinate the value of x exceeds a specific point. How do I do that?
As a first step I tried using a function with lists:
def coordinates(dataset):
x = np.array(0)
y = np.array(0)
z = np.array(0)
dataset = open(dataset,'r')
dataset = line.strip()
dataset = line.split()
i=0
while i<10:
x = np.append(x,float(line[0]))
y = np.append(y,float(line[1]))
z = np.append(y,float(line[2]))
i+=1
print x
return x,y
(I used print x to check the results at the terminal)
When using the function it seems line.split() only uses the last line and splits it. So the result at the terminal is [0 x10 x10 x10 x10 x10 x10 ...].
Does anyone know how to fix it? Or is there any other/better solution?
Use np.loadtxt function. After you have all your coordinates in three arrays
from io import StringIO
import numpy as np
### simulates your input file
c = StringIO("0 1 2 \n 3 4 5 \n 6 7 8")
d=np.loadtxt(c) # file readout into a 2D array
x=d[:,0] # gets x coordinate array
y=d[:,1]
z=d[:,2]
print (x)
print (y)
print (z)
###
xQ = 3.5 # your "exceed" coordinate
print (y[x>xQ][0]) # returns the first y value where x>xQ
The last line uses that [x>xQ] is in fact a boolean mask array that we can apply onto other coordinates, y in your case.

Categorical Mixture Model in Pymc3

I'm new to Pymc3 and I'm trying to create the Categorical Mixture Model shown in https://en.wikipedia.org/wiki/Mixture_model#Categorical_mixture_model . I'm having difficulty hooking up the 'x' variable. I think it's because I have to make the z variable Deterministic, but I'm getting an error message at the line where 'x' is assigned : "ValueError: We expected 3 inputs but got 2.". It looks like the p function only accepts 2 inputs so I'm stuck. I've tried a bunch of different things, but haven't been able to get this to work yet.
import numpy as np
from pymc3 import *
import theano.tensor as t
K = 3 #NUMBER OF TOPICS
V = 20 #NUMBER OF WORDS
N = 15 #NUMBER OF DOCUMENTS
#GENERAETE RANDOM CATEGORICAL MIXTURES
data = np.ones([N,V])
#theano.compile.ops.as_op(itypes=[t.lscalar, t.dscalar, t.dscalar],otypes=[t.dvector])
def p(z=z, phi=phi):
return [phi[z[i,j]] for i in range(D) for j in range(W)]
model = Model()
with model:
alpha = np.ones(V)
beta = np.ones(K)
theta = [Dirichlet('theta_%i' % i, alpha, shape=V) for i in range(K)]
phi = Dirichlet('phi', beta, shape=K)
z = [Categorical('z_%i' % i, p = phi, shape=V) for i in range(N)]
x = [Categorical('x_%i_%i' % (i,j), p=p(z[i][j],phi), observed=data[i,j]) for i in range(N) for j in range(V)]
#x = [Categorical('x_%i_%i' % (i,j), p=theta[z[i][j]], observed=data[i,j]) for i in range(N) for j in range(V)]
print "Created model. Now begin sampling"
step = Slice()
trace = sample(n, step)
trace.get_values('phi')
For starters, in your example above, z and phi have no value which would allow them to be used as default values. We also don't have values for D and W.
As for the number of arguments, the function you define has 2 but your theano decorator above it has 3. I'd suggest
#theano.compile.ops.as_op(itypes=[t.lscalar, t.dvector],otypes=[t.dvector])
def p(z, phi):
return [phi[z[i,j]] for i,j in zip(range(D),range(W))]