Symbolic manipulation over non-numeric types - python

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.

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

sympy: how to simplify across multiple expressions

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

How to simplify logarithm of exponent in sympy?

When I type
import sympy as sp
x = sp.Symbol('x')
sp.simplify(sp.log(sp.exp(x)))
I obtain
log(e^x)
Instead of x. I know that "there are no guarantees" on this function.
Question. Is there some specific simplification (through series expansion or whatsoever) to convert logarithm of exponent into identity function?
You have to set x to real type and your code will work:
import sympy as sp
x = sp.Symbol('x', real=True)
print(sp.simplify(sp.log(sp.exp(x))))
Output: x.
For complex x result of this formula is not always is equal to x. Example is here.
If you want to force the simplification, expand can help because it offers the force keyword which basically makes certain assumptions like this for you without you having to declare your variables as real. But be careful with the result -- you will not want to use it when those assumptions are not warranted.
>>> log(exp(x)).expand(force=True)
x
You can also set the argument "inverse" to "True" in the simplify function:
>>> simplify(log(exp(x)), inverse=True)
x

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

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