How do you substitute into solutions in sympy? - python

Consider this simple MWE:
from sympy.solvers.diophantine import diophantine
from sympy import symbols
x, y, z = symbols("x, y, z", integer=True)
diophantine(x*(2*x + 3*y - z))
This outputs:
[(t_0, t_1, 2*t_0 + 3*t_1), (0, n1, n2)]
If I want to create instances of these solutions I would like, for
example, to able to substitute integer values into t_0 and t_1. How
can you do that?
I tried e.g.
diof = diophantine(x*(2*x + 3*y - z))
list(diof)[0][0].subs(t_0, 0)
but that gives
NameError: name 't_0' is not defined

t_0 is not defined as a Python variable. You can create the Python variable in a couple of different ways:
from sympy import symbols
t_0 = symbols("t_0")
Alternatively, you can capture the symbol generated from your SymPy calculation into a Python variable. Here's one way:
diofl = list(diof) # Assuming that diof is as you had defined it.
t_0 = diofl[1][0] # Presuming that this is the part of diofl
# that contains the correct symbol. Print
# diofl[1][0] to be sure!
After that, you can then use t_0 as an argument of the subs() method.

Related

Getting the derivative of a function as a function with sympy (for later evaluation and substitution)

I want to work with generic functions as long as possible, and only substitute functions at the end.
I'd like to define a function as the derivative of another one, define a generic expression with the function and its derivative, and substitute the function at the end.
Right now my attempts is as follows, but I get the error 'Derivative' object is not callable:
from sympy import Function
x, y, z = symbols('x y z')
f = Function('f')
df = f(x).diff(x) # <<< I'd like this to be a function of dummy variable x
expr = f(x) * df(z) + df(y) + df(0) # df is unfortunately not callable
# At the end, substitute with example function
expr.replace(f, Lambda(X, cos(X))) # should return: -cos(x)*sin(z) - sin(y) - sin(0)
I think I got it to work with integrals as follows:
I= Lambda( x, integrate( f(y), (y, 0, x))) but that won't work for derivatives.
If that helps, I'm fine restricting myself to functions of a single variable for now.
As a bonus, I'd like to get this to work with any combination (products, derivatives, integrals) of the original function.
It's pretty disappointing that f.diff(x) doesn't work, as you say. Maybe someone will create support it sometime in the future. In the mean time, there are 2 ways to go about it: either substitute x for your y, z, ... OR lambdify df.
I think the first option will work more consistently in the long run (for example, if you decide to extend to multivariate calculus). But the expr in second option is far more natural.
Using substitution:
from sympy import *
x, y, z = symbols('x y z')
X = Symbol('X')
f = Function('f')
df = f(x).diff(x)
expr = f(x) * df.subs(x, z) + df.subs(x, y) + df.subs(x, 0)
print(expr.replace(f, Lambda(X, cos(X))).doit())
Lambdifying df:
from sympy import *
x, y, z = symbols('x y z')
X = Symbol('X')
f = Function('f')
df = lambda t: f(t).diff(t) if isinstance(t, Symbol) else f(X).diff(X).subs(X, t)
expr = f(x) * df(z) + df(y) + df(0)
print(expr.replace(f, Lambda(X, cos(X))).doit())
Both give the desired output.

Find and replace functions in expression tree

I need to find all the user made functions (and things like derivatives on the user function) in a SymPy expression tree with the location to then replace with just standard user-defined symbols
from sympy import *
t=symbols('t')
Now create the user made SymPy function:
theta_t = Function(r'\theta')(t)
Also, I create the symbol that I want to replace theta_t with:
theta = Symbol(r'\theta')
The expression that I want to work with is:
y = sin(theta_t)
And this is its derivative with respect to t:
dydt = y.diff(t)
I want to find and replace d/dt(theta(t)) and theta_t with symbols omega, theta. For example after substituting I want dydt to be:
dydt_new = cos(theta)*omega
So now I can work with this last expression numerically, e.g., with lambdify.
You can just substitute derivatives like anything else. You only have to be careful about substituting the derivative before the actual function. The following works for me:
from sympy import *
t = symbols('t')
theta_t = Function('theta')(t)
theta = Symbol('theta')
omega = Symbol('omega')
y = sin(theta_t)
dydt = y.diff(t)
dydt_new = dydt.subs([
( diff(theta_t,t), omega ),
( theta_t, theta ),
])
assert dydt_new==cos(theta)*omega
Note how this fails if you swap the order of substitutions.

