I have a rational function: f(x) = P(x)/Q(x).
For example:
f(x) = (5x + 3)/(1-x^2)
Because f(x) is a generating function it can be written as:
f(x) = a0 + a1*x + a2*x² + ... + a_n*x^n + ... = P(x)/Q(x)
How can I use sympy to find the nth term of the generating function f(x) (that is a_n)?
If there is no such implementation in Sympy, I am curious also to know if this implemented in other packages, such as Maxima.
I appreciate any help.
To get the general formula for a_n of the generating function of a rational form , SymPy's rational_algorithm can be used.
For example:
from sympy import simplify
from sympy.abc import x, n
from sympy.series.formal import rational_algorithm
f = (5*x + 3)/(1-x**2)
func_n, independent_term, order = rational_algorithm(f, x, n, full=True)
print(f"The general formula for a_n is {func_n}")
for k in range(10):
print(f"a_{k} = {simplify(func_n.subs(n, k))}")
Output:
The general formula for a_n is (-1)**(-n - 1) + 4
a_0 = 3
a_1 = 5
a_2 = 3
a_3 = 5
a_4 = 3
a_5 = 5
a_6 = 3
a_7 = 5
a_8 = 3
a_9 = 5
Here is another example:
f = x / (1 - x - 2 * x ** 2)
func_n, independent_term, order = rational_algorithm(f, x, n, full=True)
print(f"The general formula for a_n is {func_n.simplify()}")
print("First terms:", [simplify(func_n.subs(n, k)) for k in range(20)])
The general formula for a_n is 2**n/3 - (-1)**(-n)/3
First terms: [0, 1, 1, 3, 5, 11, 21, 43, 85, 171, 341, 683, 1365, 2731, 5461, 10923, 21845, 43691, 87381, 174763]
You could take the kth derivative and substitute 0 for x and divide by factorial(k):
>>> f = (5*x + 3) / (1-x**2)
>>> f.diff(x, 20).subs(x, 0)/factorial(20)
3
The reference here talks about rational generating functions. Looking for a recurrence you can see the pattern pretty quickly using differentiation:
[f.diff(x,i).subs(x,0)/factorial(i) for i in range(6)]
[3, 5, 3, 5, 3, 5]
Adapting the approach of this post, you could try the following:
from sympy import *
from sympy.abc import x
f = (5*x + 3) / (1-x**2)
print(f.series(n=20))
k = 50
coeff50 = Poly(series(f, x, n=k + 1).removeO(), x).coeff_monomial(x ** k)
print(f"The coeffcient of x^{k} of the generating function of {f} is {coeff50}")
# to get the first 100 coeffcients (reversing the list to get a[0] the
# coefficient of x**0 etc.):
a = Poly(series(f, x, n=100).removeO(), x).all_coeffs()[::-1]
Output:
3 + 5*x + 3*x**2 + 5*x**3 + 3*x**4 + 5*x**5 + 3*x**6 + 5*x**7 + 3*x**8 + 5*x**9 + 3*x**10 + 5*x**11 + 3*x**12 + 5*x**13 + 3*x**14 + 5*x**15 + 3*x**16 + 5*x**17 + 3*x**18 + 5*x**19 + O(x**20)
The coeffcient of x^50 of the generating function of (5*x + 3)/(1 - x**2) is 3
Following this example at Cut The Knot, the approach can be used to find out the number of ways an amount n can be paid with coins of 1, 5, 10, 25 and 50 cents.
f = 1/((1 - x)*(1 - x**5)*(1 - x**10)*(1 - x**25)*(1 - x**50))
a = Poly(series(f, x, n=101).removeO(), x).all_coeffs()[::-1]
print(a[50]) # there are 50 ways to pay 50 cents
print(a[100]) # there are 292 ways to pay 100 cents
In maxima:
powerseries((5*x+3)/(1-x^2),x,0);
returns
Use part to extract the generator:
part(''%,1);
(4-(-1)^i1)x^i1
and coeff to get the coefficient:
a(i1) := coeff(''%, x, i1);
[a(0), a(1), a(2)];
[3, 5, 3]
Another nice way to approach this is to use the ring series:
>>> from sympy.polys.ring_series import rs_mul, rs_pow
>>> from sympy.polys.rings import ring
>>> R,x=ring('x', ZZ)
>>> from sympy import ZZ
>>> R,x=ring('x', ZZ)
>>> nmax = 100
>>> s = rs_mul(5*x+3, rs_pow(1-x**2, -1, x, nmax+1), x, nmax+1)
>>> [s.coeff(x**i) for i in (2,3,5,17,100)]
[3, 5, 5, 5, 3]
Related
I want to cal
https://en.wikipedia.org/wiki/Diophantine_equation#Examples
ax + by = c This is a linear Diophantine equation.
i try
I think the way you substituted h is not good.
How should I fix it?
x,y integer
(1)(2)5^4x-2^4y=1
(3)5^5x-2^5y=1
(4)11^5x-2^5y=1
from sympy.solvers.inequalities import reduce_rational_inequalities
from sympy import *
import math
var('x y n')
def myEq(f,g,h,myMax):
myN = Symbol('myN', real=True)
myGcdex = gcdex(f, -g)
myX = g * n + myGcdex[2]
myY = solve((f * x - g * y - h).subs({x: myX}), y)[0]
myN = math.ceil(reduce_rational_inequalities([[myX.subs({n: myN}) >= myMax]], myN).lhs)
return myX.subs({n: myN}),myY.subs({n: myN})
print("#(1)",myEq ( 5**4,2**4,1, 0) )
print("#(2)",myEq ( 5**4,2**4,1, 10) )
print("#(3)",myEq ( 5**5,2**5,1,100), "????<correct>x=125,y=12207")
print("#(4)",myEq (11**5,2**5,1, 0)," ","????<correct>x= 19,y=95624")
#(1) (1, 39)
#(2) (17, 664)
#(3) (129, 100781/8) ????<correct>x=125,y=12207
#(4) (1, 80525/16) ????<correct>x= 19,y=95624
#
#〇(1)nxy 0 16*n + 1 625*n + 39 <correct>x = 16 n + 1 , y = 625 n + 39 , n=0
#〇(2)nxy 1 16*n + 1 625*n + 39
#×(3)nxy 4 32*n + 1 3125*n + 781/8 <correct>x = 32 n + 29 , y = 3125 n + 2832 , n=3
#×(4)nxy 0 32*n + 1 161051*n + 80525/16 <correct>x = 32 n + 19 , y = 161051 n + 95624, n=0
ref
I want function convert from xy to cells
https://mathworld.wolfram.com/Congruence.html
(20220407)
MY_diox( 5**4*x-2**4*y-1, 0) # (( 1, 39), (16*n - 15, 625*n - 586))
MY_diox( 5**4*x-2**4*y-1, 10) # (( 17, 664), (16*n + 1, 625*n + 39))
MY_diox( 5**5*x-2**5*y-1,100) # ((125, 12207), (32*n + 93, 3125*n + 9082))
MY_diox(11**5*x-2**5*y-1, 0) # (( 19, 95624), (32*n - 13, 161051*n - 65427))
(20220410)
ref sage
Get all positive integral solutions for a linear equation
It looks like you are trying to get a specific solution to the equation that has a certain minimum value for x. If you solve the inequality for the parameter you can convert that to an interval on integers and just select the first such integer. A modified equation to give that value at n = 1 can also be given using a shift of origin.
def diox(eq, x):
"""
>>> from sympy.abc import x, y
>>> eq = 5**5*x-2**5*y-1
>>> diox(eq, 30)
((61, 5957), (32*n + 29, 3125*n + 2832))
"""
s = diophantine(eq)
assert len(s) == 1
a, b = s.pop()
p = a.free_symbols
assert len(p) == 1
p = p.pop()
i = solve(a >= x).as_set().intersection(Integers)
if i.start.is_infinite:
i = i.sup
else:
i = i.start
t = Tuple(a, b).xreplace({p: i})
e = Tuple(a, b).xreplace({p: Symbol('n')+i-1})
return t, e
As expected, the following was not possible.
from sympy import *
from sympy.abc import x, y
from sympy.solvers.diophantine import diophantine
var('x a b c')
myFormula= a*x+b*y-c
def diox(eq, x):
.......................................
return t, e
print("#",diox(myFormula,0))
# NotImplementedError: No solver has been written for inhomogeneous_general_quadratic.
if I had an equation with more than one variable, lets say
x**2+x*y+y**2, I could find Coefficients with CoefficientList from Mathematica. It would print the desired matrix as 3x3.
In Python, I found sympy.coeff(x, n) but I can not return the coefficient for more than one variable.
Is there a way you know?
For the quadratic case, the following matches the output of Mathematica:
def CoefficientList(p, v):
"""
>>> CoefficientList(x**2+2*x*y+3*y**2+4*x+5*y+6,(x,y))
Matrix([
[6, 5, 3],
[4, 2, 0],
[1, 0, 0]])
"""
assert len(v) == 2
n = len(v)
t = [prod(i) for i in subsets([S.One] + list(v), n, repetition=n)]
p = p.expand()
m = zeros(n + 1)
r = n + 1
while t:
if r > n:
n -= 1
r = 0
c = n
x = t.pop()
if x == 1:
d = p
else:
p, d = p.as_independent(x, as_Add=True)
co = d.as_coeff_Mul()[0]
m[r, c] = co
r += 1
c -= 1
return m
But the monomials method is a good one to use. To get all the coefficients of all monomials I would recommend storing them in a defaultdict with a default value of 0. You can then retrieve the coefficients as you wish:
def coeflist(p, v):
"""
>>> coeflist(x**2+2*x*y+3*y**2+4*x+5*y+6, [x])
defaultdict(<class 'int'>, {x**2: 1, x: 2*y + 4, 1: 3*y**2 + 5*y + 6})
>>> coeflist(x**2+2*x*y+3*y**2+4*x+5*y+6, [x, y])
defaultdict(<class 'int'>, {x**2: 1, x*y: 2, x: 4, y**2: 3, y: 5, 1: 6})
>>> _[y**2]
3
"""
from collections import defaultdict
p = Poly(p, *v)
rv = defaultdict(int)
for i in p.monoms():
rv[prod(i**j for i,j in zip(p.gens, i))] = p.coeff_monomial(i)
return rv
Here is a way to find each of the coefficients of the quadratic form and represent them as a matrix:
import sympy as sy
from sympy.abc import x, y
def quadratic_form_matrix(expr, x, y):
a00, axx, ayy, ax, ay, axy = sy.symbols('a00 axx ayy ax ay axy')
quad_coeffs = sy.solve([sy.Eq(expr.subs({x: 0, y: 0}), a00),
sy.Eq(expr.diff(x).subs({x: 0, y: 0}), 2 * ax),
sy.Eq(expr.diff(x, 2).subs({y: 0}), 2 * axx),
sy.Eq(expr.diff(y).subs({x: 0, y: 0}), 2 * ay),
sy.Eq(expr.diff(y, 2).subs({x: 0}), 2 * ayy),
sy.Eq(expr.diff(x).diff(y), 2 * axy)],
(a00, axx, ayy, ax, ay, axy))
return sy.Matrix([[axx, axy, ax], [axy, ayy, ay], [ax, ay, a00]]).subs(quad_coeffs)
expr = x**2 + 2*x*y + 3*y**2 + 7
M = quadratic_form_matrix(expr, x, y)
print(M)
XY1 = sy.Matrix([x, y, 1])
quadatric_form = (XY1.T * M * XY1)[0]
print(quadatric_form.expand())
PS: Applying a conversion to a multivariate polygon as suggested #Marcus' reference, and then converting to a matrix would result in following code. Note that to get the constant term, 1 can be passed to coeff_monomial(1). The non-diagonal elements of the symmetric matrix for the quadratic form need to be half of the corresponding coefficients.
import sympy as sy
from sympy.abc import x, y
def quadratic_form_matrix_using_poly(expr, x, y):
p = sy.poly(expr)
axx = p.coeff_monomial(x * x)
ayy = p.coeff_monomial(y * y)
a00 = p.coeff_monomial(1)
ax = p.coeff_monomial(x) / 2
ay = p.coeff_monomial(y) / 2
axy = p.coeff_monomial(x * y) / 2
return sy.Matrix([[axx, axy, ax], [axy, ayy, ay], [ax, ay, a00]])
expr = x**2 + 2*x*y + 3*y**2 + 7 + 11*x + 23*y
M = quadratic_form_matrix(expr, x, y)
print(M)
XY1 = sy.Matrix([x, y, 1])
quadatric_form = (XY1.T * M * XY1)[0]
print(quadatric_form.expand())
Currently I'm working on a project that implements cubic spline interpolation. So far I have managed to calculate coefficients for my equations.
Now I'm trying to return an interpolating function that for any x returns y.
Let's assume that we have
x = [1, 3, 5]
y = [6, -2, 4]
The coefficients that we get are as follow:
[ 6, -5.75, 0, 0.4375, -2, -0.5, 2.625, -0.4375]
It is equal to
[ a<sub>0</sub>, b<sub>0</sub>, c<sub>0</sub>, d<sub>0</sub>, a<sub>1</sub>, b<sub>1</sub>, c<sub>1</sub>, d<sub>1</sub>]
The interpolating polynomials are
S<sub>0</sub>(x) = a<sub>0</sub> + b<sub>0</sub>*x + c<sub>0</sub>*x<sup>2</sup> + d<sub>0</sub>*x<sup>3</sup> x ∈ [1, 3]
S<sub>1</sub>(x) = a<sub>1</sub> + b<sub>1</sub>*x + c<sub>1</sub>*x<sup>2</sup> + d<sub>1</sub>*x<sup>3</sup> x ∈ (3, 5]
And so on - it can be calculated for more than only 3 points
Right now I have implemented a method that works only if one x is given as an input.
def interpolate_spline(x, x_array, coefficients):
i = 1
while x_array[i] < x:
i += 1
i = i - 1
a = coefficients[4 * i]
b = coefficients[4 * i + 1]
c = coefficients[4 * i + 2]
d = coefficients[4 * i + 3]
return a + b * x + c * (x ** 2) + d * (x ** 3)
And coming back to my question: Is there any possibility that it can be vectorized or at least take whole array as an input?
I don't know if that matters but assume that x_array is sorted
If I have a polynomial P, is there a way to calculate P^-1 modulo Q, being Q another polynomial?
I know that the coefficients of both polynomials belongs to the field of integers modulo z, being z an integer.
I´m not sure if SymPy has already a function for that in its galoistools module.
This is essentially the same as finding polynomials S, T such that PS + QT = 1. Which is possible when gcd(P, Q) = 1, and can be done with galoistools.gf_gcdex. For example, let's invert 3x^3+2x+4 modulo x^2+2x+3 with the coefficient field Z/11Z:
from sympy.polys.domains import ZZ
from sympy.polys.galoistools import gf_gcdex
p = ZZ.map([3, 0, 2, 4])
q = ZZ.map([1, 2, 3])
z = 11
s, t, g = gf_gcdex(p, q, z, ZZ)
if len(g) == 1 and g[0] == 1:
print(s)
else:
print('no inverse')
This prints [8, 5] - the inverse is 8x+5. Sanity check by hand:
(3x^3+2x+4)*(8x+5) = 24x^4 + 15x^3 + 16x^2 + 42x + 20
= 2x^4 + 4x^3 + 5x^2 + 9x + 9
= (x^2 + 2x + 3)*(2x^2 - 1) + 1
= 1 mod q
The program needs to compute define integral with a predetermined
accuracy (eps) with the Trapezoidal Rule and my function needs to return:
1.the approximate value of the integral.
2.the number of iterations.
My code:
from math import *
def f1(x):
return (x ** 2 - 1)**(-0.5)
def f2(x):
return (cos(x)/(x + 1))
def integral(f,a,b,eps):
n = 2
x = a
h = (b - a) / n
sum = 0.5 * (f(a) + f(b))
for i in range(n):
sum = sum + f(a + i * h)
sum_2 = h * sum
k = 0
flag = 1
while flag == 1:
n = n * 2
sum = 0
k = k + 1
x = a
h = (b - a) / n
sum = 0.5 * (f(a) + f(b))
for i in range(n):
sum = sum + f(a + i * h)
sum_new = h * sum
if eps > abs(sum_new - sum_2):
t1 = sum_new
t2 = k
return t1, t2
else:
sum_2 = sum_new
x1 = float(input("First-begin: "))
x2 = float(input("First-end: "))
y1 = float(input("Second-begin: "))
y2 = float(input("Second-end: "))
int_1 = integral(f1,x1,y1,1e-6)
int_2 = integral(f2,x2,y2,1e-6)
print(int_1)
print(int_2)
It doesn't work correct. Help, please!
You implemented the math wrong. The error is in the lines
for i in range(n):
sum = sum + f(a + i * h)
range(n) always starts at 0, so in your first iteration you just add the f(a) term again.
If you replace it with
for i in range(1, n):
sum = sum + f(a + i * h)
it works.
Also, you have a ton of redundant code; you basically coded the core of the integration algorithm twice. Try to follow the DRY-principle.
The trapezoidal rule of integration simply says that an approximation to the integral $\int_a^b f(x) dx$ is (b-a) (f(a)+f(b))/2. The error is proportional to (b-a)^2, so that it is possible to have a better estimate using the composite rule, i.e., subdividing the initial interval in a number of shorter intervals.
Is it possible to use shorter intervals and still reuse the function values previously computed, so minimizing the total number of function evaluation?
Yes, it is possible if we divide each interval in two equal parts, so that at stage 0 we use 1 intervals, at stage 1 2 equal intervals and in general, at stage n, we use 2n equal intervals.
Let's start with a simple problem and see if it possible to generalize the procedure…
a, b = 0, 32
L = b-a = 32
by the trapezoidal rule the initial approximation say I0, is given by
I0 = L * (f0+f1)/2
= L * S0
with S0 = (f0+f1)/2; a pictorial representation of the real axis, the coordinates of the interval extremes and the evaluated functions follows
x0 x1
01234567890123456789012345679012
f0 f1
Next, we divide the original interval in two,
L = L/2
x0 x2 x1
01234567890123456789012345679012
f0 f2 f1
and the new approximation, stage n=1, is obtained using two times the trapezoidal rule and applying a bit of algebra
I1 = L * (f0+f2)/2 + L * (f2+f1)/2
= L * [(f0+f1)/2 + f2]
= L * [S0 + S1]
with S1 = f2
Another subdivision, stage n=2, L = L/2 and
x0 x3 x2 x4 x1
012345678901234567890123456789012
f0 f3 f2 f4 f1
I2 = L * [(f0+f3) + (f3+f2) + (f2+f4) + (f4+f1)] / 2
= L * [(f0+f1)/2 + f2 + (f3+f4)]
= L * [S0+S1+S2]
with S2 = f3 + f4.
It is not difficult, given this picture,
x0 x5 x3 x6 x2 x7 x4 x8 x1
012345678901234567890123456789012
f0 f5 f3 f6 f2 f7 f4 f8 f1
to understand that our next approximation can be computed as follows
L = L/2
S3 = f5+f6+f7+f8
I3 = L*[S0+S1+S2+S3]
Now, we have to understand how to compute a generalization of Sn,
n = 1, … — for us, the pseudocode is
L_n = (b-a)/2**n
list_x_n = list(a + L_n + 2*Ln*j for j=0, …, 2**n-1)
Sn = Sum(f(xj) for each xj in list_x_n)
For n = 3, L = (b-a)/8 = 4, we have from the formula above list_x_n = [4, 12, 20, 28], please check with the picture...
Now we are ready to code our algorithm in Python
def trapaezia(f, a, b, tol):
"returns integ(f, (a,b)), estimated error and number of evaluations"
from math import fsum # controls accumulation of rounding errors in sums
L = b - a
S = (f(a)+f(b))/2
I = L*S
n = 1
while True:
L = L/2
new_points = (a+L+j*L for j in range(0, n+n, 2))
delta_S = fsum(f(x) for x in new_points)
new_S = S + delta_S
new_I = L*new_S
# error is estimated using Richardson extrapolation (REP)
err = (new_I - I) * 4/3
if abs(err) > tol:
n = n+n
S, I = new_S, new_I
else:
# we return a better estimate using again REP
return (4*new_I-I)/3, err, n+n+1
If you are curious about Richardson extrapolation, I recommend this document that deals exactly with the application of REP to the trapezoidal rule quadrature algorithm.
If you are curious about math.fsum, the docs don't say too much but the link to the original implementation that also includes an extended explanation of all the issues involved.