Python: Plotting a infinite series by only taking finite points - python

I am trying to plot an infinite series by taking only a finite amount of points. In my case, 3 and 10 points are sufficient.
The equation is the Lagrange power series in e the eccentricity.
E = Me + \sum_{n = 1}^{\infty}a_n e ** n
where a_n is
a_n = (1 / 2 ** (n - 1) * \sum_{k = 0}^{\lfloor n/2\rfloor} (-1) ** k /
((n - 2 * k)! * k!) * (n - 2 * k) ** (n - 1) * np.sin((n - 2 * k) * Me))
So \lfloor n/2\rfloor is latex for the floor function of n/2.
The independent variable is E and dependent Me so the function is not written as one would normal encounter such functions but I don't see a way to explicitly solve for Me so that we could write Me(E)
So what I have done so far is (see below) which is wrong since it doesn't work. What can I do get the code and plot working?
import numpy as np
import pylab as py
import math
from scipy.misc import factorial as fact
Me = np.linspace(0, 2 * np.pi, 50000.0)
e = 0.65
a = [1.0 / 2.0 ** (math.floor(n / 2.0) - 1.0) *
sum([(-1.0) ** math.floor(n / 2.0) /
(fact(math.floor(n / 2.0) - k) * fact(k)) *
(math.floor(n / 2.0) - 2.0 * k) ** (math.floor(n / 2.0) - 1.0) *
np.sin((math.floor(n / 2.0) - 2.0 * k) * Me)
for k in range(1, 4, 1)])
for n in range (1, 4, 1)]
print a
def E2(x):
return Me + sum(a[n] * e ** n for n in range(1, 4, 1)) - x
fig = py.figure()
ax = fig.add_subplot(111)
ax.plot(Me, E2(Me))
py.xlim((0, 2 * np.pi))
py.ylim((0, 2 * np.pi))
py.show()
With this program, I am getting
In [2]: /usr/bin/ipython:17: RuntimeWarning: divide by zero encountered in double_\
scalars
/usr/bin/ipython:17: RuntimeWarning: invalid value encountered in multiply
/usr/bin/ipython:17: RuntimeWarning: invalid value encountered in add
[array([ nan, inf, inf, ..., -inf, -inf, -inf]), array([ nan, inf, inf, ..., -\
inf, -inf, -inf]), array([ nan, inf, inf, ..., -inf, -inf, -inf])]
Infinity shouldn't be a value at all so I am not sure how that is being derived.
The final error is list of index out of range
/home/dustin/Documents/School/UVM/Engineering/OrbitalMechanics/lagrangeseries.py i\
n <genexpr>((n,))
17
18 def E2(x):
---> 19 return Me + sum(a[n] * e ** n for n in range(1, 4, 1)) - x
20
21 fig = py.figure()
IndexError: list index out of range
How is this out of range? Everything is summing from 1 to 3?

I didn't need to use the floor function due to the way division works in Python.
import numpy as np
import pylab as py
from scipy.misc import factorial as fact
e = 0.65
def E(M):
return (M + sum((1.0 / 2.0 ** (n - 1) *
sum((-1) ** (k) / (fact(n - k) * fact(k)) *
(n - 2 * k) ** (n - 1) *
np.sin((n - 2 * k) * M)
for k in range(0, n / 2, 1))) * e ** n
for n in range(1, 4, 1)))
M = np.linspace(0, 2 * np.pi, 50000.0)
fig = py.figure()
ax = fig.add_subplot(111)
ax.plot(E(M), M)
py.xlim((0, 2 * np.pi))
py.ylim((0, 2 * np.pi))
py.show()

the indices in the range values should be increased by one for the k counter, so instead of:
for k in range(0, n / 2, 1)
it should be:
for k in range(0, n / 2+1, 1)
otherwise for n =4 range(0, 2, 1) returns 0,1 and not 0,1,2 as needed.

Related

Finding roots of an equation involving a summation using sympy

