Sympy coeff not consistent with as_independent - python

I have the following snippet of code
import sympy
a = sympy.symbols('a')
b = sympy.symbols('b')
c = sympy.symbols('c')
print((a*b).coeff(c,0))
print((a*b).as_independent(c)[0])
I don't understand why the two print statements print different output. According to the documentation of coeff:
You can select terms independent of x by making n=0; in this case
expr.as_independent(x)[0] is returned (and 0 will be returned instead
of None):
>>> (3 + 2*x + 4*x**2).coeff(x, 0)
3
Is this a bug in sympy, or do I miss something?

It's a bug. I have a pull request fixing it here.

Related

How do I evaluate a Sympy function in Python?

I am facing a major issues in python using sympy. I didn't find any solutions to my problem or at least, I couldn't apply the solutions I found on my problem.
import sympy as sp
import math as ma
import numpy as np
E1=72500
A1=15
U01,s,C1,U02 = sp.symbols("U01,s,C1,U02")
u1 = sp.symbols("u1", cls=sp.Function)
eqs=sp.Eq(E1*A1*u1(s).diff(s)+180+U02,0)
sol=sp.dsolve(eqs,dict=True)
expr=sol.args[1]
u1=sp.lambdify(s,expr.subs(C1,U01))
print(u1(s))
#gives me : U01 - 9.19540229885057e-7*U02*s - 0.00016551724137931*s
expression1=u1(10)-54
expression2=u1(7)-99
eq1=sp.Eq(expression1,0)
eq2=sp.Eq(expression2,0)
solution = sp.solve([eq1,eq2],[U01,U02])
U01=float(solution[U01])
U02=float(solution[U02])
print(u1(55))
# gives me : U01 - 5.05747126436782e-5*U02 - 0.00910344827586207
I want to evaluate u1(55), but I still get the expression.
Thank you very much in advance.
I expect to get :
-621.0000000000018
Don't override U01 and U02 by numerical values, use intermediate variables. You have to evaluate your lambda function with solution previously found:
...
solution = sp.solve([eq1, eq2], [U01, U02])
U01_val = float(solution[U01])
U02_val = float(solution[U02])
result = u1(55).evalf(subs={U01: U01_val, U02: U02_val})
print(result)
# Output
-621.000000000001
Or simply:
...
solution = sp.solve([eq1, eq2], [U01, U02])
result = u1(55).evalf(subs=solution)
print(result)
# Output
-621.000000000001

Define a function that is a derivative of a function

I was wondering if is there is a way to define a function that is a derivative of a function. I'm new to python so I don't no much, I tired looking up stuff that might be similar but nothing has worked so far. This is what I have for my code right now.
import sympy as sp
import math
x = sp.Symbol('x')
W = 15 #kN/m
E = 70 # Gpa
I = 52.9*10**(-6) #m**4
L = 3 #m
e = 0.01
xi = 1.8
y = 9
def f(x):
return ( ( y*3*(math.pi**4)*E*I/(W*L) ) - ( 48*(L**3)*math.cos(math.pi*x/(2*L)) ) + ( 48*(L**3) ) + ( (math.pi**3)*(x**3) ) )/(3*L*(math.pi**3))**(1/2)
def derv(f,x):
return sp.diff(f)
print (derv(f,x))
Also, I don't understand whatx = sp.Symbol('x') does, so if someone could explain that, that would be awesome.
Any help is appreciated.
You are conflating two different things: python functions like f and math functions, which you can express with sympy like y = π * x/3. f is a python function that returns a sympy expression. sympy lets you stay in the world of symbolic math functions by defining variables like x = sp.Symbol('x') So calling f() produces a symbolic math function like:
You can use sympy to find the derivative of the symbolic function returned by f() but you need to define it with the sympy versions of the cos() function (and sp.pi if you want to keep it symbolic).
For example:
import sympy as sp
x = sp.Symbol('x')
W = 15 #kN/m
E = 70 # Gpa
I = 52.9*10**(-6) #m**4
L = 3 #m
e = 0.01
xi = 1.8
y = 9
def f(x):
return ( ( y*3*(sp.pi**4)*E*I/(W*L) ) - ( 48*(L**3)*sp.cos(sp.pi*x/(2*L)) ) + ( 48*(L**3) ) + ( (sp.pi**3)*(x**3) ) )/(3*L*(sp.pi**3))**(1/2)
def derv(f,x):
return sp.diff(f(x)) # pass the result of f() which is a sympy function
derv(f,x)
You've programmed the function. it appears to be a simple function of two independent variables x and y.
Could be that x = sp.Symbol('x') is how SymPy defines the independent variable x. I don't know if you need one or another one for y.
You know enough about calculus to know that you need a derivative. Do you know how to differentiate a function of a single independent variable? It helps to know the answer before you start coding.
y*3*(math.pi**4)*E*I/(W*L) ) - ( 48*(L**3)*math.cos(math.pi*x/(2*L)) ) + ( 48*(L**3) ) + ( (math.pi**3)*(x**3) ) )/(3*L*(math.pi**3))**(1/2)
Looks simple.
There's only one term with y in it. The partial derivative w.r.t. y leaves you with 3*(math.pi**4)*E*I/(W*L) )
There's only one term with Cx**3 in it. That's easy to differentiate: 3C*x**2.
What's so hard? What's the problem?
In traditional programming, each function you write is translated to a series of commands that are then sent to the CPU and the result of the calculation is returned. Therefore, symbolic manipulation, like what we humans do with algebra and calculus, doesn't make any sense to the computer. Sympy gets around this by overriding Python's normal arithmetic operators, allowing you to do generate algebraic functions that can be manipulated similarly to how we humans do math. That's what sp.Symbols('x') is doing: providing you with a symbolic variable you can work with (you're also naming it in sympy).
If you want to evaluate your derivative, simply call evalf with the numerical value you want to assign to x.

