How to obtain second derivative of generalized Laguerre polynomials with sympy? - python

I can obtain the expression for derivative but it doesn't work with n = 0, 1 because n should be >= 0 and in derivative there is L(n-2, 2, r). How to calculate it with sympy taking into account that it's easy to obtain it when L is in explicit form?
Upd: my code. So I cannot substitute l = 0 to chiLambdified.
import sympy as sym
from sympy.utilities.lambdify import lambdify
from sympy.functions.special.gamma_functions import gamma as SymG
from sympy import assoc_laguerre as SymL
from sympy import factorial as SymFactorial
from sympy import exp as SymExp
r, l, beta = sym.symbols('r, l, beta', real = True)
def chifD(r, l, beta):
return sym.sqrt( SymFactorial(l)*beta**3/(SymG(3 + l))) * r * SymL(l,2, beta * r) * SymExp(- beta * r / 2 )
def chiD(r, l, beta):
return sym.diff(chifD(r ,l, beta), r, r)
chiLambdified = sym.lambdify((r, l, beta), chiD(r, l, beta), 'sympy')

Second order Derivative of a Polynomial of order 0 or 1 is ZERO.
You can show it as follows.
# Calculating the third order differential of
# a second order polynomial: yields a zero
diff(3*x**2 + 2, x, 3)
Using sympy for calculating first and second order derivatives.
from sympy import Symbol, Function, diff
x = Symbol("x")
dydx = diff(3*x**2 + 2, x, 1)
d2ydx2 = diff(3*x**2 + 2, x, 2)
dydx, d2ydx2
Output:
(6*x, 6)
If you would like to use a function:
f = Function("f")(x)
n = 2 # order of derivative
d2ydx2 = diff(f, x, n).subs(f, 3*x**2 + 2).doit()
Another example using special functions:
import
Lgr = sympy.polys.orthopolys.laguerre_poly
Lgr(2, x=x), diff(Lgr(2, x=x), x, 2), diff(Lgr(2, x=x), x, 3), diff(Lgr(1, x=x), x, 2)
Output:
(3*x**2/2 - 1/2, 1, 0, 0)

Related

How to convert symbolic expressions to an ODE and solve it in Python?

Please quickly go through the question I asked in MATLAB Ask:
https://www.mathworks.com/matlabcentral/answers/827750-convert-the-symbolic-expression-into-the-expression-which-can-be-put-on-the-rhs-of-an-ode?s_tid=srchtitle
Now I want to reproduce the same work in Python and meet some problems. Given 2 state equations:
f1 = x2
f2 = -c*sinx1-(a + b*cosx1)*x2
The sensitivity equation is given by
dSdt = PfPx*S+PfPw=RHS # dSdt: time derivative of S (sensitivity matrix),in this case,2x3 matrix
PfPx # Jacobian matrix of F = (f1,f2) wrt x = (x1,x2),2x2 matrix
S # Sensitivity matrix S = [[x3, x5, x7],[x4, x6, x8]],2x3 matrix
PfPw # Jacobian matrix of F wrt parameters w = (a,b,c),2x3 matrix
By symbolic matrix calculation, RHS = PfPx*S + PfPw
Sensitivity equation is given as dSdt(i,j) = RHS(i,j) by vector form for dx3dt~dx8dt appending with state equation for dx1dt and dx2dt (see the picture at the end in that Link), when a=1,b=0,c=1, it generates 8 ODEs:
dx1dt= x2;
dx2dt = -sinx1-x2; # dx1dt~dx2dt are state eqns
dx3dt = x4;
dx4dt = -x3cosx1-x2-x4;
dx5dt = x6;
dx6dt = -x5cosx1-x6-x2cosx1;
dx7dt = x8;
dx8dt = -cos(x1)x7-x8-sinx1; # dx3dt – dx8dt are sensitivity eqns
Try to code the symbolic calculation in Python,
import sympy as sym
import numpy as np
from scipy.integrate import odeint
def model(x, t):
a, b, c = sym.symbols('a,b,c')
f1 = x[1]
f2 = -c * sym.sin(x[0]) - (a + b * sym.cos(x[0])) * x[1]
funcs = sym.Matrix([f1, f2])
pfpx = funcs.jacobian([x[0], x[1]]) # pfpx = Jacobian('x1,x2,x3',[f1, f2, f3])
pfpw = funcs.jacobian([a, b, c])
s = sym.Matrix([[x[2], x[4], x[6]], [x[3], x[5], x[7]]])
pfpx = pfpx.subs([(a, 1), (b, 0), (c, 1)])
pfpw = pfpw.subs([(a, 1), (b, 0), (c, 1)])
res = pfpx * s + pfpw
dydt = [f1, f2, res[0], res[3], res[1], res[4], res[2], res[5]]
return dydt
tspan = np.linspace(0, 10)
z0 = np.zeros(8)
z0[0:2] = [1, 1]
zrec = odeint(model, z0, tspan)
it is saying error on the last line zrec = odeint(model, z0, tspan) and the error msg is:
ValueError:
Can't calculate derivative wrt 1.00000000000000.
Any suggestions are appreciated!

