How to print all polynomials up to Pn+1(x) - python

This is an exercise where you use the polynomial routines in numpy to generate the Legendre polynomials recursively.
I have finished every part except for printing all the polynomials up to Pn+1(x). How can I add a line to achieve this goal. Someone, please help !!!
import numpy as np
import matplotlib.pyplot as plt
from scipy import integrate
def P(n, x):
if(n == 0):
return 1 # P0 = 1
elif(n == 1):
return x # P1 = x
else:
return N_f(n) * x * P(n - 1, x) + alpha_f(n)*P(n-2, x)
def norm_f(x, n):
return P(n-1, x) * P(n-1, x)
def overlap_f(x, n):
return x*P(n, x) * P(n-1, x)
def alpha_f(n):
return -(n-1)/float(n)
def N_f(n):
return ((2 * n)-1)/float(n)
def norm_n(n):
return integrate.quad(norm_f(n), -1, 1)
def overlap_n(n):
return integrate.quad(overlap_f(n), -1, 1)
max_n = int(input('input the max n: '))
# Creating an array of x values
X = np.linspace(-1, 1, 200)
x = np.linspace(-1, 1, 200)
for i in range(1, 7):
plt.plot(x, P(i, x), label="P" + str(i))
plt.legend(loc="best")
plt.xlabel("X")
plt.ylabel("Pn")
plt.savefig('plot_legend.png')
plt.show()

Related

Numpy - vectorize the bivariate poisson pmf equation

