sympy: how to simplify across multiple expressions - python

I have a set of sympy expressions like this (a few hundred of them):
>>> foo = parse_expr('X | Y')
>>> bar = parse_expr('(Z & X) | (Z & Y)')
>>> baz = parse_expt('AAA & BBB') # not needed for this example; just filler
I can simplify one in isolation:
>>> simplify(bar)
Z & (X | Y)
Is there a way to simplify, including the whole set of variables available?
>>> mysimplify(bar, include=(foo,bar,baz))
Z & foo

You can take advantage of Common Subexpresion Elimination. You must use it in combination with simplify by combining all your expressions into a single artificial expression (for example, by passing them as arguments to a fictitious function). I don't think that it will always work as desired, however on a loose analogue of your example it produces the expected result:
In [1]: from sympy import *
In [2]: myexprlist = sympify('listofexpr(x|y, (z&x)|(z&y))')
In [3]: cse(simplify(myexprlist))
Out[3]: ([(x0, Or(x, y))], [listofexpr(x0, And(x0, z))])
The first entry in the result is a list of introduced subexpressions. In this case
the subexpression x|y has been denoted with x0. The second part of the result is the simplified expression (packaged into a list, since the input can be a list of expressions).

Related

is it possible to define an unevaluated symbol in sympy?

I have a list of symbols in sympy:
x,y,z = symbols(["x","y","z"])
_symbols = [x,y,z]
I need to use these symbols in some algorithmically generated expressions, and these expressions must not be evaluated because I'm using them as excercises.
Is there a method to prevent evaluation by defining these symbols as UnevaluatedExpr? I was thinking as something as
map(UnevaluatedExpr, _symbols)
but this does not affect the output, as x+x gives anyway 2x.
Also something along the lines of
for symbol in _symbols:
symbol = UnevaluatedExpr(symbol)
does not work.
EDIT: I noticed that there is a somewhat weird behavior of UnevaluatedExpr (at least for me), namely
UnevaluatedExpr(x)**0
gives 1. I would have expected simply x**0 as output, since x could be 0 and in that case it's not true that the result is 1.
Creating your expressions in an evaluate(False) context might be what you want:
>>> with evaluate(False):
... x + x
...
x + x

a.cross(b.cross(c)) == (a.dot(c))*b - (a.dot(b))*c coming out False [duplicate]