I am currently to new to sympy and I am trying to reproduce the Mathematica example in the attached image in Python. My attempt is written below but it returns an empty list
import sympy
m , n, D_star, a, j = sympy.symbols('m , n, D_star, a, j')
s1 = sympy.Sum(a**(j-1),(j, 1, m-1))
rhs = 6 * sympy.sqrt((D_star * (1 + a)*(n - 1))/2)
expand_expr = sympy.solve(s1 - rhs, m)
temp = sympy.lambdify((a, n, D_star), expand_expr, 'numpy')
n = 100
a = 1.2
D_star = 2.0
ms = temp(1.2, 100, 2.0)
ms
# what I get is an empty list []
# expected answer using Mma FindRoot function is 17.0652
Adding .doit() to expand the sum seems to help. It gives Piecewise((m - 1, Eq(a, 1)), ((a - a**m)/(1 - a), True))/a for the sum in s1.
from sympy import symbols, Eq, Sum, sqrt, solve, lambdify
m, n, j, a, D_star = symbols('m n j a D_star')
s1 = Sum(a**(j - 1), (j, 1, m - 1)).doit()
rhs = 6 * sqrt((D_star * (1 + a) * (n - 1)) / 2)
expand_expr = solve(Eq(s1, rhs), m)
temp = lambdify((a, n, D_star), expand_expr, 'numpy')
n = 100
a = 1.2
D_star = 2.0
ms = temp(1.2, 100, 2.0)
This gives for expand_expr:
[Piecewise((log(a*(3*sqrt(2)*a*sqrt(D_star*(a*n - a + n - 1)) - 3*sqrt(2)*sqrt(D_star*(a*n - a + n - 1)) + 1))/log(a), Ne(a, 1)), (nan, True)),
Piecewise((3*sqrt(2)*a*sqrt(D_star*(a*n - a + n - 1)) + 1, Eq(a, 1)), (nan, True))]
which separates into a != 1 and a == 1.
The result of ms gives [array(17.06524172), array(nan)], again in a bit awkward way to separate a hypothetical a == 1.

Integrate Over Multiple Columns in 1 List to Fill Additional List With Same Number Of Columns

