Get a second implicit derivative with SymPy - python

we have the follow cell in jupyter kernel python3:
from sympy.interactive.printing import init_printing
from sympy.core.symbol import symbols
from sympy.geometry.util import idiff
init_printing(use_unicode=True)
x = symbols('x')
y = symbols('y')
then just run:
eq = x ** 2 - x * y + y ** 2 - 3
eqd1 = idiff(eq, y, x)
eqd1
we get the correct answer: 2x-y / x-2y
but if run the code:
eqd2 = idiff(eqd1, y, x)
eqd2
we get: x/y but the answer realy is: 18/(x-2y)² or 6(x²-xy+y²)/(x-2y)³
x/y and 18/(x-2y)² don't looks like a equal expression or factorial one of another

Running
eqd2 = idiff(eq, y, x, n=2)
simplify(expand(eqd2))
Produces
6(x2-xy+y2)/(x3-6x2y-12xy2-8y3)
which is the correct result (after a bit more simplification).

Related

Contradictiry values for the same calculation in python

Consider the following two results
import numpy as np
(1/21) * np.log( (1/21) / (3/21) * (3/21))
which results in
-0.14497725893921062
and the same calculation as follows
import numpy as np
x = 0.14285714285714285
y = 0.14285714285714285
xy = 0.047619047619047616
xy * np.log(xy / (x * y))
which results in
0.040347517161295414
Both calculations are same, but results has so much gap. What is the issue here?
And which one is recommended, if its not a subjective question?
Because multiplication and divison have same precedence at Python and Python reads them from left to right.
for example:
x, y, z = 2, 4, 8
these are completely different:
x / y * z == x / (y * z)
>>>False
left side is 4.0 and right side is 0.0625
ps:
Parentheses have the highest precedence and can be used to force an expression to evaluate in the order you want.

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.

Evaluate 1/tanh(x) - 1/x for very small x

I need to compute the quantity
1/tanh(x) - 1/x
for x > 0, where x can be both very small and very large.
Asymptotically for small x, we have
1/tanh(x) - 1/x -> x / 3
and for large x
1/tanh(x) - 1/x -> 1
Anyhow, when computing the expression, already from 10^-7 and smaller round-off errors lead to the expression being evaluated as exactly 0:
import numpy
import matplotlib.pyplot as plt
x = numpy.array([2**k for k in range(-30, 30)])
y = 1.0 / numpy.tanh(x) - 1.0 / x
plt.loglog(x, y)
plt.show()
For very small x, one could use the Taylor expansion of 1/tanh(x) - 1/x around 0,
y = x/3.0 - x**3 / 45.0 + 2.0/945.0 * x**5
The error is of the order O(x**7), so if 10^-5 is chosen as the breaking point, relative and absolute error will be well below machine precision.
import numpy
import matplotlib.pyplot as plt
x = numpy.array([2**k for k in range(-50, 30)])
y0 = 1.0 / numpy.tanh(x) - 1.0 / x
y1 = x/3.0 - x**3 / 45.0 + 2.0/945.0 * x**5
y = numpy.where(x > 1.0e-5, y0, y1)
plt.loglog(x, y)
plt.show()
Use the python package mpmath for arbitrary decimal precision. For example:
import mpmath
from mpmath import mpf
mpmath.mp.dps = 100 # set decimal precision
x = mpf('1e-20')
print (mpf('1') / mpmath.tanh(x)) - (mpf('1') / x)
>>> 0.000000000000000000003333333333333333333333333333333333333333311111111111111111111946629156220629025294373160489201095913
It gets extremely precise.
Look into mpmath plotting. mpmath plays well with matplotlib, which you are using, so this should solve your problem.
Here is an example of how to integrate mpmath into the code you wrote above:
import numpy
import matplotlib.pyplot as plt
import mpmath
from mpmath import mpf
mpmath.mp.dps = 100 # set decimal precision
x = numpy.array([mpf('2')**k for k in range(-30, 30)])
y = mpf('1.0') / numpy.array([mpmath.tanh(e) for e in x]) - mpf('1.0') / x
plt.loglog(x, y)
plt.show()
A probably simpler solution to overcome this is changing the data type under which numpy is operating:
import numpy as np
import matplotlib.pyplot as plt
x = np.arange(-30, 30, dtype=np.longdouble)
x = 2**x
y = 1.0 / np.tanh(x) - 1.0 / x
plt.loglog(x, y)
plt.show()
Using longdouble as data type does give the proper solution without rounding errors.
I did sightly modify your example, in your case the only thing you need to modify is:
x = numpy.array([2**k for k in range(-30, 30)])
to:
x = numpy.array([2**k for k in range(-30, 30)], dtype=numpy.longdouble)

Solving an equation for a variable

How can I get this to give me x = z*y/a ?
from sympy import *
x,y,a,z = symbols('x y a z')
z = a*x/y
solve(z,x) # returns 0!
# would like to get z*y/a
solve(z,x) correctly returns 0 because your code is effectively asking:
What's the value of x that would cause z to become 0?
What you really want to do (as described here) is solve a*x/y==z which can be done as follows:
from sympy import *
x,y,a,z = symbols('x y a z')
equation = a*x/y
new_eq = solve(equation - z, x) # its value is [y*z/a]
Don't assign z = a*x/y, and don't pass z to solve.
solve(expr, symbol) determines what values of symbol will make expr equal 0. If you want to figure out what value of x makes z equal a*x/y, you want z - a*x/y to equal 0:
solve(z - a*x/y, x)
You do not want to assign z = a*x/y. = means something entirely different from equality.
I think the answer to this question can be of help. Applied to your example, this gives:
>>> from sympy import *
>>> x,y,a,z = symbols('x y a z')
>>> l = z
>>> r = a*x/y
>>> solve(l-r,x)
[y*z/a]
As all the other answers points out the solution,
I would like to emphasize on the use of Eq instances here.
An Eq object represents An equal relation between two objects.
For using an Eq object, your code should look something like this:
In []: a, x, y, z = symbols('a, x, y, z')
In []: foo = Eq(z, a*x/y)
In []: solve(foo, x)
Out[]: [y*z/a]

partial integration of a two dimensional gaussian function

I want to carry out the following partial integration of a 2-D gaussian function of four variables (x, y, alpha and beta), with respect to only x and y, as follows. In the end I want the answer to be a function of alpha and beta only.
I wrote the following code in python to execute the above mentioned integral.
from sympy import Symbol
from sympy import integrate
from math import e
alpha = Symbol('alpha')
beta = Symbol('beta')
x = Symbol('x')
y = Symbol('y')
n = 2
value = integrate( e**( -(x - alpha)**n - (y - beta)**n ), (x, -1, 1), (y, -1, 1) )
However I get the following error:
sympy.polys.polyerrors.DomainError: there is no ring associated with RR
The above mentioned integrate function works fine for n=1. However it breaks down for n>1.
Am I doing something wrong?
Welcome to SO!
Interestingly it works when you substitute alpha and beta into the integral bounds. Try:
from IPython.display import display
import sympy as sy
sy.init_printing() # LaTeX like pretty printing forIPython
alpha, beta, x, y = sy.symbols("alpha, beta, x, y", real=True)
f = sy.exp(-x**2 - y**2) # sy.exp() is better than the numeric constant
val = sy.integrate(f, (x, -1+alpha, 1+alpha), (y, -1+beta, 1+beta))
display(val)

Categories