I'm trying to write a function to evaluate the probability mass function for the bivariate poisson distribution.
This is easy when all of the parameters (x, y, theta1, theta2, theta0) are scalars, but tricky to scale up without loops to allow these parameters to be vectors. I need it to scale such that, for:
theta0 being a scalar - the "correlation parameter" in the equation
theta1 and theta2 having length l
x, y both having length n
the output array would have shape (l, n, n). For example, a slice [j, :, :] from the output array would look like:
The first part (the constant, before the summation) I think i've figured out:
import numpy as np
from scipy.special import factorial
def constant(theta1, theta2, theta0, x, y):
exponential_part = np.exp(-(theta1 + theta2 + theta0)).reshape(-1, 1, 1)
x = np.tile(x, (len(x), 1)).transpose()
y = np.tile(y, (len(y), 1))
double_factorial = (np.power(np.array(theta1).reshape(-1, 1, 1), x)/factorial(x)) * \
(np.power(np.array(theta2).reshape(-1, 1, 1), y)/factorial(y))
return exponential_part * double_factorial
But I'm struggling with the summation part. How can I vectorize a summation where the limits depend on variable arrays?
I think I have this figured out, based on the approach that #w-m suggests: calculate every possible summation term which could appear, based on the maximum x or y value which appears, and use a mask to get rid of the ones you don't want. Assuming you have your x and y terms go from 0 to N, in consecutive order, this is calculating up to three times more terms than are actually required, but this is offset by getting to use vectorization.
Reference implementation
I wrote this by first writing a pure-Python reference implementation, which just implements your problem using loops. With 4 nested loops, it's not exactly fast, but it's handy to have while testing the numpy version.
import numpy as np
from scipy.special import factorial, comb
import operator as op
from functools import reduce
def choose(n, r):
# https://stackoverflow.com/a/4941932/530160
r = min(r, n-r)
numer = reduce(op.mul, range(n, n-r, -1), 1)
denom = reduce(op.mul, range(1, r+1), 1)
return numer // denom # or / in Python 2
def reference_impl_constant(s_theta1, s_theta2, s_theta0, s_x, s_y):
# Cast to float to prevent overflow
s_theta1 = float(s_theta1)
s_theta2 = float(s_theta2)
s_theta0 = float(s_theta0)
s_x = float(s_x)
s_y = float(s_y)
term1 = np.exp(-(s_theta1 + s_theta2 + s_theta0))
term2 = (s_theta1 ** s_x / factorial(s_x))
term3 = (s_theta2 ** s_y / factorial(s_y))
assert term1 >= 0
assert term2 >= 0
assert term3 >= 0
return term1 * term2 * term3
def reference_impl_constant_loop(theta1, theta2, theta0, x, y):
theta_len = theta1.shape[0]
xy_len = x.shape[0]
constant_array = np.zeros((theta_len, xy_len, xy_len))
for i in range(theta_len):
for j in range(xy_len):
for k in range(xy_len):
s_theta1 = theta1[i]
s_theta2 = theta2[i]
s_theta0 = theta0
s_x = x[j]
s_y = y[k]
constant_term = reference_impl_constant(s_theta1, s_theta2, s_theta0, s_x, s_y)
assert constant_term >= 0
constant_array[i, j, k] = constant_term
return constant_array
def reference_impl_summation(s_theta1, s_theta2, s_theta0, s_x, s_y):
sum_ = 0
for i in range(min(s_x, s_y) + 1):
sum_ += choose(s_x, i) * choose(s_y, i) * factorial(i) * ((s_theta0/s_theta1/s_theta2) ** i)
assert sum_ >= 0
return sum_
def reference_impl_summation_loop(theta1, theta2, theta0, x, y):
theta_len = theta1.shape[0]
xy_len = x.shape[0]
summation_array = np.zeros((theta_len, xy_len, xy_len))
for i in range(theta_len):
for j in range(xy_len):
for k in range(xy_len):
s_theta1 = theta1[i]
s_theta2 = theta2[i]
s_theta0 = theta0
s_x = x[j]
s_y = y[k]
summation_term = reference_impl_summation(s_theta1, s_theta2, s_theta0, s_x, s_y)
assert summation_term >= 0
summation_array[i, j, k] = summation_term
return summation_array
def reference_impl(theta1, theta2, theta0, x, y):
# all array inputs must be 1D
assert len(theta1.shape) == 1
assert len(theta2.shape) == 1
assert len(x.shape) == 1
assert len(y.shape) == 1
# theta vectors must have same length
theta_len = theta1.shape[0]
assert theta2.shape[0] == theta_len
# x and y must have same length
xy_len = x.shape[0]
assert y.shape[0] == xy_len
# theta0 is scalar
assert isinstance(theta0, (int, float))
constant_array = np.zeros((theta_len, xy_len, xy_len))
output = np.zeros((theta_len, xy_len, xy_len))
constant_array = reference_impl_constant_loop(theta1, theta2, theta0, x, y)
summation_array = reference_impl_summation_loop(theta1, theta2, theta0, x, y)
output = constant_array * summation_array
return output
Numpy implementation
I split the implementation of this across two functions.
The fast_constant() function calculates everything to the left of the summation symbol. The fast_summation() function calculates everything inside the summation symbol.
import numpy as np
from scipy.special import factorial, comb
def fast_summation(theta1, theta2, theta0, x, y):
x = np.tile(x, (len(x), 1)).transpose()
y = np.tile(y, (len(y), 1))
sum_limit = np.minimum(x, y)
max_sum_limit = np.max(sum_limit)
i = np.arange(max_sum_limit + 1).reshape(-1, 1, 1)
summation_mask = (i <= sum_limit)
theta_ratio = (theta0 / (theta1 * theta2)).reshape(-1, 1, 1, 1)
theta_to_power = np.power(theta_ratio, i)
terms = comb(x, i) * comb(y, i) * factorial(i) * theta_to_power
# mask out terms which aren't part of sum
terms *= summation_mask
# axis 0 is theta
# axis 1 is i
# axis 2 & 3 are x and y
# so sum across axis 1
terms = terms.sum(axis=1)
return terms
def fast_constant(theta1, theta2, theta0, x, y):
theta1 = theta1.astype('float64')
theta2 = theta2.astype('float64')
exponential_part = np.exp(-(theta1 + theta2 + theta0)).reshape(-1, 1, 1)
# x and y must be 1D
assert len(x.shape) == 1
assert len(y.shape) == 1
# x and y must have same shape
assert x.shape == y.shape
x_len, y_len = x.shape[0], y.shape[0]
x = x.reshape((x_len, 1))
y = y.reshape((1, y_len))
double_factorial = (np.power(np.array(theta1).reshape(-1, 1, 1), x)/factorial(x)) * \
(np.power(np.array(theta2).reshape(-1, 1, 1), y)/factorial(y))
return exponential_part * double_factorial
def fast_impl(theta1, theta2, theta0, x, y):
return fast_summation(theta1, theta2, theta0, x, y) * fast_constant(theta1, theta2, theta0, x, y)
Benchmarking
Assuming that X and Y range from 0 to 20, and that theta is centered somewhere inside that range, I get the result that the numpy version is roughly 280 times faster than the pure python reference.
Numerical stability
I'm unsure how numerically stable this is. For example, when I center theta at 100, I get a floating-point overflow. Typically, when computing an expression which has lots of choose and factorial expressions inside it, you'll use some mathematical equivalent which results in smaller intermediate sums. In this case I have so little understanding of the math that I don't know how you'd do that.