I am intending to take a list of random variables and alter a previous list in each column by said random variables. However, for the purpose of my function, each variable must be used in a Gamma function as well as integrated.
x[t] = c * (1 / (2 ** (v / 2) + test[t - 1]) * (gamma((v / 2) + test[t - 1]))) * integrate.\
quad(lambda h: np.exp(-h / 2) * h ** ((v / 2) + test[t - 1] - 1), 0, np.inf)
x[ t ] is an np.zeros((x , y)) list, and test[t - 1] is an np.zeros((x - 1, y)) list
I have filled test[ ] with the appropriate random variables, but I am unable to pass them through this equation to complete the columns of row [ t ] in x
When I try to run my current code, I receive:
File "C:\Program Files (x86)\Microsoft Visual Studio\Shared\Python37_64\lib\site-packages\scipy\integrate\quadpack.py", line 450, in _quad
return _quadpack._qagie(func,bound,infbounds,args,full_output,epsabs,epsrel,limit)
TypeError: only size-1 arrays can be converted to Python scalars
Is there a different special function which allows me to use each column's variable to solve for my desired x[ t ]?
import numpy as np
import matplotlib.pyplot as plt
from scipy.stats import stats
import mpmath as mp
import scipy.integrate as integrate
from scipy.special import gamma
T = 1
beta = 0.5
x0 = 0.05
q = 0
mu = x0 - q
alpha = - (2 - beta) * mu
sigma0 = 0.1
sigma = (2 - beta) * sigma0
b = - ((1 - beta) / (2 * mu) * (sigma0 ** 2))
simulations = 100
M = 50
dt = T / M
def srd_sampled_nxc2():
x = np.zeros((M + 1, simulations))
x[0] = x0
test = np.zeros((M, simulations))
for t in range(1, M + 1):
v = 4 * b * alpha / sigma ** 2
c = (sigma ** 2 * (1 - np.exp(-alpha * dt))) / (4 * alpha)
nc = np.exp(-alpha * dt) / c * x[t - 1]
if v > 1:
x[t] = c * ((np.random.standard_normal(simulations) + nc ** 0.5) ** 2 + mp.nsum(
lambda i: np.random.standard_normal(simulations) ** 2, [0, v - 1]))
else:
max_array = []
nc_over_2 = [l / 2 for l in nc]
for p in range(simulations):
sump = []
poisson_start = 0
while poisson_start <= 1:
x_i = sum(-np.log(np.random.uniform(0, 1, simulations)) / nc_over_2)
sump.append(
x_i
)
poisson_start += x_i
x_n = max(sump)
max_array.append(
x_n
)
sump = []
test[t - 1] = max_array
x[t] = c * (1 / (2 ** ((v / 2) + test[t - 1])) * (gamma((v / 2) + test[t - 1]))) * integrate.\
quad(lambda h: np.exp(-h / 2) * h ** ((v / 2) + test[t - 1] - 1), 0, np.inf)
max_array = []
return x
Ultimately ended up finding a workaround which is simple to implement:
else:
max_array = []
for p in range(simulations):
k = nc[t - 1, p]
lam = k / 2
poisson_samp = 0
while poisson_samp <= 1:
x_i = -math.log(np.random.uniform(0, 1)) / lam
max_array.append(
x_i
)
poisson_samp += x_i
test[t - 1, p] = len(max_array) - 1
max_array.clear()
for f in range(simulations):
n = test[t - 1, f]
z = integrate.quad(lambda h: np.exp(-h / 2) * h ** ((v / 2) + n - 1), 0, 1)
new[t - 1, f] = z[0]
x[t] = c * (1 / (2 ** ((v / 2) + test[t - 1]) * (gamma((v / 2) + test[t - 1]))) * new[0])
The only real problem is the shrinkage of x[t] which leads to dividing by zero--just a formula problem.

Finding a value in an equation

i`m looking for an easy way to find the value of a variable depending on the result of another one:
import numpy as np
import matplotlib.pyplot as plt
T = np.arange(0.01, 4.5, 0.0001)
N = (2.63 * 10 ** -16) * ((2.71828 ** (6.93 * T)) - 1) + ((4.05 * 10 ** -6) * T)
plt.plot(N,T)
plt.axis(xmin=-0.001, ymax=5)
plt.show()
For example I need the value of T for N= 0,00006762 (Or the closest value). This would be easy if I could solve for T, but I find it easier to create an array of the possible T`s and try the other way.
You can loop over values of T, calculate N, and compare it with the number you are looking for (0.00006762), and return the closest one you find:
target = 0.00006762
smallest_diff = 1000
best_answer = 'NA'
for T in np.arange(0.01, 4.5, 0.0001):
N = (2.63 * 10 ** -16) * ((2.71828 ** (6.93 * T)) - 1) + ((4.05 * 10 ** -6) * T)
if abs(N - target) < smallest_dif:
smallest_diff = abs(N - target)
best_answer = T
print(best_answer)

Fitting data with a custom distribution using scipy.stats

