Chapter 3 Catalan and generating functions

Definition 3.1
Let C(x)=n0cnxn=1+x+2x2+5x3+ denote the generating function of the Catalan numbers.

We can first deduce the recursive formula of the Catalan numbers C(x)=1+xC(x)2.

We use the ordinary generating function for the Catalan numbers, we have C(x)=n0cnxn=n0k=0n1ckcn1kxn Since we know C0=1 , we have C(x)=n0k=0n1ckcn1kxn=1+n1k=0n1ckcn1kxn=1+xn0k=0nckcnkxn=1+x(n0cnxn)2=1+xC(x)2 Therefore, we got C(x)=1+xC(x)2

Use the recursive formula () to prove that C(x) is a solution of the following equation of degree two:
C(x)=1+xC(x)2.

From the equation C(x)=1+xC(x)2 we have C(x)=1+xC(x)2C(x)1x=C(x)2 Then we try to prove the LHS equal to RHS.

For LHS we have C(x)1x=n1cnxnx=n0cn+1xn

For RHS, we apply we got C(x)2=(n0cnxn)2=n0(k=0nckcnk)xn=n0cn+1xn(By Definition)

Therefore we have C(x)2=n0cn+1xn=C(x)1x Then we prove that C(x) is a solution for the equation of C(x)=1+xC(x)2

Deduce a formula for C(x) and the radius of convergence.

Here we have the computation code in python

x = Symbol('x')
c = Symbol('c')
solution = solve(c - 1 - x * c**2, c)

# display the solution in latex
print("--------- Question 4.2 ----------")
print("The solution of the equation in is ")
display(solution[0]), display(solution[1])
print("The solution of the equation in Latex is ", (latex(solution[0])),
      latex(solution[1]))

We use sympy to solve the equation C(x)=1+xC(x)2 and we get C1(x)=114x2xandC2(x)=1+14x2x From the two possibilities, the C1(x) must be chosen because only the choice of the first gives C0=limx0C1(x)=1 Therefore we have C(x)=114x2x

Then we compute the radius of convergence of C(x). For the definition of radius of convergence from Wiki page. We use the expression of C(x) in power series that C(x)=114x2x=n0cnxn Base on [D’Alembert’s test], for radius of convergence R we compute limn|cn+1cn|=ρ for n0cnxn ρ=limn|cn+1cn|=limn|1n+2(2n+2n+2)1n+1(2nn)|=limn|4n+4n+2|=limn|44n+2|=4 Since ρ0, then we have the radius of convergence R=1ρ=14

Compare the efficiency of different approaches.

knitr::include_graphics('static/pic3.png')

knitr::include_graphics('static/pic4.png')

From the two graph we can see that the formula of cn=1n+1(2nn) has the highest computation efficiency. However, the non-recursive method has more execution time than the method above, compare with recursive method the complexity is still much better since the execution time is in the level of 105sec.

We can prove the expression of cn=1n+1(2nn)=(2n)!(n+1)!n! with C(x)=114x2x=n0cnxn

For power series we have 1+y=n=0(12n)yn=n=0(1)n+14n(2n1)(2nn)yn We denote that y=4x we got 14x=1n=112n1(2nn)xn Therefore we got C(x)=114x2x=n=112(2n1)(2nn)xn1=n0cnxn We can deduce that cn=12(2n+1)(2n+2n+1)=1n+1(2nn)

3.1 Manipulate Generating Functions with SymPy

Definition 3.2
We work out with the example of f(x)=112x=1+2x+4x2+8x3+16x4+ We first introduce variable x and function f as follows:

x=var('x')
f=(1/(1-2*x))

print('f = '+str(f))
print('series expansion of f at 0 and of order 10 is: '+str(f.series(x,0,10)))
display(f.series(x,0,10))

1+2x+4x2+8x3+16x4+32x5+64x6+128x7+256x8+512x9+O(x10)

One can extract coefficient n as follows: - f has to be truncated at order k (for some k>n) with f.series(x,0,k) - the n-th coefficient is then extracted by f.coeff(x**n)

f_truncated = f.series(x,0,8)
print('Truncation of f is '+str(f_truncated))
n=6
nthcoefficient=f_truncated.coeff(x**n)
print(str(n)+'th coefficient is: '+str(nthcoefficient))
display(f_truncated)

1+2x+4x2+8x3+16x4+32x5+64x6+128x7+O(x8)

Use SymPy to write another programm which computes the Catalan numbers using C(x), and compare the execution times with the functions of the first part of the Project.

