Sympy check satisfiability of statement involving symbols - sympy

I have a program that generates logical statements involving symbols, like conds below
import sympy
x, y = sympy.symbols('x,y')
conds = sympy.Eq(x+y,-1) & (x>1) & (y>2)
I would like to check if they're satisfiable (if there exist x,y meeting the conditions). In general, how can I reduce logical statements involving symbols?
sympy.solve([sympy.Eq(x+y,1), x>1, y>2]) gives a NotImplementedError and the inequality solvers can only handle one variable IIRC.
I'd appreciate any help with this.

I'm not sure exactly when this will or won't work (the problem is undecidable in full generality) but SymPy has a function reduce_inequalities that does work for the example shown:
In [8]: reduce_inequalities(conds)
Out[8]: False

Related

Eliminate unnecessary Piecewise terms from Sympy expressions

Sympy often produces expressions like
Sum(Piecewise((2**(-N)*exp(-_k*beta)*binomial(N, _k), _k <= N), (0, True)), (_k, 0, N))
where the first condition of the Piecewise is always satisfied, since it is ensured by the summation range.
In this example I can eliminate the Piecewise using
X.refine(Q.le(X.bound_symbols[0], N))
which works because I know the form of the expression.
I would like to find a general solution that can eliminate redundant Piecewise case anywhere in an expression in most reasonable cases without knowing the structure of the expression in advance, since it needs to be applied to results of other simplifications. Something like "refine by implicit constraints on bound variables". None of the simplification functions seem able to do this.
Note that the summation variable is introduced by Sympy so I do not have control over its creation.

Keep the order of parameters fixed in sympy lambdify from free_symbols

When asking for a symbol .free_symbols I get something in curly braces (which is a set).
If I use this set as list of arguments for lambdify of sympy it seems it is converted into a list. This is hinted in the doc but I suggest a warning to be given here when this conversion is made. A good reason for this is that the ordering of the symbols may be altered in this conversion.
In my case
_chiSquare.free_symbols gives {c_95_0, c_95_1}
but
list({'c_95_0', 'c_95_1'}) gives ['c_95_1', 'c_95_0']
I like to automate the making of numerical functions using .free_symbols but this is hard to work with if order of variable is changed without notice.
My question is how one is supposed to deal with free_symbols and lambdify in a way that arguments order is kept fixed.
I think it is better to keep track of the symbols explicitly rather than using free_symbols.
If you must work from free_symbols then you can sort them to get a consistent ordering:
In [3]: sorted((x*y).free_symbols, key=lambda s: s.name)
Out[3]: [x, y]

SymPy simplify does not attempt factoring

Is there a workaround for SymPy's apparent inability to simplify sqrt(x**2+2*x+1)?
from sympy import *
x = Symbol('x', real=True, positive=True)
simplify(sqrt(x**2)) # returns x
simplify(sqrt(x**2+2*x+1)) #fails to return x+1
SymPy does not try to simplify everything on sight, there are too many issues (starting with performance) if it did that. See the article Automatic Simplification in SymPy wiki.
If you want to factor an expression, you should tell SymPy to do that.
factor(sqrt(x**2+2*x+1)) # returns x+1
The formula sqrt(x**2) becomes x because (x**a)**b can be safely combined to x**(a*b) when the base is positive and exponents are real. (Even then, "can" does not always mean "should be". Some amount of automatic simplification is present in SymPy, maybe too much.)
The key difference between the two is that x**2 is a explicitly a power while x**2 + 2*x + 1 is a sum.

Sympy lambdify array with shape (n,)

I have the following 'issue' with sympy at the moment:
I have a symbolic expression like M = matrix([pi*a, sin(1)*b]) which I want to lambdify and pass to a numerical optimizer. The issue is that the optimizer needs the function to input/output numpy arrays of shape (n,) and specifically NOT (n,1).
Now I have been able to achieve this with the following code (MWE):
import numpy as np
import sympy as sp
a, b = sp.symbols('a, b')
M = sp.Matrix([2*a, b])
f_tmp = sp.lambdify([[a,b]], M, 'numpy')
fun = lambda x: np.reshape( f_tmp(x), (2,))
Now, this is of course extremely ugly, since the reshape needs to be applied every time fun is evaluated (which might be LOTS of times). Is there a way to avoid this problem? The Matrix class is by definition always 2 dimensional. I tried using sympy's MutableDenseNDimArray-class, but they don't work in conjunction with lambdify. (symbolic variables don't get recognized)
One way is to convert a matrix to a nested list and take the first row:
fun = sp.lambdify([[a, b]], M.T.tolist()[0], 'numpy')
Now fun([2, 3]) is [4, 3]. This is a Python list, not a NumPy array, but optimizers (at least those in SciPy) should be okay with that.
One can also do
fun = sp.lambdify([[a, b]], np.squeeze(M), 'numpy')
which also returns a list.
In my test the above were equally fast, and faster than the version with a wrapping function (be it np.squeeze or np.reshape): about 6 µs vs 9 µs. It seems the gain is in eliminating one function call.

sympy: test subexpression for trig function

I am trying to test whether any sub-expression contains a sin function (or any trig function)
from sympy import sin, symbols, Wild
A, B, x, y = symbols('A, B, x, y')
W1=Wild('W1')
I can do this:
>> (A*sin(x)+B*sin(y)).has(sin(x))
out: True
But this does not work:
>>: (A*sin(x)+B*sin(y)).has(sin(W1))
out: False
How do I test for one or more sin functions regardless of argument?
If you want to use Wilds, use find:
In [11]: (A*sin(x)+B*sin(y)).find(sin(W1))
Out[11]: set([sin(x), sin(y)])
But if you are searching for a single function like sin, and not generic expressions, an easier and faster way is to use atoms:
In [12]: (A*sin(x)+B*sin(y)).atoms(sin)
Out[12]: set([sin(x), sin(y)])
If you want to check for multiple trig functions, atoms takes multiple arguments, which is more efficient than calling it multiple times
In [14]: (A*sin(x)+B*cos(y)).atoms(sin, cos)
Out[14]: set([sin(x), cos(y)])
In my first attempt, I tried to test for sin using a wild card for an argument
>>: (A*sin(x)+B*sin(y)).has(sin(W1))
out: False
After reading asmeuer's answer and experimenting a bit, I discovered that you can simply pass the class sin (no argument) and it works:
>>: (A*sin(x)+B*sin(y)).has(sin, cos)
out: True
Thus, use has if you want a logical test and use atoms if you want a set of the functions that appear in the expression.
Question: is there a general class I can use to test for the presence of any trig function (sin, cos, tan, atan, ...)?