Summing two Poisson distributions with SymPy - sympy

I'm new to SymPy and I'm trying to use it to sum two Poisson distributions
Here's what I have so far (using jupyter notebook)
from sympy import *
from sympy.stats import *
init_printing(use_latex='mathjax')
lamda_1, lamda_2 = symbols('lamda_1, lamda_2')
n_1 = Symbol('n_1')
n_2 = Symbol('n_2')
n = Symbol('n')
#setting up distributions
N_1 = density(Poisson('N_1', lamda_1))(n_1)
N_2 = density(Poisson('N_2', lamda_2))(n_2)
display(N_1)
display(N_2)
print('setting N_2 in terms of N and N_1')
N_2 = N_2.subs(n_2,n-n_1)
display(N_2)
print("N_1 * N_2")
N = N_1 * N_2
#display(N)
Sum(N,(n_1,0,n))
#summation(N,(n_1,0,n))
Everything works fine until I try and run the summation. No errors just doesn't do anything and jupyter says it's running. I've let it run for 10 mins and nothing...

When declaring symbols, include their properties: being positive, integer, nonnegative, etc. This helps SymPy decide whether some transformations are legitimate.
lamda_1, lamda_2 = symbols('lamda_1, lamda_2', positive=True)
n_1, n_2, n = symbols('n_1 n_2 n', nonnegative=True, integer=True)
Unfortunately, summation still fails because SymPy cannot come up with the key trick: multiplying and dividing by factorial(n). It seems one has to tell it to do that.
s = summation(N*factorial(n), (n_1, 0, n))/factorial(n)
print(s.simplify())
This prints
Piecewise(((lamda_1 + lamda_2)**n*exp(-lamda_1 - lamda_2)/factorial(n), ((-n >= 0) & (lamda_1/lamda_2 <= 1)) | ((-n < 0) & (lamda_1/lamda_2 <= 1))), (lamda_2**n*exp(-lamda_1 - lamda_2)*Sum(lamda_1**n_1*lamda_2**(-n_1)/(factorial(n_1)*factorial(n - n_1)), (n_1, 0, n)), True))
which is a piecewise formula full of unnecessary conditions... but if we ignore those conditions (they are just artifacts of how SymPy performed the summation), the correct result
((lamda_1 + lamda_2)**n*exp(-lamda_1 - lamda_2)/factorial(n)
is there.
Aside: avoid doing import * from both sympy and sympy.stats, there are notational clashes such as E being 2.718... versus expected value. from sympy.stats import density, Poisson would be better. Also, N is a built-in SymPy function and is best avoided as a variable name.

Related

Sympy can't solve inequality with radicals

I need to solve this inequality:
enter image description here
import sympy as sp
from sympy.abc import x,n
epsilon = 0.01
a = 2/3
xn = (n**3 + n**2)**(1/3) - (n**3 - n**2)**(1/3)
i tried to solve it like this:
ans = sp.solve_univariate_inequality(sp.Abs(xn-a) < epsilon,n,relational=False)
but received:
NotImplementedError: The inequality, Abs((x3 -
x2)0.333333333333333 - (x3 + x**2)**0.333333333333333 + 2/3) <
0.01, cannot be solved using solve_univariate_inequality.
And tried so, but it didn't work
ans = sp.solve_poly_inequality(sp.Poly(xn-2/3-0.01, n, domain='ZZ'), '==')
but received:
sympy.polys.polyerrors.PolynomialError: (n3 +
n2)**0.333333333333333 contains an element of the set of generators.
Same:
ans = sp.solveset(sp.Abs(xn-2/3) < 0.01, n)
ConditionSet(n, Abs((n3 - n2)0.333333333333333 - (n3 +
n**2)**0.333333333333333 + 0.666666666666667) < 0.01, Complexes)
How can this inequality be solved?
from sympy import *
from sympy.abc import x,n
a = S(2) / 3
epsilon = 0.01
xn = (n**3 + n**2)**(S(1)/3) - (n**3 - n**2)**(S(1)/3)
ineq = Abs(xn-a) < epsilon
Let's verify where ineq is satisfied with plot_implicit. Note that the left hand side of the inequality is valid only for n>=1.
plot_implicit(ineq, (n, 0, 5), adaptive=False)
So, the inequality is satisfied for values of n greater than 3.something.
We can use a numerical approach to find the root of this equation: Abs(xn-a) - epsilon.
from scipy.optimize import bisect
func = lambdify([n], Abs(xn-a) - epsilon)
bisect(func, 1, 5)
# out: 3.5833149415284424

FInd mode of Poisson distribution with SymPy

Why I can't find the value at the mode of the Poisson pdf?
import sympy
from sympy import Symbol, simplify
from sympy.stats import Poisson, density
nobs = Symbol('nobs', positive=True, domain=sympy.Integers)
mu = Symbol('μ', domain=sympy.Reals, positive=True)
poisson_pdf = lambda n, _lambda: density(Poisson('X', _lambda))(n)
simplify(sympy.calculus.util.maximum(poisson_pdf(nobs, mu), mu))
I get
Max(oo*(-1)**nobs, (nobs*exp(-1))**nobs/gamma(nobs + 1))
the second argument of max is the solution I would like. What am I missing? And Why I get a gamma function if nobs is positive integer?
The mode of a Poisson is not always unique. (See Wikipedia, note the modes on the plots for λ = 1 and λ = 4.)
Gamma(n + 1) == factorial(n) for positive integer n.

SymPy: Interval Math

Intro
We have been working on a recent project and have been looking for a suitable system to calculate some values. SymPy was recommended as being a rich mathematical library. However, we have been unable to make it "work" with our project.
The issue we have been struggling with specifically is that many of the values we would be using have been rounded numerous times and are likely susceptible to float errors. To work around this on a previous project, we used Interval Arithmetic for JavaScript to fairly effective use. mpmath for Python appears to be similar, but SymPy not only uses mpmath, but also offers other potentially useful functions we may need in the future.
Problem
A sample equation that we have been working on lately is a = b * (1 + c * d * e) and we are looking to solve for e when all other variables are known. However, some of the variables need to be represented as a range of values as we don't know the exact value, but a small range.
Code
from sympy import *
from sympy.sets.setexpr import SetExpr
a, b, c, d, e = symbols('a b c d e')
b = 40
c = 1
d = 0.1
a = SetExpr(Interval(45.995, 46.005))
equ = Eq(b * (1 + c * d * e), a)
solveset(equ, e)
ValueError: The argument '45.995*I' is not comparable.
This was just the latest attempt, but I have tried setting domains, setting inequalities for symbols, using AccumBounds, and numerous other solutions but I can't help but think that we have completely overlooked something simple.
Solution
It appears that that using one interval is doable with the code provided by the selected answer, but it doesn't extend to multiple symbols requiring intervals or ranges of values. It appears we will be extending the mpmath library to support additional interval functions.
There is an intervalmath module in SymPy in the plotting module for some reason. It doesn't subclass Basic though so can't be used directly in an expression. We can however use lambdify to substitute it into an expression as
from sympy import *
from sympy.plotting.intervalmath import interval
b = 40
c = 1
d = 0.1
a, e = symbols('a, e', real=True)
equ = Eq(b * (1 + c * d * e), a)
sol_e, = solveset(equ, e)
f_e = lambdify(a, sol_e)
int_a = interval(45.995, 46.005)
int_e = f_e(a=int_a)
print(int_e)
This gives
[1.498750, 1.501250]
I don't think the intervalmath module is used much though so there's a good chance it might not fully work in your real problem.
Using sets is probably a better approach and it seems that imageset can do this:
In [16]: set_e = imageset(Lambda(a, sol_e), Interval(45.995, 46.005))
In [17]: set_e
Out[17]: [1.49875, 1.50125]
I'm not sure how well this works with more than one symbol/interval though.
EDIT: For completeness I'm showing how you would use intervalmath with more than one interval:
from sympy import *
from sympy.plotting.intervalmath import interval
b = 40
d = 0.1
a, c, e = symbols('a, c, e', real=True)
equ = Eq(b * (1 + c * d * e), a)
sol_e, = solveset(equ, e)
f_e = lambdify((a, c), sol_e)
int_a = interval(45.995, 46.005)
int_c = interval(0.95, 1.05)
int_e = f_e(a=int_a, c=int_c)
print(int_e)
That gives
[1.427381, 1.580263]

Getting sympy to simplify infinite sums containing piecewise functions

I am running the following in my jupyter-notebook.
from sympy import *
B = IndexedBase('B')
x, L = symbols('x L', real=True)
n = Symbol('n', integer=True)
n = Idx(n, (0, oo))
Bn = Indexed('B', n)
m = Symbol('m', integer=True)
Sum(Piecewise((0, Ne(m, n)), (L, True))*B[n], (n, 0, oo)).doit()
The last expression should evaluate to $L B_n$. I have tried using simplify, doit, limit and evalf methods on it to without success. I also found more similar issues in github but couldn't taylor this to my specific problem.
I also tried fiddling around with the underlying assumptions for integer m but couldn't find anything suitable.
Is there any direct or indirect way to get sympy to simplify infinite sums containing piecewise functions?
Just as an aside this code below works:
p = Piecewise((1, n<5), (0, True))
Sum(p, (n, 1, oo)).evalf()

Parameter optimization using a genetic algorithm?

I am trying to optimize parameters for a known function to fit an experimental data plot. The function is fairly involved
where x sweeps along a know set of numbers and p, g and c are the independent parameters to be optimized. Any ideas or resources that could be of assistance?
I would not recommend Genetic Algorithms. Instead go for straight forward Optimization.
Scipy has some resources.
You haven't provided any data or so, so I'll just go for something that should run. Below is something to get you started. I can't know if it works without seeing the data. Also, there must probably is a way to dynamically feed objectivefunc your x and y data. That's probably in the docs to scipy.optimize.minimize.
What I've done. Create a function to minimize. Here, I've called it objectivefunc. For that I've taken your function y = x^2 * p^2 * g / ... and transformed it to be of the form x^2 * p^2 * g / (...) - y = 0. Then square the left hand side and try to minimise it. Because you will have multiple (x/y) data samples, I'd minimise the sum of the squares. Put it all in a function and pass it to the minimize from scipy.
import numpy as np
from scipy.optimize import minimize
def objectivefunc(pgq):
"""Your function transformed so that it can be minimised.
I've renamed the input pgq, so that pgq[0] is p, pgq[1] is g, etc.
"""
p = pgq[0]
g = pgq[1]
q = pgq[2]
x = [10, 9.4, 17] # Some input data.
y = [12, 42, 0.8]
sum_ = 0
for i in range(len(x)):
sum_ += (x[i]**2 * p**2 * g - y[i] * ( (c**2 - x**2)**2 + x**2 * g**2) )**2
return sum_
pgq = np.array([1.3, 0.7, 0.5]) # Supply sensible initivial values
res = minimize(objectivefunc, pgq, method='nelder-mead',
options={'xtol': 1e-8, 'disp': True})
Have you tired old good Levenberg-Marquardt as implemented in Levenberg-Marquardt.vi. If it does not suite your needs, you can try Waptia libraryfor LabVIEW with one of the genetic algorithms implemented.