Cubic spline for non-monotonic data (not a 1d function)

I have a curve as shown below:
The x coordinates and the y coordinates for this plot are:
path_x= (4.0, 5.638304088577984, 6.785456961280076, 5.638304088577984, 4.0)
path_y =(0.0, 1.147152872702092, 2.7854569612800755, 4.423761049858059, 3.2766081771559668)
And I obtained the above picture by:
x_min =min(path_x)-1
x_max =max(path_x)+1
y_min =min(path_y)-1
y_max =max(path_y)+1
num_pts = len(path_x)
fig = plt.figure(figsize=(8,8))
#fig = plt.figure()
plt.suptitle("Curve and the boundary")
ax = fig.add_subplot(1,1,1)
ax.set_xlim([min(x_min,y_min),max(x_max,y_max)])
ax.set_ylim([min(x_min,y_min),max(x_max,y_max)])
ax.plot(path_x,path_y)
Now my intention is to draw a smooth curve using cubic splines. But looks like for cubic splines you need the x coordinates to be on ascending order. whereas in this case, neither x values nor y values are in the ascending order.
Also this is not a function. That is an x value is mapped with more than one element in the range.
I also went over this post. But I couldn't figure out a proper method to solve my problem.
I really appreciate your help in this regard
As suggested in the comments, you can always parameterize any curve/surface with an arbitrary (and linear!) parameter.
For example, define t as a parameter such that you get x=x(t) and y=y(t). Since t is arbitrary, you can define it such that at t=0, you get your first path_x[0],path_y[0], and at t=1, you get your last pair of coordinates, path_x[-1],path_y[-1].
Here is a code using scipy.interpolate
import numpy
import scipy.interpolate
import matplotlib.pyplot as plt
path_x = numpy.asarray((4.0, 5.638304088577984, 6.785456961280076, 5.638304088577984, 4.0),dtype=float)
path_y = numpy.asarray((0.0, 1.147152872702092, 2.7854569612800755, 4.423761049858059, 3.2766081771559668),dtype=float)
# defining arbitrary parameter to parameterize the curve
path_t = numpy.linspace(0,1,path_x.size)
# this is the position vector with
# x coord (1st row) given by path_x, and
# y coord (2nd row) given by path_y
r = numpy.vstack((path_x.reshape((1,path_x.size)),path_y.reshape((1,path_y.size))))
# creating the spline object
spline = scipy.interpolate.interp1d(path_t,r,kind='cubic')
# defining values of the arbitrary parameter over which
# you want to interpolate x and y
# it MUST be within 0 and 1, since you defined
# the spline between path_t=0 and path_t=1
t = numpy.linspace(numpy.min(path_t),numpy.max(path_t),100)
# interpolating along t
# r[0,:] -> interpolated x coordinates
# r[1,:] -> interpolated y coordinates
r = spline(t)
plt.plot(path_x,path_y,'or')
plt.plot(r[0,:],r[1,:],'-k')
plt.xlabel('x')
plt.ylabel('y')
plt.show()
With output
For non-ascending x splines can be easily computed if you make both x and y functions of another parameter t: x(t), y(t).
In your case you have 5 points so t should be just enumeration of these points, i.e. t = 0, 1, 2, 3, 4 for 5 points.
So if x = [5, 2, 7, 3, 6] then x(t) = x(0) = 5, x(1) = 2, x(2) = 7, x(3) = 3, x(4) = 6. Same for y.
Then compute spline function for both x(t) and y(t). Afterwards compute values of splines in all many intermediate t points. Lastly just use all calculated values x(t) and y(t) as a function y(x).
Once before I implemented cubic spline computation from scratch using Numpy, so I use this code in my example below if you don't mind (it could be useful for you to learn about spline math), replace with your library functions. Also in my code you can see numba lines commented out, if you want you can use these Numba annotations to speed up computation.
You have to look at main() function at the bottom of code, it shows how to compute and use x(t) and y(t).
Try it online!
import numpy as np, matplotlib.pyplot as plt
# Solves linear system given by Tridiagonal Matrix
# Helper for calculating cubic splines
##numba.njit(cache = True, fastmath = True, inline = 'always')
def tri_diag_solve(A, B, C, F):
n = B.size
assert A.ndim == B.ndim == C.ndim == F.ndim == 1 and (
A.size == B.size == C.size == F.size == n
) #, (A.shape, B.shape, C.shape, F.shape)
Bs, Fs = np.zeros_like(B), np.zeros_like(F)
Bs[0], Fs[0] = B[0], F[0]
for i in range(1, n):
Bs[i] = B[i] - A[i] / Bs[i - 1] * C[i - 1]
Fs[i] = F[i] - A[i] / Bs[i - 1] * Fs[i - 1]
x = np.zeros_like(B)
x[-1] = Fs[-1] / Bs[-1]
for i in range(n - 2, -1, -1):
x[i] = (Fs[i] - C[i] * x[i + 1]) / Bs[i]
return x
# Calculate cubic spline params
##numba.njit(cache = True, fastmath = True, inline = 'always')
def calc_spline_params(x, y):
a = y
h = np.diff(x)
c = np.concatenate((np.zeros((1,), dtype = y.dtype),
np.append(tri_diag_solve(h[:-1], (h[:-1] + h[1:]) * 2, h[1:],
((a[2:] - a[1:-1]) / h[1:] - (a[1:-1] - a[:-2]) / h[:-1]) * 3), 0)))
d = np.diff(c) / (3 * h)
b = (a[1:] - a[:-1]) / h + (2 * c[1:] + c[:-1]) / 3 * h
return a[1:], b, c[1:], d
# Spline value calculating function, given params and "x"
##numba.njit(cache = True, fastmath = True, inline = 'always')
def func_spline(x, ix, x0, a, b, c, d):
dx = x - x0[1:][ix]
return a[ix] + (b[ix] + (c[ix] + d[ix] * dx) * dx) * dx
# Compute piece-wise spline function for "x" out of sorted "x0" points
##numba.njit([f'f{ii}[:](f{ii}[:], f{ii}[:], f{ii}[:], f{ii}[:], f{ii}[:], f{ii}[:])' for ii in (4, 8)],
# cache = True, fastmath = True, inline = 'always')
def piece_wise_spline(x, x0, a, b, c, d):
xsh = x.shape
x = x.ravel()
ix = np.searchsorted(x0[1 : -1], x)
y = func_spline(x, ix, x0, a, b, c, d)
y = y.reshape(xsh)
return y
def main():
x0 = np.array([4.0, 5.638304088577984, 6.785456961280076, 5.638304088577984, 4.0])
y0 = np.array([0.0, 1.147152872702092, 2.7854569612800755, 4.423761049858059, 3.2766081771559668])
t0 = np.arange(len(x0)).astype(np.float64)
plt.plot(x0, y0)
vs = []
for e in (x0, y0):
a, b, c, d = calc_spline_params(t0, e)
x = np.linspace(0, t0[-1], 100)
vs.append(piece_wise_spline(x, t0, a, b, c, d))
plt.plot(vs[0], vs[1])
plt.show()
if __name__ == '__main__':
main()
Output:

