How to handle absolute value in Gurobi constraints - gurobi

I want to handle absolute value in Gurobi constraints. This is my code abc.lp. However I am not getting solution.
Maximize
v0 + v1 + v2
SubjeCt To
C1: 3 v0 + v1 + v2 <= 72
C2: 2 v0 + 3 v1 + 2 v2 <= 80
C3: abs_(v0 - v1) + abs_(v1 - v2) >= 10
Integers
v0 v1 v2
End

The abs_ function is part of the Gurobi Python API and does not work in an LP file. (When your LP file is read, the solver interprets your C3 constraint as a linear constraint with four variables with names abs_(v0, v1), abs_(v1, and v2).)
Also, note that absolute value constraints can only take the form var1 = abs_(var2). So you will have to define some auxiliary variables to model the constraint above.
In the Python API, you could model the constraint C3 as follows:
a = model.addVars(4, name="a") # auxiliary variables
model.addConstr(a[0] == v0 - v1)
model.addConstr(a[1] == v1 - v2)
model.addConstr(a[2] == abs_(a[0]))
model.addConstr(a[3] == abs_(a[1]))
model.addConstr(a[2] + a[3] >= 10)
In the LP file, you can see the absolute value constraint in the General Constraints section:
General Constraints
GC0: a[2] = ABS ( a[0] )
GC1: a[3] = ABS ( a[1] )

Related

Inequality constraints of convex relaxation with McCormick envelope

I have a nonconvex optimization problem for which I am calculating a lower bound using the McCormick envelope. Each bilinear term is replaced with an auxiliary variable which has the following constraints defined:
w_{ij} >= x_i^L * x_j + x_i * x_j^L - x_i^L * x_j^L
w_{ij} >= x_i^U * x_j + x_i * x_j^U - x_i^U * x_j^U
w_{ij} <= x_i^U * x_j + x_i * x_j^L - x_i^U * x_j^L
w_{ij} <= x_i^L * x_j + x_i * x_j^U - x_i^L * x_j^U
where
x_U <= x <= x_L
I am given a function taking in several arguments:
def convex_bounds(n,m,c,H,Q,A,b,lb,ub):
# n is the number of optimization variables
# m is the number of eq constraints
# H = positive, semidefinite matrix from objetcive function (n x n)
# Q is (mxn) x n
# A is m x n
# b is RHS of non linear eq constraints (m x 1)
# c,lb,ub are vectors size (n x 1)
......................................
# Create matrix B & b_ineq for inequality constraints
# where B*x <= b_ineq
B = np.eye(3)
b_ineq = np.array((10,10,10))
## these values would work in a scenario with no bilinear terms
My problem is that I don't know how to specify the inequality constraints matrix B and vector b_ineq. For this particular exercise my variables are x1, x2 and x3 with bounds 0 (x_L) and 10 (x_U). My bilinear terms are x_12 and x_23 (which will lead to auxiliary variables w_12 and w_23). How can I specify the known bounds (0 and 10) for x1,x2 and x3 and the calculated ones (as in the theory pasted above) in B and b_ineq?
I don't actually know how to proceed with this.

Numerically stable calculation of invariant mass in particle physics?