Error evaluating a derivative on Python (with .subs, .evalf and .lambdify)

I am trying to separately compute the elements of a Taylor expansion and did not obtain the results I was supposed to. The function to approximate is x**321, and the first three elements of that Taylor expansion around x=1 should be:
1 + 321(x-1) + 51360(x-1)**2
For some reason, the code associated with the second term is not working.
See my code below.
import sympy as sy
import numpy as np
import math
import matplotlib.pyplot as plt
x = sy.Symbol('x')
f = x**321
x0 = 1
func0 = f.diff(x,0).subs(x,x0)*((x-x0)**0/factorial(0))
print(func0)
func1 = f.diff(x,1).subs(x,x0)*((x-x0)**1/factorial(1))
print(func1)
func2 = f.diff(x,2).subs(x,x0)*((x-x0)**2/factorial(2))
print(func2)
The prints I obtain running this code are
1
321x - 321
51360*(x - 1)**2
I also used .evalf and .lambdify but the results were the same. I can't understand where the error is coming from.
f = x**321
x = sy.Symbol('x')
def fprime(x):
return sy.diff(f,x)
DerivativeOfF = sy.lambdify((x),fprime(x),"numpy")
print(DerivativeOfF(1)*((x-x0)**1/factorial(1)))
321*x - 321
I'm obviously just starting with the language, so thank you for your help.
I found a beginners guide how to Taylor expand in python. Check it out perhaps all your questions are answered there:
http://firsttimeprogrammer.blogspot.com/2015/03/taylor-series-with-python-and-sympy.html
I tested your code and it works fine. like Bazingaa pointed out in the comments it is just an issue how python saves functions internally. One could argument that for a computer it takes less RAM to save 321*x - 321 instead of 321*(x - 1)**1.
In your first output line it also gives you 1 instead of (x - 1)**0

multiple functions as arguments in python

I have the following problem: I have two sets of data (set T and set F). And the following functions:
x(T) = arctan(T-c0), A(x(T)) = arctan(x(T) -c1),
B(x(T)) = arctan(x(T) -c2)
and Y(x(t),F) = ((A(x(t)) - B(x(t)))/2 - A(x(t))arctan(F-c3) + B(x(t))arctan(F-c4))
# where c0,c1,c2,c3,c4 are constants
Now I want to create a surface plot of Y. And for that I would like to implement Y as a python (numpy) function what turns out to be quite complicated, because Y takes other functions as input.
Another idea of mine was to evaluate x, B and A on the data separately and store the results in numpy arrays. With those I also could get the output of the function Y , but I don't know which way is better in order to plot the data and I really would like to know how to write Y as a python function.
Thank you very much for your help
It is absolutely possible to use functions as input parameters to other functions. A use case could look like:
def plus_one(standard_input_parameter_like_int):
return standard_input_parameter_like_int + 1
def apply_function(function_as_input, standard_input_parameter):
return function_as_input(standard_input_parameter)
if(__name__ == '__main__'):
print(apply_function(plus_one, 1))
I hope that helps to solve your specific problem.
[...] somethin like def s(x,y,z,*args,*args2): will yield an
error.
This is perfectly normal as (at least as far as I know) there is only one variable length non-keyword argument list allowed per function (that has to be exactly labeled as *args). So if you remove the asterisks (*) you should actually be able to run s properly.
Regarding your initial question you could do something like:
c = [0.2,-0.2,0,0,0,0]
def x(T):
return np.arctan(T-c[0])
def A(xfunc,T):
return np.arctan(xfunc(T) - c[1])
def B(xfunc,T):
return np.arctan(xfunc(T) - c[2])
def Y(xfunc,Afunc,Bfunc,t,f):
return (Afunc(xfunc,t) - Bfunc(xfunc,t))/2.0 - Afunc(xfunc,t) * np.arctan(f - c[3]) + Bfunc(xfunc,t)*np.arctan(f-c[4])
_tSet = np.linspace(-1,1,20)
_fSet = np.arange(-1,1,20)
print Y(x,A,B,_tSet,_fSet)
As you can see (and probably already tested by yourself judging from your comment) you can use functions as arguments. And as long as you don't use any 'if' conditions or other non-vectorized functions in your 'sub'-functions the top-level function should already be vectorized.