Is there a way to check if two expressions are mathematically equal? I expected
tg(x)cos(x) == sin(x) to output True, but it outputs False. Is there a way to make such comparisons with sympy? Another example is
(a+b)**2 == a**2 + 2*a*b + b**2 which surprisingly also outputs False.
I found some similar questions, but none covered this exact problem.
From the SymPy documentation
== represents exact structural equality testing. “Exact” here means that two expressions will compare equal with == only if they are exactly equal structurally. Here, (x+1)^2 and x^2+2x+1 are not the same symbolically. One is the power of an addition of two terms, and the other is the addition of three terms.
It turns out that when using SymPy as a library, having == test for exact symbolic equality is far more useful than having it represent symbolic equality, or having it test for mathematical equality. However, as a new user, you will probably care more about the latter two. We have already seen an alternative to representing equalities symbolically, Eq. To test if two things are equal, it is best to recall the basic fact that if a=b, then a−b=0. Thus, the best way to check if a=b is to take a−b and simplify it, and see if it goes to 0. We will learn later that the function to do this is called simplify. This method is not infallible—in fact, it can be theoretically proven that it is impossible to determine if two symbolic expressions are identically equal in general—but for most common expressions, it works quite well.
As a demo for your particular question, we can use the subtraction of equivalent expressions and compare to 0 like so
>>> from sympy import simplify
>>> from sympy.abc import x,y
>>> vers1 = (x+y)**2
>>> vers2 = x**2 + 2*x*y + y**2
>>> simplify(vers1-vers2) == 0
True
>>> simplify(vers1+vers2) == 0
False
Alternatively you can use the .equals method to compare expressions:
from sympy import *
x = symbols('x')
expr1 = tan(x) * cos(x)
expr2 = sin(x)
expr1.equals(expr2)
True
The solution with simplify was too slow for me (had to crosscheck multiple variables), so I wrote the following function, which does some simple checkes beforehand, to reduce computational time, to use simplify only in the last step.
import numpy as np
import sympy as sp
def check_equal(Expr1,Expr2):
if Expr1==None or Expr2==None:
return(False)
if Expr1.free_symbols!=Expr2.free_symbols:
return(False)
vars = Expr1.free_symbols
your_values=np.random.random(len(vars))
Expr1_num=Expr1
Expr2_num=Expr2
for symbol,number in zip(vars, your_values):
Expr1_num=Expr1_num.subs(symbol, sp.Float(number))
Expr2_num=Expr2_num.subs(symbol, sp.Float(number))
Expr1_num=float(Expr2_num)
Expr2_num=float(Expr2_num)
if not np.allclose(Expr1_num,Expr2_num):
return(False)
if (Expr1.equals(Expr2)):
return(True)
else:
return(False)
As previously stated, (expr1 - expr2).simplify() or expr1.equals(expr2) will sometimes fail to recognize equality for expressions that are complex to simplify. To deal with this, a numerical evaluation of the expressions with random numbers may constitute a relatively safe "brute force" test. I've adapted the excellent solution by #Okapi575 to:
Test the numerical equality N-times with different random numbers each time for a more confident diagnostic
Warn the user when a pair of expressions only passes the numeric test but not the symbolic equality test.
For example:
Hope it can prove useful:
import sympy as sp
import numpy as np
def check_equal(Expr1, Expr2, n=10, positive=False, strictly_positive=False):
# Determine over what range to generate random numbers
sample_min = -1
sample_max = 1
if positive:
sample_min = 0
sample_max = 1
if strictly_positive:
sample_min = 1
sample_max = 2
# Regroup all free symbols from both expressions
free_symbols = set(Expr1.free_symbols) | set(Expr2.free_symbols)
# Numeric (brute force) equality testing n-times
for i in range(n):
your_values=np.random.uniform(sample_min, sample_max, len(free_symbols))
Expr1_num=Expr1
Expr2_num=Expr2
for symbol,number in zip(free_symbols, your_values):
Expr1_num=Expr1_num.subs(symbol, sp.Float(number))
Expr2_num=Expr2_num.subs(symbol, sp.Float(number))
Expr1_num=float(Expr2_num)
Expr2_num=float(Expr2_num)
if not np.allclose(Expr1_num, Expr2_num):
print("Fails numerical test")
return(False)
# If all goes well so far, check symbolic equality
if (Expr1.equals(Expr2)):
return(True)
else:
print("Passes the numerical test but not the symbolic test")
# Still returns true though
return(True)
EDIT: code updated (1) to compare expressions with differing numbers of free symbols (for example, after symbols got cancelled out during a simplification), and (2) to allow for the specification of a positive or strictly positive random number range.
Check this out from the original sympy themselves.
https://github.com/sympy/sympy/wiki/Faq
Example of it working for me

Separating real and imaginary parts using Sympy

I am trying to segregate real and imaginary parts of the output for the following program.
import sympy as sp
a = sp.symbols('a', imaginary=True)
b=sp.symbols('b',real=True)
V=sp.symbols('V',imaginary=True)
a=4*sp.I
b=5
V=a+b
print V
Kindly help. Thanks in advance.
The lines
b=sp.symbols('b',real=True)
V=sp.symbols('V',imaginary=True)
have no effect, because you overwrite the variables b and V in the lines
b=5
V=a+b
It's important to understand the difference between Python variables and SymPy symbols when using SymPy. Whenever you use =, you are assigning a Python variable, which is just a pointer to the number or expression you assign it to. Assigning it again changes the pointer, not the expression. See http://docs.sympy.org/latest/tutorial/intro.html and http://nedbatchelder.com/text/names.html.
To do what you want, use the as_real_imag() method, like
In [1]: expr = 4*I + 5
In [2]: expr.as_real_imag()
Out[2]: (5, 4)
You can also use the re() and im() functions:
In [3]: re(expr)
Out[3]: 5
In [4]: im(expr)
Out[4]: 4