Polynomial which satisfies integral and two points

Consider two points (x_0, f_0) and (x_1, f_1)
let p(x) be the degree two polynomial for which
p(x_0) = f_0
p(x_1) = f_1
and the integral of p(x) from -1 to 1 is equal to 0
Write a function which accepts two arguments
1. a length 2 NumPy vector 'x' of floating point values, with 'x[i]' containing the value of x_i,
2. a length 2 NumPy vector 'f' of floating point values, with 'f[i]' containing the value of f_i,
and which returns
a length 3 NumPy vector of floating point values containing the power series coefficients, in order from the highest order term to the constant term, for p(x)
I'm not sure where to start. My intial thought would be to have a differential equation P(1)=P(-1) with initial values p(x_0) = f_0 and p(x_1) = f_1, but I'm also having issues with the implementation.
Using sympy, Python's symbolic math library, the problem can be formulated as follows:
from sympy import symbols Eq, solve, integrate
def give_coeff(x, f):
a, b, c, X = symbols('a, b, c, X')
F = a * X * X + b * X + c # we have a second order polynomial
sol = solve([Eq(integrate(F, (X, -1, 1)), 0), # the integral should be zero (2/3*a + 2*c)
Eq(F.subs(X, x[0]), f[0]), # filling in x[0] should give f[0]
Eq(F.subs(X, x[1]), f[1])], # filling in x[1] should give f[1]
(a, b, c)) # solve for a, b and c
return sol[a].evalf(), sol[b].evalf(), sol[c].evalf()
import numpy as np
coeff = give_coeff(np.array([1, 2]), np.array([3, 4]))
print(coeff)
The code can even be expanded to polynomials of any degree:
from sympy import Eq, solve, symbols, integrate
def give_coeff(x, f):
assert len(x) == len(f), "x and f need to have the same length"
degree = len(x)
X = symbols('X')
a = [symbols(f'a_{i}') for i in range(degree + 1)]
F = 0
for ai in a[::-1]:
F = F * X + ai
sol = solve([Eq(integrate(F, (X, -1, 1)), 0)] +
[Eq(F.subs(X, xi), fi) for xi, fi in zip(x, f)],
(*a,))
# print(sol)
# print(F.subs(sol).expand())
return [sol[ai].evalf() for ai in a[::-1]]
import numpy as np
coeff = give_coeff(np.array([1, 2]), np.array([3, 4]))
print(coeff)
print(give_coeff(np.array([1, 2, 3, 4, 5]), np.array([3, 4, 6, 9, 1])))
PS: To solve the second degree equation only using numpy, np.linalg.solve can be used to solve the linear system of 3 unknowns with 3 equations. The equations need to be "hand calculated" which is are more error prone and more elaborated to extend to higher degrees.
import numpy as np
def np_give_coeff(x, f):
# general equation: F = a*X**2 + b*X + c
# 3 equations:
# integral (F, (X, -1, 1)) == 0 or (2/3*a + 2*c) == 0
# a*x[0]**2 + b*x[0] + c == f[0]
# a*x[1]**2 + b*x[1] + c == f[1]
A = np.array([[2/3, 0, 2],
[x[0]**2, x[0], 1],
[x[1]**2, x[1], 1]])
B = np.array([0, f[0], f[1]])
return np.linalg.solve(A, B)
coeff = np_give_coeff(np.array([1, 2]), np.array([3, 4]))
print(coeff)
You can solve this generically, taking advantage of the fact that
and adding that as a constraint. Then you have 3 equations for 3 unknowns (a, b, c).
There are other interesting tricks, it is a neat question. Try playing around with writing your formula in terms of a(x-b)(x-c), then you have 3bc + 1 = 0., also any solution starting with points (x0,y0),(x1,x1) has a similar solution for (k*x0,k*y0),(k*x1,k*y1).

