SymPy prints function names instead of its value - python

I recently started learning IPython. I have a problem with Sympy library. It only prints the function instead of exact value.
import matplotlib.pyplot as plt
import numpy as nm
from sympy import *
x,y = symbols("x y")
expr = cos(x)
a = expr.subs(x,1)
print(a)
The output of above program is cos(1). But I want to print the exact value of cos(1).

First of all some nitpicking: “cos(1)” is the most concise way to represent the exact value of cos(1). Numerical representations like “0.54”, “0.540302”, or “0.54030230587” are not exact but are only accurate within the respective number of digits. The fact that cos(1) is not simply translated to one of those numerical approximations is one of the features of SymPy, as it ensures that something like simplify(acos(cos(1))) actually yields 1 and not 0.99999999.
That being said, there are of course purposes where you really need a numerical representation. In this case, you can use the class function n of SymPy expressions or the function N from SymPy, for example:
from sympy import cos, N
expr = cos(1)
print(expr.n()) # 0.540302305868140
print(N(expr)) # 0.540302305868140

Related

Is there a convenient way to add complex numbers in polar form in sympy (python)?

I had some trouble adding complex numbers in polar form in sympy.
The following code
from sympy import I, exp, pi, re, im
a = exp(2*pi/3*I)
b = exp(-2*pi/3*I)
c = a+b
print(c)
print(c.simplify())
print(c.as_real_imag())
print(re(c)+im(c)*I)
print(int(c))
print(complex(c))
gives
exp(-2*I*pi/3) + exp(2*I*pi/3)
-(-1)**(1/3) + (-1)**(2/3)
(-1, 0)
-1
-1
(-1+6.776263578034403e-21j)
What I want, is to get the simplest answer to a+b, which is -1. I can obtain this, by manually rebuilding c=a+b with re(c)+im(c)*I. Why is this necessary? And is there a better way to do this?
Simply printing c retains the polar forms, obfuscating the answer, c.simplify() leaves the polar form, but is not really helpful, and c.as_real_imag() returns a tuple. int(c) does the job, but requires the knowledge, that c is real (otherwise it throws an error) and integer (otherwise, this is not the answer I want). complex(c) kind of works, but I don't want to leave symbolic calculation. Note, that float(c) does not work, since complex(c) has a non-zero imaginary part.
https://stackoverflow.com/users/9450991/oscar-benjamin has given you the solution. If you are in polar coordinates, your expression may have exponential functions. If you don't want these you have to rewrite into trigonometric functions where special values are known for many values. For example, consider a's 2*pi/3 angle:
>>> cos(2*pi/3)
-1/2
>>> sin(2*pi/3)
sqrt(3)/2
When you rewrite a in terms of cos (or sin) it becomes the sum of those two values (with I on the sin value):
>>> a.rewrite(cos)
-1/2 + sqrt(3)*I/2
When you rewrite a more complex expression, you will get the whole expression rewritten in that way and any terms that cancel/combine will do so (or might need some simplification):
>>> c.rewrite(cos)
-1

Extracting the numbers out of a SymPy expression

How can I extract all the numerical values from a SymPy expression?
For example, for this expression: sin(a/pi + a) + 0.629116159212, I want pi, -1, and 0.629116159212.
I found the srepr function in SymPy, which returns for the example:
Add(sin(Add(Mul(Pow(pi, Integer(-1)), Symbol('a')), Symbol('a'))), Float('0.62911615921200004', precision=53))
How can I extract all the numbers from this, i.e., everything that is not a Symbol?
The method atoms returns a set of all atomic (i.e., unsplittable) components of an expression.
The attribute is_number tells you whether some expression (or atom) is a number.
Combined:
from sympy import sin, pi
from sympy.abc import a
expr = sin(a/pi + a) + 0.629116159212
numbers = {atom for atom in expr.atoms() if atom.is_number}
Now, if you need to preserve the count of appearances, things get a bit more complicated, since atoms returns a set.
Here, we additionally can use:
Alternative 1:
sympy.preorder_traversal (or postorder_traversal) which iterates through all subexpressions of an expression.
(Thanks to Oscar Benjamin and A.S. Meurer.)
Alternative2:
The method find of expressions, which returns all expressions matching some criterion.
The attribute is_Atom.
from sympy import sin, pi, preorder_traversal
from sympy.abc import a
expr = sin(a/pi + 1/a) + 0.629116159212
is_atomic_number = lambda expr: expr.is_Atom and expr.is_number
# Alternative 1:
[
subexpression
for subexpression in preorder_traversal(expr)
if is_atomic_number(subexpression)
]
# Alternative 2:
expr.find(is_atomic_number,group=True)

