Converting a simple conditional statement constraint into linear equation - if-statement

I am using PuLP method to optimize a problem. I have a simple conditional statement as:
If A = 0, x = 0
Else if A>0, x = 1
How can I change it into mathematical equation (or a list of equations) if I want to use it as a constraint in optimization using PuLP method?

0.001⋅x ≤ A ≤ 640⋅x
x ∈ {0,1}
For PuLP split this into two inequality constraints.

Related

Is it possible to model a logical OR without boolean variables in linear programming?

I want to state a linear model where I can't use boolean variables due to efficiency reasons. I can only use a solver that can handle boolean variables not that efficiently. And in a productive model I would need hundreds of those variables.
I use a boolean variable to decide if I can satisfy demand either from one source (continuous variable A) or another source (continuous variable B) but not both.
The constraint is:
A + B >= demand
But either A OR B can be non-zero.
This can be ensured by using a boolean variable (Bool_A) and the following constraints:
A <= 1000 * Bool_A
B <= 1000 * (1- Bool_A)
If Bool_A = 1, then the variable A can take non-zero values and B is forced to 0, and if Bool_A = 0 then vice versa.
My question is now: does anyone know, if it is possible to model this using only linear variables (no booleans and integer variables) or has a proof that it is not possible.
In Brown, G. and Dell, R., "Formulating linear and integer linear programs: A rogues’ gallery" the following linear programming formulation for the XOR (exclusive or) can be found :
X = A xor B
resolves to
X ≤ A + B
X ≥ A - B
X ≥ - A + B
X ≤ 2 - A - B
Using an auxiliary variable:
X = A + B - 2*H
H ≤ A
H ≤ B
H ≥ A + B - 1
H ≥ 0

How to solve an algebraic equation in formal power series?

Motivation. It is well known that generating function for Catalan numbers satisfies quadratic equation. I would like to have first several coefficients of a function, implicitly defined by an algebraic equation (not necessarily a quadratic one!).
Example.
import sympy as sp
sp.init_printing() # math as latex
from IPython.display import display
z = sp.Symbol('z')
F = sp.Function('F')(z)
equation = 1 + z * F**2 - F
display(equation)
solution = sp.solve(equation, F)[0]
display(solution)
display(sp.series(solution))
Question. The approach where we explicitly solve the equation and then expand it as power series, works only for low-degree equations. How to obtain first coefficients of formal power series for more complicated algebraic equations?
Related.
Since algebraic and differential framework may behave differently, I posted another question.
Sympy: how to solve differential equation in formal power series?
I don't know a built-in way, but plugging in a polynomial for F and equating the coefficients works well enough. Although one should not try to find all coefficients at once from a large nonlinear system; those will give SymPy trouble. I take iterative approach, first equating the free term to zero and solving for c0, then equating 2nd and solving for c1, etc.
This assumes a regular algebraic equation, in which the coefficient of z**k in the equation involves the k-th Taylor coefficient of F, and does not involve higher-order coefficients.
from sympy import *
z = Symbol('z')
d = 10 # how many coefficients to find
c = list(symbols('c:{}'.format(d))) # undetermined coefficients
for k in range(d):
F = sum([c[n]*z**n for n in range(k+1)]) # up to z**k inclusive
equation = 1 + z * F**2 - F
coeff_eqn = Poly(series(equation, z, n=k+1).removeO(), z).coeff_monomial(z**k)
c[k] = solve(coeff_eqn, c[k])[0]
sol = sum([c[n]*z**n for n in range(d)]) # solution
print(series(sol + z**d, z, n=d)) # add z**d to get SymPy to print as a series
This prints
1 + z + 2*z**2 + 5*z**3 + 14*z**4 + 42*z**5 + 132*z**6 + 429*z**7 + 1430*z**8 + 4862*z**9 + O(z**10)

Solving constraint satisfaction problems in Sympy

I'm attempting to solve some simple Boolean satisfiability problems in Sympy. Here, I tried to solve a constraint that contains the Or logic operator:
from sympy import *
a,b = symbols("a b")
print(solve(Or(Eq(3, b*2), Eq(3, b*3))))
# In other words: (3 equals b*2) or (3 equals b*3)
# [1,3/2] was the answer that I expected
Surprisingly, this leads to an error instead:
TypeError: unsupported operand type(s) for -: 'Or' and 'int'
I can work around this problem using Piecewise, but this is much more verbose:
from sympy import *
a,b = symbols("a b")
print(solve(Piecewise((Eq(3, b*2),Eq(3, b*2)), (Eq(3, b*3),Eq(3, b*3)))))
#prints [1,3/2], as expected
Unfortunately, this work-around fails when I try to solve for two variables instead of one:
from sympy import *
a,b = symbols("a b")
print(solve([Eq(a,3+b),Piecewise((Eq(b,3),Eq(b,3)), (Eq(b,4),Eq(b,4)))]))
#AttributeError: 'BooleanTrue' object has no attribute 'n'
Is there a more reliable way to solve constraints like this one in Sympy?
To expand on zaq's answer, SymPy doesn't recognize logical operators in solve, but you can use the fact that
a*b = 0
is equivalent to
a = 0 OR b = 0
That is, multiply the two equations
solve((3 - 2*b)*(3 - 3*b), b)
As an additional note, if you wanted to use AND instead of OR, you can solve for a system. That is,
solve([eq1, eq2])
is equivalent to solving
eq1 = 0 AND eq2 = 0
Every equation can be expressed as something being equated to 0. For example, 3-2*b = 0 instead of 3 = 2*b. (In Sympy, you don't even have to write the =0 part, it's assumed.) Then you can simply multiply equations to express the OR logic:
>>> from sympy import *
>>> a,b = symbols("a b")
>>> solve((3-b*2)*(3-b*3))
[1, 3/2]
>>> solve([a-3-b, (3-b*2)*(3-b*3)])
[{b: 1, a: 4}, {b: 3/2, a: 9/2}]