So I noticed that there is no implementation of the Skewed generalized t distribution in scipy. It would be useful for me to fit this is distribution to some data I have. Unfortunately fit doesn't seem to be working in this case for me. To explain further I have implemented it like so
import numpy as np
import pandas as pd
import scipy.stats as st
from scipy.special import beta
class sgt(st.rv_continuous):
def _pdf(self, x, mu, sigma, lam, p, q):
v = q ** (-1 / p) * \
((3 * lam ** 2 + 1) * (
beta(3 / p, q - 2 / p) / beta(1 / p, q)) - 4 * lam ** 2 *
(beta(2 / p, q - 1 / p) / beta(1 / p, q)) ** 2) ** (-1 / 2)
m = 2 * v * sigma * lam * q ** (1 / p) * beta(2 / p, q - 1 / p) / beta(
1 / p, q)
fx = p / (2 * v * sigma * q ** (1 / p) * beta(1 / p, q) * (
abs(x - mu + m) ** p / (q * (v * sigma) ** p) * (
lam * np.sign(x - mu + m) + 1) ** p + 1) ** (
1 / p + q))
return fx
def _argcheck(self, mu, sigma, lam, p, q):
s = sigma > 0
l = -1 < lam < 1
p_bool = p > 0
q_bool = q > 0
all_bool = s & l & p_bool & q_bool
return all_bool
This all works fine and I can generate random variables with given parameters no problem. The _argcheck is required as a simple positive params only check is not suitable.
sgt_inst = sgt(name='sgt')
vars = sgt_inst.rvs(mu=1, sigma=3, lam = -0.1, p = 2, q = 50, size = 100)
However, when I try fit these parameters I get an error
sgt_inst.fit(vars)
RuntimeWarning: invalid value encountered in subtract
numpy.max(numpy.abs(fsim[0] - fsim[1:])) <= fatol):
and it just returns
What I find strange is that when I implement the example custom Gaussian distribution as shown in the docs, it has no problem running the fit method.
Any ideas?
As fit docstring says,
Starting estimates for the fit are given by input arguments; for any arguments not provided with starting estimates, self._fitstart(data) is called to generate such.
Calling sgt_inst._fitstart(data) returns (1.0, 1.0, 1.0, 1.0, 1.0, 0, 1) (the first five are shape parameters, the last two are loc and scale). Looks like _fitstart is not a sophisticated process. The parameter l it picks does not meet your argcheck requirement.
Conclusion: provide your own starting parameters for fit, e.g.,
sgt_inst.fit(data, 0.5, 0.5, -0.5, 2, 10)
returns (1.4587093459289049, 5.471769032259468, -0.02391466905874927, 7.07289326147152
4, 0.741434497805832, -0.07012808188413872, 0.5308181287869771) for my random data.

using fsolve to find the solution

import numpy as np
from scipy.optimize import fsolve
musun = 132712000000
T = 365.25 * 86400 * 2 / 3
e = 581.2392124070273
def f(x):
return ((T * musun ** 2 / (2 * np.pi)) ** (1 / 3) * np.sqrt(1 - x ** 2)
- np.sqrt(.5 * musun ** 2 / e * (1 - x ** 2)))
x = fsolve(f, 0.01)
f(x)
print x
What is wrong with this code? It seems to not work.
Because sqrt returns NaN for negative argument, your function f(x) is not calculable for all real x. I changed your function to use numpy.emath.sqrt() which can output complex values when the argument < 0, and returns the absolute value of the expression.
import numpy as np
from scipy.optimize import fsolve
sqrt = np.emath.sqrt
musun = 132712000000
T = 365.25 * 86400 * 2 / 3
e = 581.2392124070273
def f(x):
return np.abs((T * musun ** 2 / (2 * np.pi)) ** (1 / 3) * sqrt(1 - x ** 2)
- sqrt(.5 * musun ** 2 / e * (1 - x ** 2)))
x = fsolve(f, 0.01)
x, f(x)
Then you can get the right result:
(array([ 1.]), array([ 121341.22302275]))
the solution is very close to the true root, but f(x) is still very large because f(x) has a very large factor: musun.
fsolve() returns the roots of f(x) = 0 (see here).
When I plotted the values of f(x) for x in the range -1 to 1, I found that there are roots at x = -1 and x = 1. However, if x > 1 or x < -1, both of the sqrt() functions will be passed a negative argument, which causes the error invalid value encountered in sqrt.
It doesn't surprise me that fsolve() fails to find roots that are at the very ends of the valid range for the function.
I find that it is always a good idea to plot the graph of a function before trying to find its roots, as that can indicate how likely (or in this case, unlikely) it is that the roots will be found by any root-finding algorithm.

Categories

Resources