Implicit Differentiation Sympy

I've been doing derivatives in sympy, and I didn't know how that would syntactically be written. I tried looking it up, but none of the solutions made sense. For example, if I'm trying to differentiate x**5 + y**2 + z**4 = 8xyz by computation, how would I do that? Would z be a symbol, or a function like in regular derivatives? Thank you.
For two variables you can use idiff.
In your case, the simplest way is to set x and y to be functions of z, like
x = Function('x')(z)
y = Function('y')(z)
Then normal diff(expr, z) will take the derivative correctly.
You commented you used idiff, here is the corresponding code for those who want to know:
from sympy import symbols, idiff, simplify
x, y, z = symbols('x y z')
ex = x**5 + y**2 + z**4 - 8*x*y*z
ex_d = simplify(idiff(ex,(x,y),z))
display(ex_d)
In idiff(ex,(x,y),z), (x,y) are the dependent variables, and z the variable the derivative is being taken with respect to.

Why does sympy.diff not differentiate sympy polynomials as expected?

I am trying to figure out why sympy.diff does not differentiate sympy polynomials as expected. Normally, sympy.diff works just fine if a symbolic variable is defined and the polynomial is NOT defined using sympy.Poly. However, if the function is defined using sympy.Poly, sympy.diff does not seem to actually compute the derivative. Below is a code sample that shows what I mean:
import sympy as sy
# define symbolic variables
x = sy.Symbol('x')
y = sy.Symbol('y')
# define function WITHOUT using sy.Poly
f1 = x + 1
# define function WITH using sy.Poly
f2 = sy.Poly(x + 1, x, domain='QQ')
# compute derivatives and return results
df1 = sy.diff(f1,x)
df2 = sy.diff(f2,x)
print('f1: ',f1)
print('f2: ',f2)
print('df1: ',df1)
print('df2: ',df2)
This prints the following results:
f1: x + 1
f2: Poly(x + 1, x, domain='QQ')
df1: 1
df2: Derivative(Poly(x + 1, x, domain='QQ'), x)
Why does sympy.diff not know how to differentiate the sympy.Poly version of the polynomial? Is there a way to differentiate the sympy polynomial, or a way to convert the sympy polynomial to the form that allows it to be differentiated?
Note: I tried with different domains (i.e., domain='RR' instead of domain='QQ'), and the output does not change.
This appears to be a bug. You can get around it by calling diff directly on the Poly instance. Ideally calling the function diff from the top level sympy module should yield the same result as calling the method diff.
In [1]: from sympy import *
In [2]: from sympy.abc import x
In [3]: p = Poly(x+1, x, domain='QQ')
In [4]: p.diff(x)
Out[4]: Poly(1, x, domain='QQ')
In [5]: diff(p, x)
Out[5]: Derivative(Poly(x + 1, x, domain='QQ'), x)
In [6]: diff(p, x).doit()
Out[6]: Derivative(Poly(x + 1, x, domain='ZZ'), x)

How to find root of two implicit functions in Python, without using fsolve for the set of equations

I am dealing with a set of several non-linear equations that I was able to reduce analytically to set of two implicit equations with two variables. Now I wish to find roots of those equations using Brent's method. I would like to pass one function as an argument to another and solve the equation for variable 2 depending on every variable 1.
In mathematical terms I wish to solve: f(x,y) and g(x,y) in this way f(x,g(x)).
Simplify example of what I wish to do can be presented here.
Instead of:
import scipy.optimize
from scipy.optimize import fsolve
def equations(p):
y,z = p
f1 = -10*z + 4*y*z - 5*y + 4*z**2 - 7
f2 = 2*y*z + 5*y - 3
return (f1,f2)
and solve it by:
y, z = fsolve(equations,[0,19])
I wish to write something like that:
def func2(x, y):
f2= 2*y*x + 5*y - 3
return brentq(f2, -5, 5)
def func(x,y):
y = func2(x,y)
return -10*x + 4*x*y - 5*y + 4*x**2 - 7
sol, = brentq(lambda x: func(x, func2), -5, 5)
I wish to ask for help in how to pass a function as an argument for this particular purpose and explain what am I doing wrong. I am new to Python and maybe there is a better way to ensure precise solution to my problem.

Categories