Symbolic manipulation over non-numeric types

I'm interested in a python library that permits symbolic manipulation where the symbols and can be unknowns of an arbitrary type.
This is the code that I want to write:
>>> myexpression = symbol("foo") == "bar"
>>> print myexpression
foo == "bar"
>>> print myexpression(foo="quux")
False
>>> myexpression.or_(True)
True
Or some rough approximation of that. It doesn't actually even need to be that clever, I'd be happy enough having to call a lot of extra introspection methods to get something like the above (for instance, even if the logical tautology is not directly simplified)
My first instinct was to look at sympy, but it seems that library makes the strong assumption that symbolic variables must be numbers; and I'd like to at least operate on sequences and sets:
>>> myexpression = sympy.Eq(sympy.Symbol("foo"), 5)
>>> myexpression
foo == 5
>>> myexpression = sympy.Eq(sympy.Symbol("foo"), "bar")
Traceback (most recent call last):
...
sympy.core.sympify.SympifyError: SympifyError: 'bar'
Is there a way to get sympy to understand non-numeric variables, or another library that can do similar things?
Not sure how well it fits the uses you have in mind, but the nltk (Natural Language Toolkit) has modules for symbolic manipulation, including first order logic, typed lambda calculus, and a theorem prover. Take a look at this howto.
Could you just map everything into a Sympy symbol? For instance, in your last expression:
sympy.Eq(sympy.Symbol("foo"), sympy.Symbol("bar")). Or do you mean you actually want to write logical statements about set relationships?
Boolean logic is in SymPy although not as easily expressible as it should be. Its definitely there though.
In [1]: x,y,z = symbols('x y z')
In [2]: A = Eq(x,y)
In [3]: A
Out[3]: x = y
In [4]: B = Gt(y,z)
In [5]: And(A,B)
Out[5]: x = y ∧ y > z
In [6]: C = Gt(x,z)
In [7]: And(A, Or(B,C))
Out[7]: x = y ∧ (y > z ∨ x > z)
I'm not aware of many methods to simplify these expressions. This is the sort of thing that would be easy to do if there was interest though.

Basics of SymPy

I am just starting to play with SymPy and I am a bit surprised by some of its behavior, for instance this is not the results I would expect:
>>> import sympy as s
>>> (-1)**s.I == s.E**(-1* s.pi)
False
>>> s.I**s.I == s.exp(-s.pi/2)
False
Why are these returning False and is there a way to get it to convert from one way of writing a complex number to another?
From the FAQ:
Why does SymPy say that two equal expressions are unequal?
The equality operator (==) tests whether expressions have identical form, not whether they are mathematically equivalent.
To make equality testing useful in basic cases, SymPy tries to rewrite mathematically equivalent expressions to a canonical form when evaluating them. For example, SymPy evaluates both x+x and -(-2*x) to 2*x, and x*x to x**2.
The simplest example where the default transformations fail to generate a canonical form is for nonlinear polynomials, which can be represented in both factored and expanded form. Although clearly a(1+b) = a+ab mathematically, SymPy gives:
>>> bool(a*(1+b) == a + a*b) False
Likewise, SymPy fails to detect that the difference is zero:
>>> bool(a*(1+b) - (a+a*b) == 0) False
If you want to determine the mathematical equivalence of nontrivial expressions, you should apply a more advanced simplification routine to both sides of the equation. In the case of polynomials, expressions can be rewritten in a canonical form by expanding them fully. This is done using the .expand() method in SymPy:
>>> A, B = a*(1+b), a + a*b
>>> bool(A.expand() == B.expand()) True
>>> (A - B).expand() 0
If .expand() does not help, try simplify(), trigsimp(), etc, which attempt more advanced transformations. For example,
>>> trigsimp(cos(x)**2 + sin(x)**2) == 1 True
Because they're not equal. Try this one:
s.E**(s.I* s.pi)== s.I*s.I

Categories