Minimize system of nonlinear equation (integral on exponent)

General:
I am using maximum entropy to find distribution for on positive integers vectors, I can estimate the mean and variance, and have three equation I am trying to find a and b,
The equations:
integral(exp(a*x^2+bx+c) from (0 , infinity))-1
integral(xexp(ax^2+bx+c)from (0 , infinity))- mean
integral(x^2*exp(a*x^2+bx+c) from (0 , infinity))- mean^2 - var
(integrals between [0,∞))
The problem:
I am trying to use numerical solver and I used fsolve of sympy
But I guess I am missing some knowledge.
My code:
import numpy as np
import sympy as sym
from scipy.optimize import *
def myFunction(x,*data):
y = sym.symbols('y')
m,v=data
F = [0]*3
x[0] = - abs(x[0])
print(x)
F[0] = (sym.integrate(sym.exp(x[0] * y ** 2 + x[1] * y + x[2]), (y, 0,sym.oo)) -1).evalf()
F[1] = (sym.integrate(y*sym.exp(x[0] * y ** 2 + x[1] * y + x[2]), (y, 0,sym.oo))-m).evalf()
F[2] = (sym.integrate((y**2)*sym.exp(x[0] * y ** 2 + x[1] * y + x[2]), (y,0,sym.oo)) -v-m).evalf()
print(F)
return F
data = (10,3.5) # mean and var for example
xGuess = [1, 1, 1]
z = fsolve(myFunction,xGuess,args = data)
print(z)
my result are not that accurate, is there a better way to solve it?
integral(exp(a*x^2+bx+c))-1 = 5.67659292676884
integral(xexp(ax^2+bx+c))- mean = −1.32123173796713
integral(x^2*exp(a*x^2+bx+c))- mean^2 - var = −2.20825624606312
Thanks
I have rewritten the problem replacing sympy with numpy and lambdas (inline functions).
Also note that in your problem statement you subtract the third equation with $mean^2$, but in your code you only subtract $mean$.
import numpy as np
from scipy.optimize import minimize
from scipy.integrate import quad
def myFunction(x,data):
m,v=data
F = np.zeros(3) # use numpy array
# use scipy.integrade.quad for integration of lambda functions
# quad output is (result, error), so we just select the result value at the end
F[0] = quad(lambda y: np.exp(x[0] * y ** 2 + x[1] * y + x[2]), 0, np.inf)[0] -1
F[1] = quad(lambda y: y*np.exp(x[0] * y ** 2 + x[1] * y + x[2]), 0, np.inf)[0] -m
F[2] = quad(lambda y: (y**2)*np.exp(x[0] * y ** 2 + x[1] * y + x[2]), 0, np.inf)[0] -v-m**2
# minimize the squared error
return np.sum(F**2)
data = (10,3.5) # mean and var for example
xGuess = [-1, 1, 1]
z = minimize(lambda x: myFunction(x, data), x0=xGuess,
bounds=((None, 0), (None, None), (None, None))) # use bounds for negative first coefficient
print(z)
# x: array([-0.99899311, 2.18819689, 1.85313181])
Does this seem more reasonable?