Reason for "Maximum recursion error" in Python

I wrote this program describing an algorithm for the simulation of a partial differential equation. The basic functions I use are defined by
import numpy as np
import math
from scipy import integrate, stats
def shift(func, x, a=0):
return func(x-a)
def scale(func, a=1):
return a*func
def trunc(func, x):
if x <= 0:
return 0
else:
return func(x)
def quad(func, a, b):
return integrate.quad(func, a, b)
def gauss(func, t, x):
def pregau(z):
k = (-t ** (1 / 2)) * z
return shift(func, x, k)*math.exp(-(z**2)/2)
fa = (1 / ((2 * math.pi) ** (1 / 2)) * integrate.quad(pregau, -np.inf, np.inf)[0])
return fa
The program then simulates the solution to the partial differential equation by
def vundl(x, u, l0=0.0, a=a, b=b, c=c):
v = [u(x)]
l = [l0]
f_temp_rec = u
for i in range(10):
def f_temp(x):
y = x - c * dt + B[i + 1] * 2 * a
z = b * dt
return gauss(f_temp_rec, z, y)
li = l[i] + quad(f_temp, 0, np.inf)[0]
l = np.append(l, li)
if x <= 0:
v = np.append(v, 0)
f_temp_rec = 0
else:
f_temp_rec = f_temp
v = np.append(v, f_temp(x))
return [v, l]
def u0(x):
return stats.beta.pdf(x, 2.7, 3.05)
print(vundl(x = 0.5, u0))
If I run this program for N=0 it produces a vector. Running the program for N>0 gives me the following error:
"RecursionError: maximum recursion depth exceeded"
but it actually should give me a vector v and a vector l.
I'm not sure exactly what you're trying to do in vundl with f_temp and f_temp_rec, but in the else: block you assign:
f_temp_rec = f_temp
and then call f_temp which calls gauss(f_temp_rec, z, y). Since at this point f_temp_rec is f_temp the function f_temp calls itself in an infinite recursion.
You should be able to see in in traceback that f_temp is calling itself repeatedly.

Graphing diagram In Python

