Symbolically multiply infinite sums in SymPy - python

I'm writing software which uses SymPy to symbolically write code, and I've encountered multiplied sums that I need to simplify. The algorithm I'm using calls for the use of the Cauchy product to convert two sums multiplied by each other into a double sum. Below is an example of what I'm trying to accomplish:
from sympy import Sum, Function, Symbol, oo
# Define variables
n = Symbol('n')
x = Symbol('x')
t = Symbol('t')
# Define functions
theta = Function('theta')(t)
p = Function('p')(n,x)
q = Function('q')(n,x)
# Create Summations
pSum = Sum(p*theta**n, (n,0,oo))
qSum = Sum(q*theta**n, (n,0,oo))
# Multiply
out = pSum * qSum
print(out)
>>> Sum(p(n, x)*theta(t)**n, (n, 0, oo))*Sum(q(n, x)*theta(t)**n, (n, 0, oo))
I need to convert this to
print(out)
>>> Sum(Sum((p(i, x)*q(n-i, x))*theta**n, (i, 0, n)), (n, 0, oo))
My approach at this was importing Sum and defining a class that inherits from Sum. I then define the __mul__ operator to do what I want. This works for simple cases, but in more complicated cases, it won't work. In this example, the first case works, but the next one won't multiply because the * isn't calling __mul__ when already in SymPy.
import sympy
from sympy import expand, Function, Symbol, oo, diff, Sum, Derivative
class Sum2(Sum):
# Overriding the __mul__ method.
def __mul__(self, other):
if isinstance(other, Sum2):
i = Symbol('i')
n = Symbol('n')
return Sum2(Sum(self.args[0].subs(n, i)*other.args[0].subs(n, n-i), (i,0,n)), (n,0,oo))
else:
super().__mul__(other)
x = Symbol('x')
t = Symbol('t')
n = Symbol('n')
f = Function('f')(n, x)
a = Sum2(f*t**n, (n,0,oo))
# Works
print(a*a)
# Doesn't work.
c = (Derivative(a,x)*a).doit()
print(c)
print(c.doit())
print(expand(c))
I've tried a similar approach, inheriting from Function instead. Same problem. Perhaps __mul__ wasn't the right function to redefine? How can I allow infinite sums to be multiplied in this way?

Related

How to calculate a sigmoid function without using an exp() function in Python?

I'm working in somewhat of a limited development environment. I'm writing a neural network in Python. I don't have access to numpy and as it is I can't even import the math module. So my options are limited. I need to calculate the sigmoid function, however I'm not sure how the exp() function works under the hood. I understand exponents and that I can use code like:
base = .57
exp = base ** exponent
However I'm not sure what exponent should be? How do functions like numpy.exp() calculate the exponent? This is what I need to replicate.
The exponential function exp(a) is equivalent to e ** a, where e is Euler's number.
>>> e = 2.718281828459045
>>> def exp(a):
... return e ** a
...
>>> import math # accuracy test
>>> [math.exp(i) - exp(i) for i in range(1, 12, 3)]
[0.0, 7.105427357601002e-15, 2.2737367544323206e-13, 1.4551915228366852e-11]
def sigmoid(z):
e = 2.718281828459
return 1.0/(1.0 + e**(-1.0*z))
# This is the formula for sigmoid in pure python
# where z = hypothesis. You have to find the value of hypothesis
you can use ** just fine for your use case it will work with both float and integer input
print(2**3)
8
print(2**0.5 )
1.4142135623730951
if you really need a drop in replacement for numpy.exp()
you can just make a function that behaves like it is written in the docs https://numpy.org/doc/stable/reference/generated/numpy.exp.html
from typing import List
def not_numpy_exp(x:[List[float],float]):
e = 2.718281828459045 # close enough
if type(x) == list:
return [e ** _x for _x in x]
else:
return e**x
how the exp() function works under the hood
If you mean math.exp from built-in module math in this place it does simply
exp(x, /)
Return e raised to the power of x.
where e should be understand as math.e (2.718281828459045). If import math is not allowed you might do
pow(2.718281828459045, x)
instead of exp(x)

Evaluating a sum in SymPy

I want to evaluate the sum
using Python and SymPy, I'm relatively new using SymPy and the first thing I tried was
from sympy import exp, oo, summation, symbols
n, x = symbols('n,x')
summation(exp(-n*x), (n, 1, oo))
But it doesn't work, it just returns the unevaluated sum.
I can make it work using
from sympy import exp, oo, summation, symbols
n, x = symbols('n,x')
f = exp(-x)
summation(x**(-n), (n, 1, oo)).subs(x,f)
But I would like to know if it is possible to make it work without need to break the expression into x^n and then substitute x by e^-x.
Thank you
Try using the following:
x , n = smp.symbols('x n')
smp.Sum(smp.exp(-n*x),(n, 1, smp.oo))

Getting the error "cannot assign function to call" when computing derivatives with SymPy