Graphing Intergration in Python

In the following code I have implemented Simpsons Rule in Python. I have attempted to plot the absolute error as a function of n for a suitable range of integer values n. I know that the exact result should be 1-cos(pi/2). However my graph doesn't seem to be correct. How can I fix my code to get the correct output? there were two loops and I don't think I implemented my graph coding correctly
def simpson(f, a, b, n):
"""Approximates the definite integral of f from a to b by the composite Simpson's rule, using n subintervals (with n even)"""
h = (b - a) / (n)
s = f(a) + f(b)
diffs = {}
for i in range(1, n, 2):
s += 4 * f(a + i * h)
for i in range(2, n-1, 2):
s += 2 * f(a + i * h)
r = s
exact = 1 - cos(pi/2)
diff = abs(r - exact)
diffs[n] = diff
ordered = sorted(diffs.items())
x,y = zip(*ordered)
plt.autoscale()
plt.loglog(x,y)
plt.xlabel("Intervals")
plt.ylabel("Error")
plt.show()
return s * h / 3
simpson(lambda x: sin(x), 0.0, pi/2, 100)
Your simpson method should just calculate the integral for a single value of n (as it does), but creating the plot for many values of n should be outside that method. as:
from math import pi, cos, sin
from matplotlib import pyplot as plt
def simpson(f, a, b, n):
"""Approximates the definite integral of f from a to b by the composite Simpson's rule, using 2n subintervals """
h = (b - a) / (2*n)
s = f(a) + f(b)
for i in range(1, 2*n, 2):
s += 4 * f(a + i * h)
for i in range(2, 2*n-1, 2):
s += 2 * f(a + i * h)
return s * h / 3
diffs = {}
exact = 1 - cos(pi/2)
for n in range(1, 100):
result = simpson(lambda x: sin(x), 0.0, pi/2, n)
diffs[2*n] = abs(exact - result) # use 2*n or n here, your choice.
ordered = sorted(diffs.items())
x,y = zip(*ordered)
plt.autoscale()
plt.loglog(x,y)
plt.xlabel("Intervals")
plt.ylabel("Error")
plt.show()

Categories

Resources