In the following code I have implemented Newtons method in Python.
import math
def Newton(f, dfdx, x, eps):
f_value = f(x)
iteration_counter = 0
while abs(f_value) > eps and iteration_counter < 100:
try:
x = x - float(f_value)/dfdx(x)
except ZeroDivisionError:
print ("Error! - derivative zero for x = ", x)
sys.exit(1) # Abort with error
f_value = f(x)
iteration_counter += 1
# Here, either a solution is found, or too many iterations
if abs(f_value) > eps:
iteration_counter = -1
return x, iteration_counter
def f(x):
return (math.cos(x)-math.sin(x))
def dfdx(x):
return (-math.sin(x)-math.cos(x))
solution, no_iterations = Newton(f, dfdx, x=1, eps=1.0e-14)
if no_iterations > 0: # Solution found
print ("Number of function calls: %d" % (1 + 2*no_iterations))
print ("A solution is: %f" % (solution))
else:
print ("Solution not found!")
However now I am looking to plot the convergence diagram on that same interval. This would be the absolute error as a function of the number of iterations on the interval [0,1]. Meaning the number of iterations on the x axis with the corresponding absolute error on the y axis
I attempted to make an iterable that each time yields a 2-tuple with the absolute error, and the iteration. Here is my code below, with the output and graph. Is my output correct? should the graph look like this? All help is greatly appreciated! The number of iterations from my code is 3
import math
def Newton(f, dfdx, x, eps):
f_value = f(x)
iteration_counter = 0
while abs(f_value) > eps and iteration_counter < 100:
try:
x = x - float(f_value)/dfdx(x)
yield iteration_counter, abs(f(x))
except ZeroDivisionError:
print ("Error! - derivative zero for x = ", x)
sys.exit(1) # Abort with error
f_value = f(x)
iteration_counter += 1
# Here, either a solution is found, or too many iterations
if abs(f_value) > eps:
iteration_counter = -1
return x, iteration_counter
def f(x):
return (math.cos(x)-math.sin(x))
def dfdx(x):
return (-math.sin(x)-math.cos(x))
import numpy as np
np.array(list(Newton(f,dfdx, 1,10e-4)))
which produces the following output:
array([[0.00000000e+00, 4.74646213e-03],
[1.00000000e+00, 1.78222779e-08]])
and finally:
import numpy as np
import matplotlib.pyplot as plt
data = np.array(list(Newton(f,dfdx, 1, 10e-14)))
plt.plot(data[:,0], data[:,1])
plt.yscale('log')
plt.show()
which produces the graph:
Your Newton function shouldn't yield and return at the same time
Use a more slowly converging function to test your results
This is what I would do:
import math
import sys
import numpy as np
import matplotlib.pyplot as plt
def newton(f, dfdx, x, eps):
f_value = f(x)
iteration_counter = 0
while abs(f_value) > eps and iteration_counter < 100:
try:
x = x - float(f_value)/dfdx(x)
yield iteration_counter, x, abs(f(x))
except ZeroDivisionError:
print ("Error! - derivative zero for x = ", x)
sys.exit(1) # Abort with error
f_value = f(x)
iteration_counter += 1
def f(x):
return x ** 2 - 1.34
def dfdx(x):
return 2 * x
data = np.array(list(newton(f, dfdx, 10, 10e-14)))
# plt.plot(data[:, 0], data[:, 1]) # x-axis: iteration, y-axis: x values
plt.plot(data[:, 0], data[:, 2]) # x-axis: iteration, y-axis: f(x) values
plt.yscale('log')
plt.show()

How do I solve expressions in python such as f1(x) = f2(x)?