Not aligned Sympy's nice pritting of division

I'm trying to nice print some divisions with Sympy but I noticed it didn't display aligned.
import sympy
sympy.init_printing(use_unicode=True)
sympy.pprint(sympy.Mul(-1, sympy.Pow(-5, -1, evaluate=False), evaluate=False))
# Output:
# -1
# ───
# -5 # Note that "-5" is displayed slightly more on the right than "-1".
Reason/fix for this?
EDIT: I did a lot of reverse-engineering using inspect.getsource and inspect.getsourcefile but it didn't really help out in the end.
Pretty Printing in Sympy seems to be relying on the Prettyprinter by Jurjen Bos.
import sympy
from sympy.printing.pretty.stringpict import *
sympy.init_printing(use_unicode=True)
prettyForm("-1")/prettyForm("-5")
# Displays:
# -1
# --
# -5
So it does display aligned, but I can't get it to use unicode.
The PrettyPrinter is called from the file sympy/printing/pretty/pretty.py in the method PrettyPrinter._print_Mul which simply return prettyForm.__mul__(*a)/prettyForm.__mul__(*b) with, I thought, a and b simply being ['-1'] and ['-5'] but it wouldn't work.
Found out where the weird part is coming from:
stringpict.py line 417:
if num.binding==prettyForm.NEG:
num = num.right(" ")[0]
This is being done ONLY for the numerator. It adds a space after the numerator if the numerator is negative… Weird!
I'm not sure if there can be a fixed other than directly editing the file. I'm going to report this on Github.
Thanks all for your help and suggestion.
PS: In the end, I used pdb to help me debug and figure out what was actually going out!
EDIT: Hotfix if you can't / don't want to edit the code source:
import sympy
sympy.init_printing(use_unicode=True)
from sympy.printing.pretty.stringpict import prettyForm, stringPict
def newDiv(self, den, slashed=False):
if slashed:
raise NotImplementedError("Can't do slashed fraction yet")
num = self
if num.binding == prettyForm.DIV:
num = stringPict(*num.parens())
if den.binding == prettyForm.DIV:
den = stringPict(*den.parens())
return prettyForm(binding=prettyForm.DIV, *stringPict.stack(
num,
stringPict.LINE,
den))
prettyForm.__div__ = newDiv
sympy.pprint(sympy.Mul(-1, sympy.Pow(-5, -1, evaluate=False), evaluate=False))
# Displays properly:
# -1
# ──
# -5
I just copied the function from the code source and removed the incriminated line.
Possible improvement could be to functools.wraps the new function with the original one.
Negative denominators are not standard and badly handled. If you really need them, you can modify the string outpout given by the pretty function :
import sympy
sympy.init_printing(use_unicode=True)
def ppprint(expr):
p=sympy.pretty(expr)
s=p.split('\n')
if len(s)==3 and int(s[2])<0:
s[0]=" "+s[0]
s[1]=s[1][0]+s[1]
p2="\n".join(s)
print(p2)
else: print(p)
This extend the bar and the numerator of one unit for negative denominators. No warranty of robustness on big expressions.
>>>> ppprint(sympy.Mul(sympy.Pow(-5, -1,evaluate=False),-1,evaluate=False))
-1
────
-5
I was not quite sure what you are searching for, but I think I was dealing with something similar a while ago.
I got a comprehension list and used this for printing.
You may find it useful.
x = amp * np.sin( 2 * np.pi * 200 * times ) + nse1
x2 = np.array_split(x,epochs(
Rxy[i], freqs_xy = mlab.csd(x2[i], y2[i], NFFT=nfft, Fs=sfreq)
Rxy_mean0 = [complex(sum(x)/len(x)) for x in Rxy]
import pprint
pp = pprint.PrettyPrinter(indent=4)
pp.pprint(Rxy_mean0)

Categories

Resources