In particle physics, we have to compute the invariant mass a lot, which is for a two-body decay
When the momenta (p1, p2) are sometimes very large (up to a factor 1000 or more) compared to the masses (m1, m2). In that case, there is large cancellation happening between the last two terms when the calculation is carried out with floating point numbers on a computer.
What kind of numerical tricks can be used to compute this accurately for any inputs?
The question is about suitable numerical tricks to improve the accuracy of the calculation with floating point numbers, so the solution should be language-agnostic. For demonstration purposes, implementations in Python are preferred. Solutions which reformulate the problem and increase the amount of elementary operations are acceptable, but solutions which suggest to use other number types like decimal or multi-precision floating point numbers are not.
Note: The original question presented a simplified 1D dimensional problem in form of a Python expression, but the question is for the general case where the momenta are given in 3D dimensions. The question was reformulated in this way.
With a few tricks listed on Stackoverflow and the transformation described by Jakob Stark in his answer, it is possible to rewrite the equation into a form that does not suffer anymore from catastrophic cancellation.
The original question asked for a solution in 1D, which has a simple solution, but in practice, we need the formula in 3D and then the solution is more complicated. See this notebook for a full derivation.
Example implementation of numerically stable calculation in 3D in Python:
import numpy as np
# numerically stable implementation
#np.vectorize
def msq2(px1, py1, pz1, px2, py2, pz2, m1, m2):
p1_sq = px1 ** 2 + py1 ** 2 + pz1 ** 2
p2_sq = px2 ** 2 + py2 ** 2 + pz2 ** 2
m1_sq = m1 ** 2
m2_sq = m2 ** 2
x1 = m1_sq / p1_sq
x2 = m2_sq / p2_sq
x = x1 + x2 + x1 * x2
a = angle(px1, py1, pz1, px2, py2, pz2)
cos_a = np.cos(a)
if cos_a >= 0:
y1 = (x + np.sin(a) ** 2) / (np.sqrt(x + 1) + cos_a)
else:
y1 = -cos_a + np.sqrt(x + 1)
y2 = 2 * np.sqrt(p1_sq * p2_sq)
return m1_sq + m2_sq + y1 * y2
# numerically stable calculation of angle
def angle(x1, y1, z1, x2, y2, z2):
# cross product
cx = y1 * z2 - y2 * z1
cy = x1 * z2 - x2 * z1
cz = x1 * y2 - x2 * y1
# norm of cross product
c = np.sqrt(cx * cx + cy * cy + cz * cz)
# dot product
d = x1 * x2 + y1 * y2 + z1 * z2
return np.arctan2(c, d)
The numerically stable implementation can never produce a negative result, which is a commonly occurring problem with naive implementations, even in double precision.
Let's compare the numerically stable function with a naive implementation.
# naive implementation
def msq1(px1, py1, pz1, px2, py2, pz2, m1, m2):
p1_sq = px1 ** 2 + py1 ** 2 + pz1 ** 2
p2_sq = px2 ** 2 + py2 ** 2 + pz2 ** 2
m1_sq = m1 ** 2
m2_sq = m2 ** 2
# energies of particles 1 and 2
e1 = np.sqrt(p1_sq + m1_sq)
e2 = np.sqrt(p2_sq + m2_sq)
# dangerous cancelation in third term
return m1_sq + m2_sq + 2 * (e1 * e2 - (px1 * px2 + py1 * py2 + pz1 * pz2))
For the following image, the momenta p1 and p2 are randomly picked from 1 to 1e5, the values m1 and m2 are randomly picked from 1e-5 to 1e5. All implementations get the input values in single precision. The reference in both cases is calculated with mpmath using the naive formula with 100 decimal places.
The naive implementation loses all accuracy for some inputs, while the numerically stable implementation does not.
If you put e.g. m1 = 1e-4, m2 = 1e-4, p1 = 1 and p2 = 1 in the expression, you get about 4e-8 with double precision but 0.0 with single precision calculation. I assume, that your question is about how one can get the 4e-8 as well with single precision calculation.
What you can do is a taylor expansion (around m1 = 0 and m2 = 0) of the expression above.
e ~ e|(m1=0,m2=0) + de/dm1|(m1=0,m2=0) * m1 + de/dm2|(m1=0,m2=0) * m2 + ...
If I calculated correctly, the zeroth and first order terms are 0 and the second order expansion would be
e ~ (p1+p2)/p1 * m1**2 + (p1+p2)/p2 * m2**2
This yields exactly 4e-8 even with single precision calculation. You can of course do more terms in the expansion if you need, until you hit the precision limit of a single float.
Edit
If the mi are not always much smaller than the pi you could further massage the equation to get
The complicated part is now the one in the square brackets. It essentially is sqrt(x+1)-1 for a wide range of x values. If x is very small, we can use the taylor expansion of the square root (e.g. like here). If the x value is larger, the formula works just fine, because the addition and subtraction of 1 are no longer discarding the value of x due to floating point precision. So one threshold for x must be choosen below one switches to the taylor expansion.

GLPK - Minimize a variable value

I'm working in virtual network embedding, and I'm creating a model with glpk to embed the networks.
I have this following objective function:
minimize cost: sum{(i,j) in VEdges} sum{u in SNodes, v in SNodes} weight[u,v] * fw[i,j,u,v] * secSupEdge[u,v] + sum{u in SNodes, v in SNodes} r[u,v] * secSupEdge[u,v];
Then I have the following two restrictions (among others)
s.t. relConst2{(i,j) in VEdges, u in AllNodes, v in AllNodes}: bwDem[i,j] * phiw[i,j,u,v] >= fw[i,j,u,v];
s.t. linkSecConst0{(i,j) in VEdges, u in SNodes, v in SNodes}: phiw[i,j,u,v] * secDemEdge[i,j] <= secSupEdge[u,v];
"phiw" is a binary variable
"fw" and "r" are variables that take any value >= 0
all the others ("weight", "bwDem", "secDemEdges", "secSupEdge") are just params
I want to relate phiw with fw. When fw > 0, phiw should take the value 1. When fw == 0, phiw should take the value 0.
Normally it does what I want, but sometimes phiw takes the value 1 when fw has the value 0, which is not what I want. This happens because the restrictions are met:
Example 1:
s.t. relConst2: 4 * 1 >= 0
s.t. linkSecConst0: 1 * 2 <= 2
Is there a way to minimize the value of phiw variable but not putting it in the objective function? Or putting it in the objective function but not changing the value of the result neither the value of all other variables?
The question is about minimizing phiw, however, the description of the problem suggests that what you want to do is link the values of phiw and fw, and specifically to have phiw = 1 when fw > 0, and phiw = 0 otherwise (i.e., fw = 0).
I would suggest that you add constraint that directly maps the conditional on fw to the value of phiw, such as:
s.t. LinkConstraint { (i,j) in VEdges, u in AllNodes, v in AllNodes }:
if fw[i,j,u,v] > 0 then 1 else 0 = phiw[i,j,u,v] ;