SymPy outputs a numerical result when a symbolic expression is expected

I'ld like my SymPy results to be displayed as precise results and not as decimal results. I looked through the SymPy documentation, but couldn't find anything helpful.
To illustrate the problem, here is some example code:
from sympy import *
u = symbols("u")
integrate((1+u)**(1/2), (u, 0, 1))
Output:
1.21895141649746
Expected result:
(4/3)*sqrt(2)-(2/3)
The problem is that SymPy will simplify expressions containing floats and so removes those symbolic expressions. Although the expression doesn't look like a float, the division 1/2 is done with standard Python, internally represented as 0.5.
The solution is to first convert one of the parts of the fraction to a SymPy object. The easiest way is with the function S, as in:
from sympy import *
u = symbols("u")
print(integrate((1+u)**(S(1)/2), (u, 0, 1)))
which outputs the desired -2/3 + 4*sqrt(2)/3.
The gotcha section of the documentation tries to explain this behavior.

How to apart Exponential function in python

I am trying to apart Exponential function in python.
import sympy as sym
from sympy.abc import t
from sympy import exp
u = (3*(exp(4*t) - 1)*exp(-4*t))/4
apart = sym.apart(u, t)
print(apart)
But i get the error:
exp(4*t) contains an element of the set of generators
it looks like exp() is confusing it. For a workaround
import sympy as sym
from sympy.abc import t,z
from sympy import exp
u = (3*(exp(4*t) - 1)*exp(-4*t))/4
expr = sym.apart(u.subs(exp(t),z), z)
expr = expr.subs(z,exp(t))
Which gives
Out[3]: 3/4 - 3*exp(-4*t)/4
Using 3.7 on conda
Your expression is a univariate, rational function in terms of exp(t):
>>> u.subs(exp(t),y)
3*(y**4 - 1)/(4*y**4)
>>> apart(_)
3/4 - 3/(4*y**4)
>>> _.subs(y, exp(t))
3/4 - 3*exp(-4*t)/4
But SymPy can handle such non-symbol generators so for such an expression sym.apart(u) would have given the same result as shown above. When you said the generator was t it detected the exp(t) and raised the error since an expression like t + exp(t) has two generators that depend on t.

Python Sympy Arbitrary Approximation to Arbitrary Sympy Expression?