import math
import pylab
import sympy
def f1(x):
"""function representing a cosine variant function and returned"""
return math.cos(2 * math.pi * x) * math.exp(-x ** 2)
def f2(x):
"""function representing a log variant function and returned"""
return math.log(x + 2.2)
def positive_places(f, xs):
"""return a list of elements of xs that are positive when operated in by
f"""
list1 = []
for i in xs:
if f(i) > 0:
list1.append(i)
return list1
def create_plot_data(f, xmin, xmax, n):
"""returns a tuple (xs, ys) where xs and ys are two sequences,
each containing n numbers"""
xs = [xmin + i * ((xmax - xmin) / (n - 1)) for i in range(n)]
ys = [f(xs[i]) for i in range(n)]
return (xs, ys)
def myplot():
"""plots a graph of f1() and returns the graph"""
print(create_plot_data(f1, -2, 2, 1001))
(a1, b1) = create_plot_data(f1, -2, 2, 1001)
(a2, b2) = create_plot_data(f2, -2, 2, 1001)
pylab.plot(a1, b1, label='f1(x)')
pylab.plot(a2, b2, label='f2(x)')
pylab.xlabel('x')
pylab.ylabel('y')
pylab.legend()
pylab.grid()
pylab.savefig('plot.pdf')
pylab.savefig('plot.png')
pylab.show()
def find_cross():
return sympy.solve(math.cos(2 * math.pi * x) * math.exp(-x ** 2) - math.log(x + 2.2), x)
`
Hi im trying to define a function that will find the positive x value point where 2 equations are equal: f1(x) = f2(x)
f1(x) = math.cos(2 * math.pi * x) * math.e ** (-x ** 2)
f2(x) = math.log(x + 2.2)
for the point between x = 0 and x = 0.5
When using SymPy you can take advantage of mpmath's root finder ability to work with arbitrary many digits:
import mpmath
import sympy as sy
sy.init_printing()
mpmath.mp.dps = 30 # accuracy of 30 digits
# declare expressions:
x = sy.Symbol('x', real=True)
f1 = sy.cos(2*sy.pi*x) * sy.exp(-x**2)
f2 = sy.log(x + sy.Rational(22, 10))
g = f2 - f1 # f1 == f2 is equivalent to g == 0:
dg = g.diff(x) # 1. derivative needed by numeric root-finder
# generate numeric functions from SymPy expressions:
g_m, dg_m = (sy.lambdify(x, f_, modules="mpmath") for f_ in (g, dg))
# find the roots:
x_sln = mpmath.findroot(g_m, [0, 0.5], solver='secant', df=dg)
print("Intersection f1(x) == f2(x) is at x = {}".format(x_sln))
# => Intersection f1(x) == f2(x) is at x = 0.0922612383093564032487110560683
Note that mixing SymPy, math (and NumPy) functions can have unwanted side effects.

Lagrange Interpolation In Python - Won't Print out

This is the problem I have to solve:
Write a program to evaluate and plot the Lagrange interpolant Iu(x) of u(x) = 1/(1+x^2) for x between -5 and 5. Do this for 5,7,9,11,13,15 point interpolants (5,7,9 etc. data points between, and including, -5 and 5). Your results should show both the function and the interpolant.
This is the code I have come up with so far:
import numpy as np
import matplotlib.pyplot as plt
def L_k(x, k, xp, yp):
ans = 1
for i in range(len(xp)):
if i != k:
ans *= (x - xp[i]) / (xp[k] - xp[i])
return ans
def p_L(x, xp, yp):
ans = 0
for k in range(len(yp)):
ans += yp[k] * L_k(x, k, xp, yp)
return ans
def verify(xp, yp):
status = 'Verified!'
for k in range(len(xp)):
if abs(p_L(xp[k], xp, yp) - yp[k]) > 1e-15:
status = 'Error!'
break
print (status)
def verbose_verify(xp, yp):
print ('x', 'Exact', 'Approx', 'Difference')
for k in range(len(xp)):
x = xp[k]
exact = yp[k]
approx = p_L(xp[k], xp, yp)
diff = abs(p_L(xp[k], xp, yp) - yp[k])
print (x, exact, approx, diff)
def graph(f, n, xmin, xmax, resolution=1001):
xlist = np.linspace(xmin, xmax, n)
ylist = f(xlist)
xlist_fine = np.linspace(xmin, xmax, resolution)
ylist_fine = p_L(xlist_fine, xlist, ylist)
plt.plot(xlist, ylist, 'ro')
plt.plot(xlist_fine, ylist_fine)
def annotate_graph():
ax = plt.gca()
ax.set_xlabel('x')
ax.set_ylabel('f(x)')
ax.legend(['f(x)', 'Interpolated'])
if __name__ == '__main__':
xlist = np.linspace(0, np.pi, 5)
ylist = np.sin(xlist)
verbose_verify(xlist, ylist)
graph(np.sin, 5, 0, np.pi)
annotate_graph()
plt.show()
However it is not printing anything out. No error come up, there's just no output. What am I doing wrong?

Categories