AMPL double conditions in constraints

I'm working on an optimization project and I'm using AMPL with CPLEX for this.
My problem is somehow simple but I couldn't do it without using some additional "useless" variables.
So assume I have the following code:
set A:= a b c;
set B:= 1 2 3;
var x{A,B} binary;
now I want a constraint to be processed under 2 conditions, for example:
if x[a,1] = 1 and x[a,2] = 1 then (some constraint).
Unfortunately, CPLEX won't let me use the syntax:
s.t const: x[a,1] = 1 and x[a,2] = 1 ==> (some constraint)
it says "logical constraint _slogcon[1] is not an indicator constraint.
Now the way I did it was by introducing a new variable.
var dummyVar{A,A,B,B} binary;
this variable is equal to 1 if both x[a,1] = 1 and x[a,2] = 1.
subject to condition: 2*dummyVar[a,a,1,2] <= x[a,1] + x[a,2]
My problem is with the large model I'm working with. In my case, this dummyVar is not simply a small set, it contains a set of sets. When AMPL is processing the code (translating it to be read by CPLEX), it crashes due to lack of memory.
Is there any simple way to write something like
s.t const: x[a,1] = 1 and x[a,2] = 1 ==> (some constraint)
without introducing any additional variables? Thanks in advance.
To model this effectively, you should consider two things
'some-constraint' is linear or quadratic.
if either x[a,1] or x[a,2] are 1, then the constraint can be violated.
On point 1, your some-constraint is of the form
l <= f(x) <= u
where f(x) is a quadratic of linear function and l and u are constraints. If you let f_max and f_min be the upper and lower bounds of the function f(x) over all feasible values of x then you can write your conditional constraint as
l - (l - f_min) (x[a,1] + x[a,2]) <= f(x) <= u + (f_max - u)(x[a,1] + x[a,2])
If either x[a,1] or x[a,2] are 1 then the constraint becomes
f_min <= f(x) <= f_max
or looser if both x[a,1] and x[a,2] are both 1. If both are 0, then the original constraint is enforced.

k consecutive integers constraint

How can I state the following constraint in Constraint Programming? (Preferably in Gurobi or Comet).
S is an array of integers of size n. The set of integers that I can use to fill the array are in the range 1-k. There is a constraint ci for each of the integers that can be used. ci denotes the minimum number of consecutive integers i.
For example if c1 = 3, c2 = 2 then 1112211112111 is not a valid sequence since there must be two consecutive 2's, whereas 1112211122111 is a valid sequence.
Perhaps using the regular constraint (automaton in Comet) would be the best approach.
However, here is a straightforward solution in MiniZinc which use a lot of reifications. It should be possible to translate it to Comet at least (I don't think Gurobi support reifications).
The decision variables (the sequences) are in the array "x". It also use a helper array ("starts") which contains the start positions of each sequences; this makes it easier to reason about the sequences in "x". The number of sequences is in "z" (e.g. for optimization problems).
Depending on the size of x and other constraints, one can probably add more (redundant) constraints on how many sequences there can be etc. This is not done here, though.
Here's the model: http://www.hakank.org/minizinc/k_consecutive_integers.mzn
It's also shown below.
int: n;
int: k;
% number of consecutive integers for each integer 1..k
array[1..k] of int: c;
% decision variables
array[1..n] of var 1..k: x;
% starts[i] = 1 -> x[i] starts a new sequence
% starts[i] = 0 -> x[i] is in a sequence
array[1..n] of var 0..k: starts;
% sum of sequences
var 1..n: z = sum([bool2int(starts[i] > 0) | i in 1..n]);
solve :: int_search(x, first_fail, indomain_min, complete) satisfy;
constraint
forall(a in 1..n, b in 1..k) (
(starts[a] = b ) ->
(
forall(d in 0..c[b]-1) (x[a+d] = b )
/\
forall(d in 1..c[b]-1) (starts[a+d] = 0 )
/\
(if a > 1 then x[a-1] != b else true endif) % before
/\
(if a <= n-c[b] then x[a+c[b]] != b else true endif) % after
)
)
/\
% more on starts
starts[1] > 0 /\
forall(i in 2..n) (
starts[i] > 0 <-> ( x[i]!=x[i-1] )
)
/\
forall(i in 1..n) (
starts[i] > 0 -> x[i] = starts[i]
)
;
output [
"z : " ++ show(z) ++ "\n" ++
"starts: " ++ show(starts) ++ "\n" ++
"x : " ++ show(x) ++ "\n"
];
%
% data
%
%% From the question above:
%% It's a unique solution.
n = 13;
k = 2;
c = [3,2];