I find myself wanting to use approxmations provided as part of the mpmath package, but getting confused on exactly what they are supposed to be doing:
http://docs.sympy.org/dev/modules/mpmath/calculus/approximation.html
What exactly is the difference between a sympy expression and a sympy.mpmath expression ?
If I want a taylor approximation to a symbolic expression without understanding what mpmath package is doing I can do the following:
#Imports
import sympy
import sympy.parsing
import sympy.parsing.sympy_parser
import Library_TaylorApproximation
#Create a sympy expression to approximate
ExampleStringExpression = 'sin(x)'
ExampleSympyExpression = sympy.parsing.sympy_parser.parse_expr(ExampleStringExpression)
#Create a taylor expantion sympy expression around the point x=0
SympyTaylorApproximation = sympy.series(
ExampleSympyExpression,
sympy.Symbol('x'),
1,
4,
).removeO()
#Cast the sympy expressions to python functions which can be evaluated:
VariableNames = [str(var) for var in SympyTaylorApproximation.free_symbols]
PythonFunctionOriginal = sympy.lambdify(VariableNames, ExampleSympyExpression)
PythonFunctionApproximation = sympy.lambdify(VariableNames, SympyTaylorApproximation)
#Evaluate the approximation and the original at a point:
print PythonFunctionOriginal(2)
print PythonFunctionApproximation(2)
#>>> 0.909297426826
#>>> 0.870987413961
However, if I try to do the same thing with mpmath based on the documentation:
TaylorCoefficients = sympy.mpmath.taylor(ExampleSympyExpression, 1, 4 )
print 'TaylorCoefficients', TaylorCoefficients
#>>> TypeError: 'sin' object is not callable
I can try to cram the python function in there (which is callable):
TaylorCoefficients = sympy.mpmath.taylor(PythonFunctionOriginal, 1, 4 )
print 'TaylorCoefficients', TaylorCoefficients
#>>> TaylorCoefficients [mpf('0.8414709848078965'), mpf('0.0'), mpf('0.0'), mpf('0.0'), mpf('-8.3694689805155739e+57')]
But the above does not make any sense, because I know that derivatives cannot be taken of a python function.
I can call the mpmath function sin:
TaylorCoefficients = sympy.mpmath.taylor(sympy.mpmath.sin, 1, 4 )
print 'TaylorCoefficients', TaylorCoefficients
#>>> TaylorCoefficients [mpf('0.8414709848078965'), mpf('0.54030230586813977'), mpf('-0.42073549240394825'), mpf('-0.090050384311356632'), mpf('0.035061291033662352')]
But then I cannot do manipulations on it the way I would want too -> like If I want
SinTimesCos = sympy.mpmath.sin*sympy.mpmath.cos
TaylorCoefficients = sympy.mpmath.taylor(SinTimesCos, 1, 4 )
print 'TaylorCoefficients', TaylorCoefficients
#>>> TypeError: unsupported operand type(s) for *: 'function' and 'function'
Exactly WHAT is an mpmath function ?
It is not a sympy expression, and it is also not a python function. How do I do manipulations on arbitrary expressions?
It would appear that I cannot take approximations of arbitrary sympy expressions in the documentation.
http://docs.sympy.org/dev/modules/mpmath/calculus/approximation.html
How do I take arbitrary approximations ( Pade / Cheby Chev / Fourier )
to arbitrary sympy expressions?
EDIT:
So an example of what I am looking for is the following approximation:
#Start with a sympy expression of (a, b, x)
expressionString = 'cos(a*x)*sin(b*x)*(x**2)'
expressionSympy = sympy.parsing.sympy_parser.parse_expr(expressionString)
#Do not want to decide on value of `a or b` in advance.
#Do want approximation with respect to x:
wantedSympyExpression = SympyChebyChev( expressionSympy, sympy.Symbol('x') )
Result could either be a list of coefficient expressions that are functions of a, and b:
wantedSympyExpressionCoefficients = [ Coef0Expression(a,b), Coef1Expression(a,b), ... , CoefNExpression(a,b)]
OR the result could be the entire sympy expression itself (which is itself a function of a, b):
wantedSympyExpression = Coef0Expression(a,b) + Coef1Expression(a,b) *(x**2) + ... + CoefNExpression(a,b) (x**N)
Note that a and b are not chosen in advance of performing the approximation.
mpmath functions are ordinary Python functions. They simply do their math in arbitrary-precision arithmetic.
But the above does not make any sense, because I know that derivatives cannot be taken of a python function.
You can't take the derivative symbolically, but you can compute an approximation of the derivative by evaluating the function several times and using numerical differentiation techniques. This is what sympy.mpmath.taylor does. Quoting the docs:
The coefficients are computed using high-order numerical differentiation. The function must be possible to evaluate to arbitrary precision.
If you have a SymPy expression and want to evaluate it to arbitrary precision, use evalf, like
sympy.sin(1).evalf(100)
You can use sin(x).evalf(100, subs={x:1}) to replace the x with 1 before evaluating. evalf uses mpmath under the hood, so this will give you the same result that mpmath would, but without having to use mpmath directly.

Categories

Resources