I want to get rid of an extra substitution which sympy makes when differentiating a user defined composite function. The code is
t = Symbol('t')
u = Function('u')
f = Function('f')
U = Symbol('U')
pprint(diff(f(u(t),t),t))
The output is:
d d ⎛ d ⎞│
──(f(u(t), t)) + ──(u(t))⋅⎜───(f(ξ₁, t))⎟│
dt dt ⎝dξ₁ ⎠│ξ₁=u(t)
I guess it does this because you can't differentiate w.r.t u(t), so this is ok. What I want to do next is to substitute u(t) with an other variable say U and then get rid of the extra substitution \xi_1
⎞│
⎟│
⎠│ξ₁=U
To clarify, I want this output:
d d ⎛d ⎞
──(f(U, t)) + ──(U)⋅⎜──(f(U, t))⎟
dt dt ⎝dU ⎠
The reason is; when I Taylor expand a composite function like this, the extra substitutions make the output unreadable. Does anyone know how to do this? Any other solution is of course welcomed.
Substituting is done with subs. If something is not evaluated you can force it with the doit method.
>>> diff(f(u(t),t),t).subs(u(t),U)
Derivative(U,t)∗Subs(Derivative(f(xi1,t),xi1),(xi1,),(U,))+Derivative(f(U,t),t)
>>> _.doit()
Derivative(f(U,t),t)
Check the tutorial! It has all these ideas presented nicely.
Related
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.
I can write, for example,
Line(Point(3,-4), Point(-2,2)).equation()
to generate an equation of a line that passes through those points, but the output is given as
-6x - 5y - 2
presumably being equivalent to -6x - 5y - 2 = 0. How can I instead set the output to be
y = (-6/5)x - (2/5)
I thought it might have to do with some formatting settings in the equation() method, so I checked the documention, but it didn't say anything about it.
EDIT 1: It appears that if I input
solve(Eq(Line(Point(3,-4), Point(-2,2)).equation()))
I will get the (albeit ugly) output
⎡⎧ 5⋅y 1⎫⎤
⎢⎨x: - ─── - ─⎬⎥
⎣⎩ 6 3⎭⎦
This does give a rearranged solution, but the issue is that this is only in the form of x=f(y). I'm not sure how I would get it to instead be in terms of y=f(x).
EDIT 2: I think this might actually be a bug with solve(), or Eq(). If I instead manually type
solve(-6*x-5*y-2,y)
or
solve(Eq(-6*x-5*y-2),y)
I will get the (somewhat ugly, but correct) output of
⎡ 6⋅x 2⎤
⎢- ─── - ─⎥
⎣ 5 5⎦
Now if I were to instead type
solve(Eq(Line(Point(3,-4), Point(-2,2)).equation()),y)
or
solve(Eq(Line(Point(3,-4), Point(-2,2)).equation()),x)
I get the output of
[]
This is rather strange, though, because
Eq(-6*x-5*y-2)
and
Eq(Line(Point(3,-4),Point(-2,2)).equation())
both output
-6⋅x - 5⋅y - 2 = 0
so I'm really not sure what Is going on here.
Since you need to pass the symbol you want to solve for, you can do something like this (Although the equation function expects strings )
x, y = symbols('x, y')
eq = (Line(Point(3,-4), Point(-2,2)).equation(x,y))
print(solve(eq, y))# prints [-6*x/5 - 2/5]
or you can get the symbol from the expression and pass it to solve like
eq = (Line(Point(3,-4), Point(-2,2)).equation())
print(solve((eq), list(eq.atoms(Symbol))[1])) # prints [-6*x/5 - 2/5]
The symbols used in the equation have assumptions on them and that makes them different from the plain symbols you might create with Symbol('x'). So that's why it has the option to pass in the symbols you want to use for x and y.
>>> var('x y')
(x, y)
>>> Line(Point(3,-4), Point(-2,2)).equation(x,y)
-6*x - 5*y - 2
>>> Eq(y, solve(_, y)[0])
Eq(y, -6*x/5 - 2/5)
That's also why you didn't get a solution in one of your examples -- the variable you were solving for wasn't in the equation. It looked the same but it wasn't since it had different assumptions on it.
I am trying to calculate general composite function derivative using sympy. In my specific case script is the following:
from sympy import *
t=symbols('t')
p=Function('p')
x=Function('x')
v=diff(x(p(t)),t)
a=diff(v,t)
for variable a it yields:
Derivative(p(t), t)**2*Derivative(x(p(t)), p(t), p(t)) + Derivative(p(t), t, t)*Subs(Derivative(x(_xi_1), _xi_1), (_xi_1,), (p(t),))
If I call doit(), answer still contains subs object
a.doit() #answer: Derivative(p(t), t)**2*Subs(Derivative(x(_xi_3), _xi_3, _xi_3), (_xi_3,), (p(t),)) + Derivative(x(p(t)), p(t))*Derivative(p(t), t, t)
Mathematically the answer is correct but I still need output in following format (without Subs objects):
Derivative(p(t), t)**2*Derivative(x(p(t)), p(t), p(t)) + Derivative(x(p(t)), p(t))*Derivative(p(t), t, t)
Is there any way to achieve desired result? To be clear this example is very simplified compared to my original expression so I need general way to get desired output.
Indeed, repeated applications of doit() in this case result in flip-flopping between two forms of the expression: half the time the first addend has Subs, half the time it's the second.
But you can deal with the issue as follows:
for b in a.atoms(Subs):
a = a.xreplace({b: b.doit()})
This returns Derivative(p(t), t)**2*Derivative(x(p(t)), p(t), p(t)) + Derivative(x(p(t)), p(t))*Derivative(p(t), t, t) as desired.
The trick is that atoms(Subs) is the set of all Subs objects in the expression, and doit is applied only to them, not to Derivative objects where it only messes things up. (Ideally, doit would not mess Derivative objects up in the first place...)
I need to know how transfer string input into executable function.
For example - user write string 'x*Sin(x**2)' and then programm takes it as function, can calculate a value for given x, can plot derivation of this function etc. I've read that there is module called scitools.stringfunction, but as far as I know this module is not callable in python-3.
Any ideas how to make it?
For Python 2.X
f = lambda x: input() # the user inputs: x**2 + 1
y = f(3)
print y # outputs: 10
For Python 3.X
f = lambda x: eval(input())
y = f(5)
print y
Just make sure to import the required mathematical functions. And make sure the user inputs a valid Python arithmetic expression.
using sympy you could do something like this:
from sympy import var
from sympy import sympify
x = var('x') # the possible variable names must be known beforehand...
user_input = 'x * sin(x**2)'
expr = sympify(user_input)
res = expr.subs(x, 3.14)
print(res) # -1.322...
if you want to turn the user input into a function you can call you could to this:
from sympy.utilities.lambdify import lambdify
f = lambdify(x, expr)
# f(3.14) -> -1.322...
sympy can do sybolic calculations (including derivatives); if you want to make plots i strongly suggest matplotlib.
the advantage of using a math library opposed to eval is that you do not need to sanitize the user input (against malicious code).
(deleted this thanks to a comment from ejm).
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.