Python Sympy Arbitrary Approximation to Arbitrary Sympy Expression? - python

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.

Related

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.

SymPy prints function names instead of its value

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

Sympy allows definition of integer symbols but does not account for their behavior

I have the following set of commands to do a definite integral
n [2]: from sympy import *
init_printing()
x,L = symbols('x, L')
n = symbols('n', integer = True)
exp = sin((n+Rational(1,2))*pi*x/L)**2
integrate(exp, (x,0,L))
The result of these commands shown below:
The first result implies that n=-1/2 which implies that n is not an integer. What is the point of giving an integer attribute to the symbol if it doesn't account for it in operations as shown above? How can I force sympy to recognize that the first part of the piecewise result is impossible if n is integer?
If the equality had evaluated, this condition would have been rejected and the Piecewise would have evaluated to your expected result. Because SymPy didn't know if your L was zero or not, it couldn't evaluate that equality.
So try
>>> n = var('n', integer=True)
>>> L = var('L', nonzero=True)
>>> exp = sin((n+Rational(1,2))*pi*x/L)**2
>>> integrate(exp, (x,0,L))
L/2
And there you go! :-) (Note, however, that it should have been sufficient to just say that L was finite to know that the equality could never be true, but SymPy fails to evaluate that condition, too.)
/c
Declaring the symbol n as an integer has no consequences for the evaluating except for the simplification of expressions:
The assumptions system allows users to specify that symbols have certain common mathematical properties, such as being positive, imaginary, or integer. SymPy is careful to never perform simplifications on an expression unless the assumptions allow them.
and
Assumptions are only needed to restrict a domain so that certain simplifications can be performed. They are not required to make the domain match the input of a function.
So in your case there is no need to specify the symbol n to be an integer.

Categories

Resources