# We compute C(x) with Taylor Expansion
x = var('x')
f = (1 - sqrt(1 - 4 * x)) / (2 * x)

def CatalanTaylorExpansion(n):
    return f.series(x, 0, n).coeff(x**(n - 1))
    
lis = [CatalanTaylorExpansion(i) for i in range(11)]
lis[1] = 1
print("The first ten Catalan numbers with Taylor Expansion are ", lis[1:])

The first ten Catalan numbers with Taylor Expansion are  [1, 1, 2, 5, 14, 42, 132, 429, 1430, 4862]
knitr::include_graphics('static/pic5.png')

knitr::include_graphics('static/pic6.png')

From the two graph we can see that the Taylor Expansion method is much faster than the recursive method but much slower than the method non-recursive and Binomial Formula.

3.2 Motzkin Numbers

Definition 3.3
The Motzkin numbers m0,m1,m2, are similar to Catalan numbers and defined by m0=m1=1 and for every n2 mn=mn1+k=0n2mkmn2k.

  1. Find the generating function M(x)=n0mnxn.
  2. Compute the radius of convergence of C and M. Compare with numerical experiments: which sequence is growing fastest between (cn) and (mn)?

We first try to simplify the motzkin numbers recurrence relation. We have M(x)=n0mnxn=n0(mn1+k=0n2mkmn2k)xn Since we have M0=M1=1, therefore we have M(x)=n0(mn1+k=0n2mkmn2k)xn=xn0mn1xn1+n0k=0n2mkmn2kxn=xM(x)+1+n2k=0n2mkmn2kxn=xM(x)+1+x2n0k=0nmkmnkxn=xM(x)+1+x2(n0mnxn)2=xM(x)+1+x2M(x)

Therefore, we know that M(x)=n0mnxn is a root for x2M2+(x1)M+1=0.

x = symbols('x')
M = symbols('M')
SeriesM = solve(x**2 * M**2 + x * M - M + 1, M)
print(SeriesM)
display(SeriesM[0])
display(SeriesM[1])

We use sympy to solve the equation we have M1(x)=1x12x3x22x2M2(x)=1x+12x3x22x2 Since we know M(0)=1, therefore the only possible solution is M(x)=1x12x3x22x2

# Implementation of the formula of Motzkin Numbers  
def MotzkinFormula(n):
    x = symbols('x')
    m= (1-x-sqrt(1-2*x-3*x**2))/(2*x**2)
    m_truncated = m.series(x,0,n+1)
    return m_truncated.coeff(x**n)
  
print("--------- Question 4.1.1.1 ----------")
lis = [MotzkinFormula(i) for i in range(11)]
lis[0] = 1
print("The first ten Motzkin numbers with Taylor Expansion are ", lis[1:])

--------- Question 4.1.1.1 ----------
The first ten Motzkin numbers with Taylor Expansion are  [1, 2, 4, 9, 21, 51, 127, 323, 835, 2188]

An integral representation of Motzkin numbers is given by mn=2π0πsin(x)2(2cos(x)+1)ndx. They have the asymptotic behaviour mn12π(3n)3/23n,n Therefore, they have the same radius of convergence. We apply the similar method as Catalan number. Base on [D’Alembert’s test], for radius of convergence R we compute limn|mn+1mn|=ρ for n0mnxn ρ=limn|mn+1mn|=limn|(3n+1)323n+1(3n)323n|=limn|3(nn+1)3/2|=3 Since ρ0, then we have the radius of convergence R=1ρ=13.

Or we can illustrate in this way, from the definition of radius of convergence, we need to find an R such that when x<R the series converges. Then we observe that radius shows when 12R3R2=0. Then we got R=13 or r=1. Since when x<1, the function diverges, we can also get R=13

Then we can say the radius of convergence of C is smaller than M. Therefore the sequence of cn is growing faster than mn. We can also show this in the graph.

# plot the Catalan numbers and Motzkin numbers in the same graph
N = [i for i in range(1, 16)]
plt.figure(figsize=(10, 7))
lis_catalan = [CatalanNonRecursive(i) for i in range(1, 16)]
lis_motzkin = [MotzkinFormula(i) for i in range(1, 16)]
plt.plot(N, lis_catalan, 'o-', label='Catalan Numbers')
plt.plot(N, lis_motzkin, 'o-', label='Motzkin Numbers')
plt.legend()
plt.title("Catalan Numbers and Motzkin Numbers")
plt.xlabel("N")
plt.ylabel("Numbers")
plt.show()
knitr::include_graphics('static/pic7.png')