I am trying to write the constraint related to multiple variables. However, it shows error "Indicator constraints can only be triggered by a single binary variable at a given value". Can you help me fix this error? Thank you very much!
The code is following:
mdl.addConstrs((x[i,j,k] - t[i,j,k] == 1) >> (d2[j,k] == d2[i,k] - d[i,j]) for i, j, k in arcos2 if i != 0 and j != 0)
Where:
x[i,j,k], t[i,j,k] are binary variables
d2[j,k], d2[i,k] are continuous variables
d[i,j] is a parameter
I think the error message is pretty clear. Define binary helper variables q[i,j,k] to represent x[i,j,k] - t[i,j,k]. Then:
for i, j, k in arcos2:
if i != 0 and j != 0:
mdl.addConstr(q[i,j,k] == x[i,j,k] - t[i,j,k])
mdl.addConstr((q[i,j,k] == 1) >> (d2[j,k] == d2[i,k] - d[i,j]))
Related
I have a variable made of 961 elements. And I have a constraint like this: only 8 elements of the variable are nonzero, and the others are 0. I don't know how to express this constraint in cvxpy. I tried this:
import cvxpy as cp
K = cp.Variable(961, integer=Ture)
s = 0
constraint = [cp.sum([s+1 for t in K if t!=0])==8]
But I got the following error:
Exception: Cannot evaluate the truth value of a constraint or chain constraints, e.g., 1 >= x >= 0.
Let's look at this mathematically.
Problem: You have integer variables x[i] ∈ {0,1,2,...,N} and you want to allow only K of them to be nonzero.
We can do this by introducing a parallel binary variable b[i] ∈ {0,1} that indicates whether x[i] is pinned to zero. I use the convention:
b[i] = 0 => x[i] = 0
b[i] = 1 => x[i] ∈ {0,1,2,...,N}
This can be written simply as a set of constraints:
x[i] <= N*b[i]
sum(i,b[i]) = K
If you want to use the slightly different definition:
b[i] = 0 => x[i] = 0
b[i] = 1 => x[i] ∈ {1,2,...,N}
then we need:
x[i] <= N*b[i]
x[i] >= b[i]
sum(i,b[i]) = K
If the integer variables are: x[i] ∈ {-N,...,-2,-1,0,1,2,...,N} then we can do:
x[i] <= N*b[i]
x[i] >= -N*b[i]
sum(i,b[i]) = K
I assume that CVXPY generates the same thing when you say:
abs(x) <= N*b
sum(b) == K
(The condition abs(x[i]) >= b[i] is a little bit more messy to linearize in this case).
This should not be too difficult to transcribe into a CVXPY model. Note that we need this explicit upper bound N on x[i]. Make it not too large.
I've been struggling trying to find a way I can store a vector so I can use it later. Here's my code:
while cota > RTOL:
for i in range (0, n + 1):
if i == 0:
u[i] = T_b - T_inf
elif 0 < i < n:
u[i] = (u[i + 1] + u[i - 1])/y
else:
u[i] = 0
The vector "u" changes with each iteration as the resulting vector from an iteration is the input for the next, however, in order to define the cut-off for the loop I need to be able to access both the current and previous iteration (the cut-off happens once a certain tolerance is reached and that requires being able to compare the current iteration to the previous one). In order to do this I've tried writing it onto a text file, but I'm wondering if there's a more elegant solution that somehow allows me to avoid that.
I recommend you remove the conditional from the loop,
and invent a new vector v to store results.
while cota > RTOL:
v = {} # Or a numpy array? Unclear from your example.
v[0] = T_b - T_inf
v[n] = 0
for i in range(1, n):
v[i] = (u[i + 1] + u[i - 1]) / y
Then do something useful with v, not sure what your use case is.
Perhaps you want to copy it on top of u for subsequent processing.
By using two separate vectors
you won't have to worry about u[i - 1] giving
a value you munged just a moment ago
on the previous loop iteration.
mdl = Model('CVRP')
x = mdl.binary_var_dict(A, name='x')
u = mdl.continuous_var_dict(N, name='u')
mdl.minimize(mdl.sum(distanceList[i][j]*x[i, j] for i, j in A))
mdl.add_constraints(mdl.sum(x[i, j] for j in V if j != i) == 1 for i in N)
mdl.add_constraints(mdl.sum(x[i, j] for i in V if i != j) == 1 for j in N)
mdl.add_constraints(mdl.add(u[i] - u[j] + n*(x[i,j]) <= n - 1 for i in N for j in N if i!=j))
When I ran this code, I got this warning:
Warning: constraint has already been posted: 25x_25_24-u_24+u_25 <= 24, index is: 649
I think my model duplicates same constraints many times, but I cannot figure that why this is happening. It is related to the last constraint that provides subtour elimination.
I really appreciate that somebody helps me to get rid of duplication or a new subtour elimination constraint. Thanks.
Model.add(..) builds a constraint , add it to the model and returns it.
Thus when you call Model.add_constraints on the results of the various Model.add calls, you end adding constraints *which have already been added.
Removing the call to Model.add should do the trick:
mdl.add_constraints((u[i] - u[j] + n*(x[i,j]) <= n - 1) for i in N for j in N if i!=j)
How do I use z3 to count the number of solutions? For example, I want to prove that for any n, there are 2 solutions to the set of equations {x^2 == 1, y_1 == 1, ..., y_n == 1}. The following code shows satisfiability for a given n, which isn't quite what I want (I want number of solutions for an arbitrary n).
#!/usr/bin/env python
from z3 import *
# Add the equations { x_1^2 == 1, x_2 == 1, ... x_n == 1 } to s and return it.
def add_constraints(s, n):
assert n > 1
X = IntVector('x', n)
s.add(X[0]*X[0] == 1)
for i in xrange(1, n):
s.add(X[i] == 1)
return s
s = Solver()
add_constraints(s, 3)
s.check()
s.model()
If there are a finite number of solutions, you can use the disjunct of the constants (your x_i's) not equal to their assigned model values to enumerate all of them. If there are infinite solutions (which is the case if you want to prove this for all natural numbers n), you can use the same technique, but of course couldn't enumerate them all, but could use this to generate many solutions up to some bound you pick. If you want to prove this for all n > 1, you will need to use quantifiers. I've added a discussion of this below.
While you didn't quite ask this question, you should see this question/answer as well: Z3: finding all satisfying models
Here's your example doing this (z3py link here: http://rise4fun.com/Z3Py/643M ):
# Add the equations { x_1^2 == 1, x_2 == 1, ... x_n == 1 } to s and return it.
def add_constraints(s, n, model):
assert n > 1
X = IntVector('x', n)
s.add(X[0]*X[0] == 1)
for i in xrange(1, n):
s.add(X[i] == 1)
notAgain = []
i = 0
for val in model:
notAgain.append(X[i] != model[val])
i = i + 1
if len(notAgain) > 0:
s.add(Or(notAgain))
print Or(notAgain)
return s
for n in range(2,5):
s = Solver()
i = 0
add_constraints(s, n, [])
while s.check() == sat:
print s.model()
i = i + 1
add_constraints(s, n, s.model())
print i # solutions
If you want to prove there are no other solutions for any choice of n, you need to use quantifiers, since the previous approach will only work for finite n (and it gets very expensive quickly). Here is an encoding showing this proof. You could generalize this to incorporate the model generation capability in the previous part to come up with the +/- 1 solution for a more general formula. If the equation has a number of solutions independent of n (like in your example), this would allow you to prove equations have some finite number of solutions. If the number of solutions is a function of n, you'd have to figure that function out. z3py link: http://rise4fun.com/Z3Py/W9En
x = Function('x', IntSort(), IntSort())
s = Solver()
n = Int('n')
# theorem says that x(1)^2 == 1 and that x(1) != +/- 1, and forall n >= 2, x(n) == 1
# try removing the x(1) != +/- constraints
theorem = ForAll([n], And(Implies(n == 1, And(x(n) * x(n) == 1, x(n) != 1, x(n) != -1) ), Implies(n > 1, x(n) == 1)))
#s.add(Not(theorem))
s.add(theorem)
print s.check()
#print s.model() # unsat, no model available, no other solutions
I’m having a bit of trouble controlling the results from a data generating algorithm I am working on. Basically it takes values from a list and then lists all the different combinations to get to a specific sum. So far the code works fine(haven’t tested scaling it with many variables yet), but I need to allow for negative numbers to be include in the list.
The way I think I can solve this problem is to put a collar on the possible results as to prevent infinity results(if apples is 2 and oranges are -1 then for any sum, there will be an infinite solutions but if I say there is a limit of either then it cannot go on forever.)
So Here's super basic code that detects weights:
import math
data = [-2, 10,5,50,20,25,40]
target_sum = 100
max_percent = .8 #no value can exceed 80% of total(this is to prevent infinite solutions
for node in data:
max_value = abs(math.floor((target_sum * max_percent)/node))
print node, "'s max value is ", max_value
Here's the code that generates the results(first function generates a table if its possible and the second function composes the actual results. Details/pseudo code of the algo is here: Can brute force algorithms scale? ):
from collections import defaultdict
data = [-2, 10,5,50,20,25,40]
target_sum = 100
# T[x, i] is True if 'x' can be solved
# by a linear combination of data[:i+1]
T = defaultdict(bool) # all values are False by default
T[0, 0] = True # base case
for i, x in enumerate(data): # i is index, x is data[i]
for s in range(target_sum + 1): #set the range of one higher than sum to include sum itself
for c in range(s / x + 1):
if T[s - c * x, i]:
T[s, i+1] = True
coeff = [0]*len(data)
def RecursivelyListAllThatWork(k, sum): # Using last k variables, make sum
# /* Base case: If we've assigned all the variables correctly, list this
# * solution.
# */
if k == 0:
# print what we have so far
print(' + '.join("%2s*%s" % t for t in zip(coeff, data)))
return
x_k = data[k-1]
# /* Recursive step: Try all coefficients, but only if they work. */
for c in range(sum // x_k + 1):
if T[sum - c * x_k, k - 1]:
# mark the coefficient of x_k to be c
coeff[k-1] = c
RecursivelyListAllThatWork(k - 1, sum - c * x_k)
# unmark the coefficient of x_k
coeff[k-1] = 0
RecursivelyListAllThatWork(len(data), target_sum)
My problem is, I don't know where/how to integrate my limiting code to the main code inorder to restrict results and allow for negative numbers. When I add a negative number to the list, it displays it but does not include it in the output. I think this is due to it not being added to the table(first function) and I'm not sure how to have it added(and still keep the programs structure so I can scale it with more variables).
Thanks in advance and if anything is unclear please let me know.
edit: a bit unrelated(and if detracts from the question just ignore, but since your looking at the code already, is there a way I can utilize both cpus on my machine with this code? Right now when I run it, it only uses one cpu. I know the technical method of parallel computing in python but not sure how to logically parallelize this algo)
You can restrict results by changing both loops over c from
for c in range(s / x + 1):
to
max_value = int(abs((target_sum * max_percent)/x))
for c in range(max_value + 1):
This will ensure that any coefficient in the final answer will be an integer in the range 0 to max_value inclusive.
A simple way of adding negative values is to change the loop over s from
for s in range(target_sum + 1):
to
R=200 # Maximum size of any partial sum
for s in range(-R,R+1):
Note that if you do it this way then your solution will have an additional constraint.
The new constraint is that the absolute value of every partial weighted sum must be <=R.
(You can make R large to avoid this constraint reducing the number of solutions, but this will slow down execution.)
The complete code looks like:
from collections import defaultdict
data = [-2,10,5,50,20,25,40]
target_sum = 100
# T[x, i] is True if 'x' can be solved
# by a linear combination of data[:i+1]
T = defaultdict(bool) # all values are False by default
T[0, 0] = True # base case
R=200 # Maximum size of any partial sum
max_percent=0.8 # Maximum weight of any term
for i, x in enumerate(data): # i is index, x is data[i]
for s in range(-R,R+1): #set the range of one higher than sum to include sum itself
max_value = int(abs((target_sum * max_percent)/x))
for c in range(max_value + 1):
if T[s - c * x, i]:
T[s, i+1] = True
coeff = [0]*len(data)
def RecursivelyListAllThatWork(k, sum): # Using last k variables, make sum
# /* Base case: If we've assigned all the variables correctly, list this
# * solution.
# */
if k == 0:
# print what we have so far
print(' + '.join("%2s*%s" % t for t in zip(coeff, data)))
return
x_k = data[k-1]
# /* Recursive step: Try all coefficients, but only if they work. */
max_value = int(abs((target_sum * max_percent)/x_k))
for c in range(max_value + 1):
if T[sum - c * x_k, k - 1]:
# mark the coefficient of x_k to be c
coeff[k-1] = c
RecursivelyListAllThatWork(k - 1, sum - c * x_k)
# unmark the coefficient of x_k
coeff[k-1] = 0
RecursivelyListAllThatWork(len(data), target_sum)