sympy: test subexpression for trig function - sympy

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, ...)?

Related

sympy: sympy function symbolic or non-symbolic

I am trying to understand about sympy's symbolic functions:
import sympy
from sympy.abc import x,y,z
with sympy.evaluate(False):
print(sympy.sympify("diff(x,x)").func)
print(sympy.parse_expr("diff(x, x)", local_dict={'diff':sympy.Derivative}).func)
print(sympy.sympify("Derivative(x,x)").func)
pass
This puts out:
Piecewise
<class 'sympy.core.function.Derivative'>
<class 'sympy.core.function.Derivative'>
This example should illustrate that diff is not a symbolic function yet Derivative is.
sympy.sympify("diff(x,x)").func results in Piecewise.
What exactly makes a function in sympy 'symbolic'?
Why don't both of the functions belong to <class 'sympy.core.function.Derivative'>?
I tried to test on a few examples if a function is symbolic using:
list_of_funcs = [sin, cos, tan, sec, csc, cot, sinh, cosh, tanh, sech, csch, coth, asin, acos, atan, asec, acsc, acot, asinh, acosh, atanh, asech, acsch, acoth, log, log, log, exp, <class 'sympy.concrete.summations.Sum'>, <class 'sympy.concrete.products.Product'>, Piecewise, jacobi, Piecewise]
with sympy.evaluate(False):
for f in list_of_funcs:
if issubclass(f, sympy.Basic):
print(f'{f}: True')
It returned True for all yet as far as I understood Piecewise is not symbolic.
Could you help me finding a way to test if a function is symbolic?
Answering this question without going too deep into coding concepts is not easy, but I can give it a try.
SymPy exposes many functions:
cos, sin, exp, Derivative, Integral... we can think of them as symbolic functions. Let's say you provide one or more arguments, then:
the function might evaluate to some symbolic numerical value. For example, cos(0) will return the symbolic number 1.
the function might return an "unevaluated" object. For example, cos(x) returns cos(x): this is a symbolic expression of type cos (as you have seen by running the func attribute). Similarly, you can create a derivative object Derivative(expr, x): this is a symbolic expression that represents a derivative, it doesn't actually compute the derivative!
Unevaluate functions, for example Function("f")(x), which will render as f(x): this is a symbolic expression of type f.
diff, integrate, series, limit, ... : those are ordinary python functions (for example, created with def diff(...)) that are going to apply some operation to a symbolic expression. When you call diff(expr, x) you are asking SymPy to compute the derivative of expr with respect to x. What if you wanted to represent the derivative without actually computing it? You write Derivative(expr, x).
So, going back to your example:
sympy.parse_expr("diff(x, x)", local_dict={'diff':sympy.Derivative})
this can be easily simplified to:
sympy.parse_expr("Derivative(x, x)")
A few more "relationships":
diff and Derivative
integrate and Integral
limit and Limit
Think of "symbolic" functions as nouns and "non symbolic" as verbs.
noun-like verb-like
---------- ---------
Integral integrate
Derivative diff
Sum summation
Product product
Those that are Python functions (I think what you mean by non-symbolic) emit some evaluated form of something that could also exist in an unevaluated form, e.g. prod(x, (x, 1, 5)) -> 120; Product(x, (x, 1, 5)) -> no change.
It would be better to refer to them in some other way. What I think you mean is "evaluated" vs "non-evaluated" (since almost all of SymPy's functions will return SymPy objects with "symbols", even if numeric).
If the type(thing) -> function it is not a class itself, it is a Python function. If you check the type of cos or Sum you will not get function as the result.
Whereas some of the evaluates and unevaluated forms may have different names (Sum vs summation) others, like Add are evaluative by default but you can use the evaluate=False arg to stop that: Add(x, x) = x + x != Add(x,x,evaluate=False). Those which are evaluative can be made non-evaluative by passing evaluate=True, e.g. Derivative(x, x, evaluate=True) -> 1.

Sympy check satisfiability of statement involving symbols

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

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.

How can I enumerate the undefined functions in a SymPy expression?

I have a variety of SymPy expressions involving UndefinedFunction instances:
f = Function('f')
g = Function('g')
e = f(x) / g(x)
How can I obtain a list of the function invocations appearing in such expressions? In this example, I'd like to get [f(x), g(x)].
I'm aware of free_symbols but it kicks back set([x]) (as it should).
You are right that you want to use atoms, but be aware that all functions in SymPy subclass from Function, not just undefined functions. So you'll also get
>>> (sin(x) + f(x)).atoms(Function)
set([f(x), sin(x)])
So you'll want to further reduce your list to only those functions that are UndefinedFunctions. Note that UndefinedFunction is the metaclass of f, so do to this, you need something like
>>> [i for i in expr.atoms(Function) if isinstance(i.__class__, UndefinedFunction)]
[f(x)]
It turns out that the atoms member method can accept a type on which to filter. So
e.atoms(Function)
returns
set([f(x), g(x)])
as I'd wanted. And that fancier things like
e.diff(x).atoms(Derivative)
are possible.