SymPy simplify does not attempt factoring - sympy

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.

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

How to prevent Sympy from calculating degree in pow

There is an expression:
3^(48*x)
Sympy on further calculations will convert it to:
79766443076872509863361^x
Perhaps there is some kind of flag that prohibits such horrors.
If simplify is used it will cause that expansion. One way you can keep this from happening is to replace 48 with Symbol("48") so it is a variable. An UnevaluatedExpr will not be protected from the actions of simplify so that might be your only option.
>>> simplify(UnevaluatedExpr(2**(4*x))+1)
16**x + 1
>>> simplify(2**(Symbol('4')*x)+1)
2**(4*x) + 1

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.

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