What does lu_factorize return?

boost::number::ublas contains the M::size_type lu_factorize(M& m) function. Its name suggests that it performs the LU decomposition of a given matrix m, i.e. should produce two matrices that m = L*U. There seems to be no documentation provided for this function.
It is easy to deduce that it returns 0 to indicate successful decomposition, and a non-zero value when the matrix is singular. However, it is completely unclear where is the result. Taking the matrix by reference suggests that it works in-place, however it should produce two matrices (L and U) not one. So what does it do?
There is no documentation in boost, but looking at the documentation of SciPy's lu_factor one can see, that it's not uncommon to return one result for the LU decomposition.
This is enough, because in a typical approach to LU decomposition, L's diagonal consists of ones only, as presented in this answer from Mathematics, for example.
So, it is possible to fit both L and U into one matrix, putting L in result's lower part, omitting the diagonal (which is assumed to contain only ones), and U in the upper part. For example, for a 3x3 problem the result is:
u11 u12 u13
m = l21 u22 u23
l31 l32 u33
which implies:
1 0 0
L = l21 1 0
l31 l32 1
and
u11 u12 u13
U = 0 u22 u23
0 0 u33
Inspecting boost's void lu_substitute(const M& m, vector_expression<E>& e) function, from the same namespace seems to confirm this. It solves the equation LUx = e, where both L and U are contained in its m argument in two steps.
First solve Lz = e for z, where z = Ux, using lower part of m:
inplace_solve(m, e, unit_lower_tag ());
then, having computed z = Ux (with e modified in place), Ux = e can be solved, using upper part of m:
inplace_solve(m, e, upper_tag ());
inplace_solve is mentioned in the documentation, and it:
Solves a system of linear equations with triangular form, i.e. A is triangular.
So everything seems to make sense.
The boost doesn't have document of LU factorization (a lower triangular matrix L and upper triangular matrix U), but the source code shared with the public.
If the code is hard to follow, please check the webpage by Nick Higham. It had an detailed explanation. Here are an example from the link:
Let's say we need to solve Ax = b.
  (1) Make LU from input matrix, A
[3 -1 1  1]
[-1  3 1 -1] ->
[-1 -1 3  1]
[1  1 1  3]
Low
[1     0    0    0]
[-1/3   1   0   0]
[-1/3 -1/2 1 0]
[1/3    1/2  0 1]
Upper
[3    -1   1   1]
[0 8/3 4/3 -2/3]
[0   0   4    1]
[0   0   0    3]
   This example looks straight forward to human but algorithm wise could be numerous steps. This is why LU Factorization came. Methodically, Relation with Gaussian Elimination, Schur Complements, and Block Implementations are some.
  (2) Solve the triangular systems Ly = b and Ux = y, since then b = L(Ux).

Linear Programming - variable that equals the sign of an expression

I am trying to write a linear program and need a variable z that equals the sign of x-c, where x is another variable, and c is a constant.
I considered z = (x-c)/|x-c|. Unfortunately, if x=c, then this creates division by 0.
I cannot use z=x-c, because I don't want to weight it by the magnitude of the difference between x and c.
Does anyone know of a good way to express z so that it is the sign of x-c?
Thank you for any help and suggestions!
You can't model z = sign(x-c) exactly with a linear program (because the constraints in an LP are restricted to linear combinations of variables).
However, you can model sign if you are willing to convert your linear program into a mixed integer program, you can model this with the following two constraints:
L*b <= x - c <= U*(1-b)
z = 1 - 2*b
Where b is a binary variable, and L and U are lower and upper bounds on the quantity x-c. If b = 0, we have 0 <= x - c <= U and z = 1. If b = 1, we have L <= x - c <= 0 and z = 1 - 2*1 = -1.
You can use a solver like Gurobi to solve mixed integer programs.
For k » 1 this is a smooth approximation of the sign function:
Also
when ε → 0
These two approximations haven't the division by 0 issue but now you must tune a parameter.
In some languages (e.g. C++ / C) you can simply write something like this:
double sgn(double x)
{
return (x > 0.0) - (x < 0.0);
}
Anyway consider that many environments / languages already have a sign function, e.g.
Sign[x] in Mathematica
sign(x) in Matlab
Math.signum(x) in Java
sign(1, x) in Fortran
sign(x) in R
Pay close attention to what happens when x is equal to 0 (e.g. the Fortran function will return 1, with other languages you'll get 0).