This code is a derivative code for a Taylor expansion that is 5 derivatives long. So ds(i) is supposed to replace its zero valued variables with the new x values (the derivative values). I keep getting the error "cannot assign function to call"
def derivatives(f, x, a, n):
f = f(x)
x = var
a = 1.0
n = 5
ds = np.zeros(n)
exp = f(x)
for i in range(n):
exp = sp.diff(exp,x)
ds(i) = exp.replace(x, a)
return ds
You probably meant ds[i], not ds(i). Square brackers for indexing vs round parentheses for function calls. That said, the code has other issues, from undefined var to using a NumPy array (?) to store SymPy objects. In general, it's advisable to keep in mind that SymPy works primarily with expressions not with functions. Expressions do not "take arguments", they are not like callable functions in Python.
And all of this is unnecessary, because SymPy computes n-th derivative on its own. Example, the 5th derivative of exp(2*x) at 0:
x = sp.symbols('x')
f = sp.exp(2*x) # an expression, not a function
n = 5
a = 0
print(f.diff(x, n).subs(x, a)) # take derivative n times, then plug a for x
prints 32. Or, if you want a Taylor expansion up to and including x**n:
print(f.series(x, a, n + 1))
prints 1 + 2*x + 2*x**2 + 4*x**3/3 + 2*x**4/3 + 4*x**5/15 + O(x**6).

Solving an equation with scipy's fsolve

I'm trying to solve the equation f(x) = x-sin(x) -n*t -m0
In this equation, n and m0 are attributes, defined in my class. Further, t is a constant integer in the equation, but it has to change each time.
I've solved the equation so i get a 'new equation'. I've imported scipy.optimize
def f(x, self):
return (x - math.sin(x) -self.M0 - self.n*t)
def test(self,t):
return fsolve(self.f, 1, args=(t))
Any corrections and suggestions to make it work?
I can see at least two problems: you've mixed up the order of arguments to f, and you're not giving f access to t. Something like this should work:
import math
from scipy.optimize import fsolve
class Fred(object):
M0 = 5.0
n = 5
def f(self, x, t):
return (x - math.sin(x) -self.M0 - self.n*t)
def test(self, t):
return fsolve(self.f, 1, args=(t))
[note that I was lazy and made M0 and n class members]
which gives:
>>> fred = Fred()
>>> fred.test(10)
array([ 54.25204733])
>>> import numpy
>>> [fred.f(x, 10) for x in numpy.linspace(54, 55, 10)]
[-0.44121095114838482, -0.24158955381855662, -0.049951288133726734,
0.13271070588400136, 0.30551399241764443, 0.46769772292130796,
0.61863201965219616, 0.75782574394219182, 0.88493255340251409,
0.99975517335862207]
You need to define f() like so:
def f(self, x, t):
return (x - math.sin(x) - self.M0 - self.n * t)
In other words:
self comes first (it always does);
then comes the current value of x;
then come the arguments you supply to fsolve().
You're using a root finding algorithm of some kind. There are several in common use, so it'd be helpful to know which one.
You need to know three things:
The algorithm you're using
The equation you're finding the roots for
The initial guess and range over which you're looking
You need to know that some combinations may not have any roots.
Visualizing the functions of interest can be helpful. You have two: a linear function and a sinusiod. If you were to plot the two, which sets of constants would give you intersections? The intersection is the root you're looking for.

Mathematica to Python

How can this Mathematica code be ported to Python? I do not know the Mathematica syntax and am having a hard time understanding how this is described in a more traditional language.
Source (pg 5): http://subjoin.net/misc/m496pres1.nb.pdf
This cannot be ported to Python directly as the definition a[j] uses the Symbolic Arithmetic feature of Mathematica.
a[j] is basically the coefficient of xj in the series expansion of that rational function inside Apart.
Assume you have a[j], then f[n] is easy. A Block in Mathematica basically introduces a scope for variables. The first list initializes the variable, and the rest is the execution of the code. So
from __future__ import division
def f(n):
v = n // 5
q = v // 20
r = v % 20
return sum(binomial(q+5-j, 5) * a[r+20*j] for j in range(5))
(binomial is the Binomial coefficient.)
Using the proposed solutions from the previous answers I found that sympy sadly doesn't compute the apart() of the rational immediatly. It somehow gets confused. Moreover, the python list of coefficients returned by *Poly.all_coeffs()* has a different semantics than a Mathmatica list. Hence the try-except-clause in the definition of a().
The following code does work and the output, for some tested values, concurs with the answers given by the Mathematica formula in Mathematica 7:
from __future__ import division
from sympy import expand, Poly, binomial, apart
from sympy.abc import x
A = Poly(apart(expand(((1-x**20)**5)) / expand((((1-x)**2)*(1-x**2)*(1-x**5)*(1-x**10))))).all_coeffs()
def a(n):
try:
return A[n]
except IndexError:
return 0
def f(n):
v = n // 5
q = v // 20
r = v % 20
return sum(a[r+20*j]* binomial(q+5-j, 5) for j in range(5))
print map(f, [100, 50, 1000, 150])
The symbolics can be done with sympy. Combined with KennyTM's answer, something like this might be what you want:
from __future__ import division
from sympy import Symbol, apart, binomial
x = Symbol('x')
poly = (1-x**20)**5 / ((1-x)**2 * (1-x**2) * (1-x**5) * (1-x**10))
poly2 = apart(poly,x)
def a(j):
return poly2.coeff(x**j)
def f(n):
v = n // 5
q = v // 20
r = v % 20
return sum(binomial(q+5-j, 5)*a(r+20*j) for j in range(5))
Although I have to admit that f(n) does not work (I'm not very good at Python).

Categories

Resources