GFUN
A Sage Toolbox for the OEIS
Part 1: Basic operations

Introduction

A generating function is a formal power series \(a(x) = \sum_{n=0}^\infty a_n x^n\) which lets us calculate with the sequence \((a_0,a_1,a_2,...)\) as if it were an analytic function. Compared with the ring of sequences the ring of power series has two great advantages: It is an integral domain (which the ring of sequences is not) and its multiplication, the Cauchy product, has a natural combinatorial interpretation.

Gfun is a classic Maple package for the manipulation of generating functions by Bruno Salvy and Paul Zimmermann written in 1994 (Gfun, swmath). We borrow the name gfun and intend to provide in a series of posts on this blog a similar toolbox, implemented in Sage and geared for the use with the OEIS. In this post we start with the most basic operations and examples.

Our implementation is object oriented and is hopefully easier and more intuitive. We illustrate this with an example, the computation of A048172.

The Maple version:

with(gfun): 
f := series((ln(1+x)-x^2/(1+x)), x, 21):
egf := seriestoseries(f, 'revogf'): 
seriestolist(egf, 'Laplace');

The same with our Sage toolbox:

gf = log(1+x)-x^2/(1+x)
gfun(gf, 'rev').as_egf()

The constructor gfun

The constructor gfun (g, op) has two arguments, g a symbolic expression in one or two variables and op the name of an operation according to the table below. It returns an object representing a formal power series which can be accessed through the methods listed below.

The operations op:

  • None    ... g unmodified (the default without parameter).
  • 'rev'   ... compositional inverse of g.
  • 'inv'   ... multiplicative inverse of g.
  • 'exp'   ... exponential of g.
  • 'log'   ... logarithm of g.
  • 'int'   ... formal integral of g.
  • 'der'   ... formal derivative of g.
  • 'logder' .. logarithmic derivative of g.

The methods

The methods return the sequence of coefficients of the represented power series up to the given precision prec (which is by default 12). The type of the power series is indicated by the method name. The types are 'ogf' (ordinary power series), 'egf' (exponential power series), 'lgf' (logarithmic power series) and 'bgf' (binary power series).

  • as_ogf    (prec=12, search=false)
  • as_egf    (prec=12, search=false)
  • as_lgf    (prec=12, search=false)
  • as_bgf    (prec=12, search=false)
  • as_series (prec=12, typ='ogf')

Setting the parameter 'search=true' (default is false) will look up related information in the OEIS provided you are connected with the Internet.

In the bivariate case (i. e. the given symbolic expression depends on two variables x and t) 'coeffs' returns a triangular table giving the coefficients of those polynomials which are the coefficients of the power series when expanded in t. 'values' returns a rectangular array displaying the values of these polynomials evaluated at the nonnegative integers. The values method evaluates the n-th polynomial in the n-th column of the rectangular array. The 'colgenerator' returns a rational generating function of the n-th column of the values array.

  • coeffs       (typ='ogf', rows = 8)
  • values       (typ='ogf', rows = 8, cols = 8)
  • pred         (typ='ogf', rows = 8)
  • succ         (typ='ogf', rows = 8)
  • colgenerator (n, typ='ogf')

The methods 'pred' (short for predecessor) and 'succ' (short for successor) are two transformations which map integer triangles to integer triangles. 'succ' lists the numerators of the partial fraction decomposition of the generating functions of the columns of the value array as an triangular array. And 'pred' is the transformation inverse to 'succ'. Many examples show that these transformations lead to interesting and meaningful new integer triangles.

Example use

The toolbox gfun.sage can be downloaded from github. To load the toolbox we have to execute the next command first. The path must of course be adapted to the computing environment.

In [1]:
attach('~/.sage/gfun.sage')

The univariate case.

In [2]:
x = SR.var('x')
cato = (1-2*x-sqrt(1-4*x))/(2*x)

Note: The type of input gfun expects is a symbolic expression. ('SR' in 'x = SR.var('x')' stands for Symbolic Ring.)

In [3]:
gf = gfun((1-2*x-sqrt(1-4*x))/(2*x))
print gf.as_ogf()
print gf.as_ogf(6)
Out[3]:
[0, 1, 2, 5, 14, 42, 132, 429, 1430, 4862, 16796, 58786]
[0, 1, 2, 5, 14, 42]

If you want more (or fewer) terms of the sequence call as_ogf with this value. You can also call as_ogf without a value. Then the default length (= 12) is used.

You don't have to re-execute gfun to get a different length of the sequence. The returned object behaves as if it can provide unlimited access to the sequence. This is in contrast to the way some similar (Maple, Mathematica) libraries work which can be found in the OEIS. These programs work on lists; there you have to assign a fixed length at the start which you can't change afterwards. More generally the objects in these libraries behave like 1-based lists whereas the objects here behave like 0-based sequences.

You also can execute different 'as_xgf' methods on the same object. In combination with the operations this gives a multitude of different representations of sequences.

In [4]:
R = gfun(cato, 'rev')
print R.as_ogf()     # A181983
print R.as_egf(9)    # A001563
print R.as_lgf()     # A000290
print R.as_bgf(10)   # A036289
Out[4]:
[0, 1, -2, 3, -4, 5, -6, 7, -8, 9, -10, 11]
[0, 1, -4, 18, -96, 600, -4320, 35280, -322560]
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81, 100, 121]
[0, 2, -8, 24, -64, 160, -384, 896, -2048, 4608]
In [5]:
S = gfun(1 - cato, 'inv')
print S.as_ogf(9)   # A088218 
print S.as_egf(9)   # A000407
print S.as_lgf(9)   # A002457 
print S.as_bgf(9)   # A069723
Out[5]:
[1, 1, 3, 10, 35, 126, 462, 1716, 6435]
[1, 1, 6, 60, 840, 15120, 332640, 8648640, 259459200]
[0, 1, -6, 30, -140, 630, -2772, 12012, -51480]
[1, 2, 12, 80, 560, 4032, 29568, 219648, 1647360]

The bivariate case.

The Motzkin polynomials, A097610.

In [6]:
x, t = SR.var('x, t')
motzkin = gfun((1-t*x-sqrt((x^2-4)*t^2-2*t*x+1))/(2*t^2))
motzkin.as_ogf(5)
Out[6]:
[1, x, x^2 + 1, x^3 + 3*x, x^4 + 6*x^2 + 2]
In [7]:
motzkin.coeffs()
Out[7]:
[[1],
 [0,  1],
 [1,  0,  1],
 [0,  3,  0,  1],
 [2,  0,  6,  0,  1],
 [0, 10,  0, 10,  0,  1],
 [5,  0, 30,  0, 15,  0, 1],
 [0, 35,  0, 70,  0, 21, 0, 1]]

Motzkin polynomials evaluated at the integers, A247495.

In [8]:
motzkin.values()
[n\k][0][1] [2]  [3]   [4]   [5]    [6]     [7] 
[0]   1, 0,  1,   0,    2,    0,     5,      0, A126120
[1]   1, 1,  2,   4,    9,   21,    51,    127, A001006
[2]   1, 2,  5,  14,   42,  132,   429,   1430, A000108
[3]   1, 3, 10,  36,  137,  543,  2219,   9285, A002212
[4]   1, 4, 17,  76,  354, 1704,  8421,  42508, A005572
[5]   1, 5, 26, 140,  777, 4425, 25755, 152675, A182401
[6]   1, 6, 37, 234, 1514, 9996, 67181, 458562, A025230
A000012,A001477,A002522,A079908, ... 

Using the rational generating functions of the columns gives the array with rows and columns exchanged.

In [9]:
for n in range(8):
gf = motzkin.colgenerators(n)
print gfun(gf).as_ogf(7)
[1,   1,    1,    1,     1,      1,      1]
[0,   1,    2,    3,     4,      5,      6]
[1,   2,    5,   10,    17,     26,     37]
[0,   4,   14,   36,    76,    140,    234]
[2,   9,   42,  137,   354,    777,   1514]
[0,  21,  132,  543,  1704,   4425,   9996]
[5,  51,  429, 2219,  8421,  25755,  67181]
[0, 127, 1430, 9285, 42508, 152675, 458562]

The column generating functions are given in the form of partial fractions.

In [10]:
for n in range(6):
print motzkin.colgenerators(n)
-1/(x-1)
1/(x-1) + 1/(x-1)^2
-2/(x-1) - 3/(x-1)^2 - 2/(x-1)^3
4/(x-1) + 10/(x-1)^2 + 12/(x-1)^3 + 6/(x-1)^4
-9/(x-1) - 33/(x-1)^2 - 62/(x-1)^3 - 60/(x-1)^4 - 24/(x-1)^5
21/(x-1)+111/(x-1)^2+300/(x-1)^3+450/(x-1)^4+360/(x-1)^5+120/(x-1)^6

Collecting the numerators of these partial fractions gives (apart from the signs) the number triangle A247497 which we call the 'associated Motzkin numbers'. This triangle with column k divided by k! is the successor triangle of the Motzkin triangle, motzkin.succ[n,k] = A247497(n,k)/k!.

In [11]:
motzkin.succ()
Out[11]:
[[1],
 [1, 1],
 [2, 3, 1],
 [4, 10, 6, 1],
 [9, 33, 31, 10, 1],
 [21, 111, 150, 75, 15, 1],
 [51, 378, 706, 500, 155, 21, 1],
 [127, 1303, 3276, 3136, 1365, 287, 28, 1]]

The first column lists the Motzkin numbers and the second column A058987 Catalan(n) - Motzkin(n-1). The next to last column are the triangular numbers A000217.

Summary: We started with the Motzkin polynomials A097610, looked at the Motzkin values A247495 and arrived via the partial fractions of the column generating functions at the associated Motzkin numbers A247497 which include the Motzkin numbers A001006 as a special case.

The exact definitions of the 'pred' and 'succ' transformations and many more examples are given in this blog post.

The 'explore' methods

  • explore_values(g, typ='ogf', rows=6, cols=6)

This methods is a convenience function. Given a bivariate generating function g it searches the OEIS for information about sequences in the rows and columns of the value table (you have to be online). It helps to quickly get an overview of the situation and to build a cross-reference table like the one given above.

For instance the call

In [18]:
gfun.explore_values(motzkin)        

tries to find information about the first 6 rows and the first 6 columns of the array of Motzkin values.

  • explore_genfun(g)

Given an univariate generating function g this method searches for all combinations of the above operations with the above methods which make mathematical sense and give an integer sequence. If such sequences exist it will search the OEIS for information about these sequences.

The information provided by explore_genfun() is often very useful while studying a sequence, sometimes even more useful and inspiring than the information returned by the SuperSeeker. This is because it does not only hint to information that can be found in the OEIS but also indicates what possible valuable information is missing. Note that you have to be connected to the internet to use this method and it may take some time to finish. (See the example at the end of this post.)

After the method has finished it displays a plot which is a kind of a fingerprint of the generating function. A green path indicates that there are related sequences in the OEIS (which are listed in the output), a red path indicates that in this case a meaningful integer sequence exists which is apparently not in the database. In the other cases for one reason or another there is no related integer sequence.

This plot is a snapshot of the current situation for the Riordan numbers. It was generated by the commands:

In [19]:
x = SR.var('x')
riordan = (1+x-sqrt(1-2*x-3*x^2))/(2*x*(1+x))
gfun.explore_genfun(riordan)

Conventions

All sequences here are by definition functions from N = {0,1,2,3,...} to some codomain. Triangles and rectangles are functions from N X N to some codomain. In other words all sequences have 'offset' 0 and all two-dimensional arrays are (0, 0) based. Lists in the OEIS might deviate from this: often they have (1, 1) or (1,0) or (0,1) as base-point of enumeration. This means that references to the sequences in the OEIS are always modulo the different conventions.

Examples for generating functions

What you are reading is in fact an HTML-rendered IPython notebook which explains the use of the toolbox by examples.

Riordan numbers

A005043, OGF

In [9]:
x = SR.var('x')
riordan = gfun(2/(1+x+sqrt((1+x)*(1-3*x))))
riordan.as_ogf()
Out[9]:
[1, 0, 1, 1, 3, 6, 15, 36, 91, 232, 603, 1585]

Or written in one line:

In [10]:
gfun(2/(1+x+sqrt((1+x)*(1-3*x)))).as_ogf()
Out[10]:
[1, 0, 1, 1, 3, 6, 15, 36, 91, 232, 603, 1585]

A005043, EGF

In [11]:
x = SR.var('x')
riordanE = gfun(exp(x)*(bessel_I(0, 2*x)-bessel_I(1, 2*x)))
riordanE.as_egf()
Out[11]:
[1, 0, 1, 1, 3, 6, 15, 36, 91, 232, 603, 1585]

Or written in one line:

In [12]:
gfun(exp(x)*(bessel_I(0, 2*x)-bessel_I(1, 2*x))).as_egf()
Out[12]:
[1, 0, 1, 1, 3, 6, 15, 36, 91, 232, 603, 1585]

Lucas numbers

A000204, A000032, LGF

In [13]:
lucas = gfun(-log(1/(x^2 - x - 1)))
lucas.as_lgf()
Out[13]:
[0, 1, 3, 4, 7, 11, 18, 29, 47, 76, 123, 199]

Squares of Pell numbers

A079291, LGF

In [14]:
pellsqr = gfun(log((1+2*x+x^2)/(1-6*x+x^2))/8)
pellsqr.as_lgf(10)
Out[14]:
[0, 1, -4, 25, -144, 841, -4900, 28561, -166464, 970225]

Balanced parentheses of two types

A151374, BGF

In [15]:
catalan = gfun((1 - sqrt(1 - 4*x))/(2*x))
catalan.as_bgf() 
Out[15]:
[1, 2, 8, 40, 224, 1344, 8448, 54912, 366080, 2489344, 17199104, 120393728]

The derivative of Cato

Cato is a nickname for Cata-lan with first term 0. A245391, BGF

In [16]:
cato = (1 - sqrt(1 - 4*x) - 2*x)/(2*x) 
print gfun(cato, 'der').as_bgf() 
Out[16]:
[1, 8, 60, 448, 3360, 25344, 192192, 1464320, 11202048, 85995520, 662165504, 5112102912]

Generalized Fibonacci numbers

A000045, A247506, parametrized OGF

In [17]:
gfun(1/(1 - x - x^2)).as_ogf()
Out[17]:
[1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144]

This is case n=2 of the generalized Fibonacci numbers.

In [18]:
genFibo = lambda n: (1-sum(x^j for j in (1..n)))^(-1) 
for n in range(0,9):
print gfun(genFibo(n)).as_ogf()
Out[18]:
[1, 0, 0, 0, 0,  0,  0,  0,   0,   0,   0,    0]
[1, 1, 1, 1, 1,  1,  1,  1,   1,   1,   1,    1]
[1, 1, 2, 3, 5,  8, 13, 21,  34,  55,  89,  144]
[1, 1, 2, 4, 7, 13, 24, 44,  81, 149, 274,  504]
[1, 1, 2, 4, 8, 15, 29, 56, 108, 208, 401,  773]
[1, 1, 2, 4, 8, 16, 31, 61, 120, 236, 464,  912]
[1, 1, 2, 4, 8, 16, 32, 63, 125, 248, 492,  976]
[1, 1, 2, 4, 8, 16, 32, 64, 127, 253, 504, 1004]
[1, 1, 2, 4, 8, 16, 32, 64, 128, 255, 509, 1016]

Note that the limiting case n → oo is A011782 [A000079]. Additionally this is the main diagonal of the array. This type of convergence is also called 'compositional convergence'.

In [19]:
gfun((1-x)/(1-2*x)).as_ogf()  
Out[19]:
[1, 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024]

Generalized Catalan numbers

A000108, A247507, bivariate OGF

In [20]:
x, t = SR.var('x, t')
genCatalan = gfun((1-t*x-sqrt(x^2*t^2-2*t*x-4*t+1))/(2*t))
genCatalan.coeffs()
Out[20]:
[[  1],
 [  1,    1],
 [  2,    3,    1],
 [  5,   10,    6,    1],
 [ 14,   35,   30,   10,    1],
 [ 42,  126,  140,   70,   15,   1],
 [132,  462,  630,  420,  140,  21,  1],
 [429, 1716, 2772, 2310, 1050, 252, 28, 1]]
In [21]:
genCatalan.values()

This table can be found in A247507 showing how many sequences in the OEIS are related to this generating function.

Out[21]:
[0][1] [2]  [3]    [4]     [5]      [6] 
[0] 1, 1,  2,   5,    14,     42,     132,  A000108
[1] 1, 2,  6,  22,    90,    394,    1806,  A006318
[2] 1, 3, 12,  57,   300,   1686,    9912,  A047891
[3] 1, 4, 20, 116,   740,   5028,   35700,  A082298
[4] 1, 5, 30, 205,  1530,  12130,  100380,  A082301
[5] 1, 6, 42, 330,  2814,  25422,  239442,  A082302
[6] 1, 7, 56, 497,  4760,  48174,  507696,  A082305
[7] 1, 8, 72, 712,  7560,  84616,  985032,  A082366
[8] 1, 9, 90, 981, 11430, 140058, 1782900,  A082367
In [28]:
genCatalan.succ()
Out[28]:
[[1],
 [0, 1],
 [0, 0, 1],
 [0, -1, 0, 1],
 [0, 0, -5, 0, 1],
 [0, 2, -5, -15, 0, 1],
 [0, 0, 21, -35, -35, 0, 1],
 [0, -5, 56, 91, -140, -70, 0, 1]]
 
In [28]:
genCatalan.pred()
Out[28]:
[[1],
 [0, 1],
 [1, 0, 1],
 [-1, 3, 0, 1],
 [3, -5, 5, 0, 1],
 [-16, 0, -20, 5, 0, 1],
 [-30, -182, -91, -70, 0, 0, 1],
 [-477, -966, -1302, -581, -210, -14, 0, 1],
 [-2653, -8955, -9808, -6762, -2331, -546, -42, 0, 1]]
 

Little Narayana polynomials

A000108, A090181, A247507, bivariate OGF

In [22]:
x, t = SR.var('x, t')
littleNarayana = gfun((t*(1-x)-sqrt((t*(x-1))^2-2*t*(x+1)+1))/(2*t))
print littleNarayana.as_ogf(5)
littleNarayana.coeffs()
Out[22]:
[1, x, x^2 + x, x^3 + 3*x^2 + x, x^4 + 6*x^3 + 6*x^2 + x]
                  
[[1],
[0, 1],
[0, 1,  1],
[0, 1,  3,   1],
[0, 1,  6,   6,   1],
[0, 1, 10,  20,  10,   1],
[0, 1, 15,  50,  50,  15,  1],
[0, 1, 21, 105, 175, 105, 21, 1]]
In [23]:
littleNarayana.values()

The same table, with rows and columns interchanged, can be found in A243631, showing how many sequences in the OEIS are related to this generating function.

Out[23]:
    
[0][1] [2]  [3]   [4]    [5]     [6] 
[0]  1, 0,  0,   0,    0,     0,      0, 
[1]  1, 1,  2,   5,   14,    42,    132,  A000108
[2]  1, 2,  6,  22,   90,   394,   1806,  A006318 
[3]  1, 3, 12,  57,  300,  1686,   9912,  A047891 
[4]  1, 4, 20, 116,  740,  5028,  35700,  A082298 
[5]  1, 5, 30, 205, 1530, 12130, 100380,  A082301 
[6]  1, 6, 42, 330, 2814, 25422, 239442,  A082302
[7]  1, 7, 56, 497, 4760, 48174, 507696,  A082305 
[8]  1, 8, 72, 712, 7560, 84616, 985032,  A082366
[9]  1, 9, 90, 981, 11430,140058,1782900, A082367  
A002378,A033445,..  
      
In [32]:
littleNarayana.succ()
Out[32]:
[[1],
 [1, 1],
 [0, 2, 1],
 [-1, -1, 3, 1],
 [0, -10, -5, 4, 1],
 [2, -8, -50, -15, 5, 1],
 [0, 42, -84, -175, -35, 6, 1],
 [-5, 107, 329, -469, -490, -70, 7, 1]]
 
In [32]:
littleNarayana.pred()
Out[32]:
[[1],
 [1, 1],
 [1, 2, 1],
 [1, 3, 3, 1],
 [-1, 1, 5, 4, 1],
 [-19, -35, -15, 5, 5, 1],
 [-151, -352, -286, -90, 0, 6, 1],
 [-1091, -2863, -2863, -1386, -315, -14, 7, 1]]
  

Large Narayana polynomials

A131198, A243631, bivariate OGF

In [24]:
x, t = SR.var('x, t')
largeNarayana = gfun((t*(x-1)-sqrt((t*(x-1))^2-2*t*(x+1)+1))/(2*t*x))
print largeNarayana.as_ogf(5)
largeNarayana.coeffs()
Out[24]:
[1, 1, x + 1, x^2 + 3*x + 1, x^3 + 6*x^2 + 6*x + 1]
                  
[[1],
[ 1],
[ 1,  1],
[ 1,  3,   1],
[ 1,  6,   6,   1],
[ 1, 10,  20,  10,   1],
[ 1, 15,  50,  50,  15,  1],
[ 1, 21, 105, 175, 105, 21, 1]]
In [25]:
largeNarayana.values()
Out[25]:
   [0][1][2]     [3]     [4]     [5]     [6] 
[0] 1, 1, 1,      1,      1,      1,      1, 
[1] 1, 1, 2,      5,     14,     42,    132,  A000108
[2] 1, 1, 3,     11,     45,    197,    903,  A001003
[3] 1, 1, 4,     19,    100,    562,   3304,  A007564
[4] 1, 1, 5,     29,    185,   1257,   8925,  A059231
[5] 1, 1, 6,     41,    306,   2426,  20076,  A078009
[6] 1, 1, 7,     55,    469,   4237,  39907,  A078018
[7] 1, 1, 8,     71,    680,   6882,  72528,  A081178
A000027,A028387,A090197,A090198,A090199,A090200,..
    
In [36]:
largeNarayana.succ()
Out[36]:
[[1],
 [-1, 0],
 [0, -1, 0],
 [1, 0, -1, 0],
 [0, 5, 0, -1, 0],
 [-2, 5, 15, 0, -1, 0],
 [0, -21, 35, 35, 0, -1, 0],
 [5, -56, -91, 140, 70, 0, -1, 0]]
 
In [36]:
largeNarayana.pred()
Out[36]:
[[1],
 [-1, 0],
 [0, -1, 0],
 [0, 0, -1, 0],
 [1, 1, 0, -1, 0],
 [5, 10, 5, 0, -1, 0],
 [26, 61, 50, 15, 0, -1, 0],
 [140, 371, 371, 175, 35, 0, -1, 0]] 
 

Further remarks on Narayana polynomials

For the reason of reference we add explicit definitions of the two kinds of Narayana polynomials. Note that both kinds give the Catalan numbers in row 1 in the tables above. The brand-mark is row 2: the little Narayana polynomials give the little Schröder numbers and the large Narayana polynomials the large Schröder numbers.

# Little Narayana polynomials:
def liN(n, x):
    N = lambda n,k: binomial(n,k)^2*(n-k)/(n*(k+1))
    return expand(add(N(n, k)*x^k for k in range(n))
           if n>0 else 1)
# Large Narayana polynomials:
def laN(n, x):
    N = lambda n,k: binomial(n+1,k)*binomial(2*n-k,n)/(n+1)
    return expand(add(N(n,k)*(x-1)^k for k in range(n+1)))

Scaled Legendre polynomials

2^n*P_n(x), A157077, bivariate BGF

In [26]:
legendre = gfun((1-2*x*t+t^2)^(-1/2))
print legendre.as_bgf(5)
legendre.coeffs('bgf')
Out[26]:
[1, 2*x, 6*x^2 - 2, 20*x^3 - 12*x, 70*x^4 - 60*x^2 + 6]
                  
[[ 1],
[  0,    2],
[ -2,    0,   6],
[  0,  -12,   0,   20],
[  6,    0, -60,    0,    70],
[  0,   60,   0, -280,     0,   252],
[-20,    0, 420,    0, -1260,     0, 924],
[  0, -280,   0, 2520,     0, -5544,   0, 3432]]
In [27]:
legendre.values('bgf')
Out[27]:
[[1,  0,  -2,    0,      6,       0,       -20,          0],
 [1,  2,   4,    8,     16,      32,        64,        128],
 [1,  4,  22,  136,    886,    5944,     40636,     281488],
 [1,  6,  52,  504,   5136,   53856,    575296,    6225792],
 [1,  8,  94, 1232,  16966,  240368,   3468844,   50712992],
 [1, 10, 148, 2440,  42256,  752800,  13660480,  251113600],
 [1, 12, 214, 4248,  88566, 1899432,  41492284,  918172848],
 [1, 14, 292, 6776, 165136, 4139744, 105702976, 2734083968]]
 
In [40]:
legendre.succ('bgf')
Out[40]:
[[1],
 [2, 2],
 [4, 18, 6],
 [8, 128, 120, 20],
 [16, 870, 1690, 700, 70],
 [32, 5912, 21000, 16100, 3780, 252],
 [64, 40572, 247044, 310800, 128100, 19404, 924]] 
 
In [40]:
legendre.pred('bgf')
Out[40]:
[[1],
 [2, 2],
 [10, 18, 6],
 [108, 208, 120, 20],
 [1566, 3320, 2390, 700, 70],
 [28620, 66028, 55020, 21140, 3780, 252],
 [635860, 1568196, 1456896, 666540, 160440, 19404, 924]] 
 

Lah polynomials

A111596, bivariate EGF

In [28]:
x, t = SR.var('x, t')
lah = gfun(exp(x*t/(1-t)))
lah.as_egf(7)
Out[28]:
[1,
 x,
 x^2 + 2*x,
 x^3 + 6*x^2 + 6*x,
 x^4 + 12*x^3 + 36*x^2 + 24*x,
 x^5 + 20*x^4 + 120*x^3 + 240*x^2 + 120*x,
 x^6 + 30*x^5 + 300*x^4 + 1200*x^3 + 1800*x^2 + 720*x]
 
In [29]:
lah.coeffs('egf')
Out[29]:
[[1],
 [0,    1],
 [0,    2,     1],
 [0,    6,     6,     1],
 [0,   24,    36,    12,    1],
 [0,  120,   240,   120,   20,   1],
 [0,  720,  1800,  1200,  300,  30,  1],
 [0, 5040, 15120, 12600, 4200, 630, 42, 1]]
 
In [30]:
lah.values('egf')
Out[30]:
[[1, 0,  0,   0,    0,      0,       0,        0],
 [1, 1,  3,  13,   73,    501,    4051,    37633],
 [1, 2,  8,  44,  304,   2512,   24064,   261536],
 [1, 3, 15,  99,  801,   7623,   83079,  1017495],
 [1, 4, 24, 184, 1696,  18144,  220096,  2977216],
 [1, 5, 35, 305, 3145,  37225,  495475,  7306325],
 [1, 6, 48, 468, 5328,  68976,  997056, 15877728],
 [1, 7, 63, 679, 8449, 118587, 1846999, 31535371]]
 
In [45]:
lah.succ('egf')
Out[45]:
[[1],
 [1, 1],
 [-1, 1, 1],
 [1, -5, 0, 1],
 [1, 15, -11, -2, 1],
 [-19, -29, 70, -15, -5, 1],
 [151, -87, -299, 200, -10, -9, 1],
 [-1091, 1891, 504, -1449, 420, 14, -14, 1]]
 
In [45]:
lah.pred('egf')
Out[45]:
[[1],
 [1, 1],
 [0, 1, 1],
 [0, -1, 0, 1],
 [0, 2, -1, -2, 1],
 [0, -6, 5, 5, -5, 1],
 [0, 24, -26, -15, 25, -9, 1],
 [0, -120, 154, 49, -140, 70, -14, 1]]
 

Eulerian polynomials

A173018, bivariate EGF

In [31]:
x, t = SR.var('x, t')
eulerian = gfun((x-1)/(x-exp(t*(x-1))))  
print eulerian.as_egf(5)
eulerian.coeffs('egf')
Out[31]:
[1, 1, x + 1, x^2 + 4*x + 1, x^3 + 11*x^2 + 11*x + 1]
                  
[[1],
[1],
[1,   1],
[1,   4,    1],
[1,  11,   11,    1],
[1,  26,   66,   26,    1],
[1,  57,  302,  302,   57,   1],
[1, 120, 1191, 2416, 1191, 120, 1]]
In [32]:
eulerian.values('egf')
Out[32]:
[[1, 1, 1,  1,   1,     1,      1,       1],
 [1, 1, 2,  6,  24,   120,    720,    5040],
 [1, 1, 3, 13,  75,   541,   4683,   47293],
 [1, 1, 4, 22, 160,  1456,  15904,  202672],
 [1, 1, 5, 33, 285,  3081,  40005,  606033],
 [1, 1, 6, 46, 456,  5656,  84336, 1467376],
 [1, 1, 7, 61, 679,  9445, 158095, 3088765],
 [1, 1, 8, 78, 960, 14736, 272448, 5881968]]
 
In [49]:
eulerian.succ('egf')
Out[49]:
[[1],
 [-1, 0],
 [0, -1, 0],
 [2, 1, -1, 0],
 [0, 15, 5, -1, 0],
 [-16, -5, 65, 16, -1, 0],
 [0, -441, -175, 203, 42, -1, 0],
 [272, -749, -5971, -2044, 469, 99, -1, 0]]
 
In [49]:
eulerian.pred('egf')
Out[49]:
[[1],
 [-1, 0],
 [0, -1, 0],
 [1, 1, -1, 0],
 [6, 11, 5, -1, 0],
 [25, 64, 55, 16, -1, 0],
 [-16, 103, 260, 183, 42, -1, 0],
 [-2671, -5311, -3004, -29, 434, 99, -1, 0]]
 

The harmonic polynomials

A109822, bivariate EGF

In [33]:
x, t = SR.var('x, t')
harmonic = gfun(1 + x/(1-x)*(1/(1-x*t)^(1/x)-1/(1-x*t)))
print harmonic.as_egf(5)
harmonic.coeffs('egf')
Out[33]:
[1, x, 2*x^2 + x, 6*x^3 + 4*x^2 + x, 24*x^4 + 18*x^3 + 7*x^2 + x]
                  
[[1],
 [0, 1],
 [0, 1,  2],
 [0, 1,  4,   6],
 [0, 1,  7,  18,  24],
 [0, 1, 11,  46,  96,  120],
 [0, 1, 16, 101, 326,  600,  720],
 [0, 1, 22, 197, 932, 2556, 4320, 5040]]
 
In [34]:
harmonic.values('egf')
Out[34]:
[[1, 0,   0,    0,     0,       0,        0,          0],
 [1, 1,   3,   11,    50,     274,     1764,      13068],
 [1, 2,  10,   66,   558,    5790,    71370,    1019970],
 [1, 3,  21,  201,  2496,   38280,   699960,   14873880],
 [1, 4,  36,  452,  7412,  150580,  3653700,  103138980],
 [1, 5,  55,  855, 17430,  441030, 13341780,  469845180],
 [1, 6,  78, 1446, 35250, 1067874, 38702814, 1633558038],
 [1, 7, 105, 2261, 64148, 2263660, 95609640, 4704165480]]
 
In [53]:
harmonic.succ('egf')
Out[53]:
[[1],
 [1, 1],
 [1, 5, 2],
 [3, 31, 32, 6],
 [12, 254, 499, 222, 24],
 [60, 2570, 8665, 6886, 1704, 120],
 [360, 30990, 170280, 216159, 92126, 14520, 720],
 [2520, 434490, 3776220, 7218057, 4724608, 1252476, 136800, 5040]]
 
In [53]:
harmonic.pred('egf')
Out[53]:
[[1],
 [1, 1],
 [3, 5, 2],
 [29, 55, 32, 6],
 [481, 1022, 739, 222, 24],
 [12351, 28554, 23905, 9286, 1704, 120],
 [453649, 1120916, 1045100, 481359, 117326, 14520, 720]]
 

Further remarks on harmonic polynomials

Why call these polynomials 'harmonic polynomials'? Because they evaluate at x=1 to the harmonic numbers H(n) like this: H(n) = harmonic(n, 1) / n!.

In [35]:
P = harmonic.as_egf()
print [p(x=1)/factorial(n) for (n, p) in enumerate(P)]
Out[35]:
[1, 1, 3/2, 11/6, 25/12, 137/60, 49/20, 363/140, 761/280, 7129/2520, 7381/2520, 83711/27720]

The generating function of the harmonic numbers:

In [36]:
H = gfun(1-log(1-x)/(1-x))
print H.as_ogf()
Out[36]:
[1, 1, 3/2, 11/6, 25/12, 137/60, 49/20, 363/140, 761/280, 7129/2520, 7381/2520, 83711/27720]

Note that these polynomials also give nice values at x = -1, the order of alternating group A_n, A001710.

In [37]:
print [(-1)^n*p(x=-1) for (n, p) in enumerate(P)]
Out[37]:
[1, 1, 1, 3, 12, 60, 360, 2520, 20160, 181440, 1814400, 19958400]

Generalized Lucas Numbers

A247505, parametrized LGF

In [38]:
x = SR.var('x')
genLucas = lambda n: -log((1+sum((-1)^(j+1)*x^j for j in (1..n)))^(-1))
for n in (0..9):
print gfun(genLucas(n)).as_lgf()
Out[38]:
[0, 0, 0, 0,  0,  0,  0,   0,   0,   0,    0,    0]
[0, 1, 1, 1,  1,  1,  1,   1,   1,   1,    1,    1]
[0, 1, 3, 4,  7, 11, 18,  29,  47,  76,  123,  199]
[0, 1, 3, 7, 11, 21, 39,  71, 131, 241,  443,  815]
[0, 1, 3, 7, 15, 26, 51,  99, 191, 367,  708, 1365]
[0, 1, 3, 7, 15, 31, 57, 113, 223, 439,  863, 1695]
[0, 1, 3, 7, 15, 31, 63, 120, 239, 475,  943, 1871]
[0, 1, 3, 7, 15, 31, 63, 127, 247, 493,  983, 1959]
[0, 1, 3, 7, 15, 31, 63, 127, 255, 502, 1003, 2003]
[0, 1, 3, 7, 15, 31, 63, 127, 255, 511, 1013, 2025]

Note that the limiting case n → oo is A000225 and that the main diagonal is also this sequence. This is another case of compositional convergence.

In [39]:
A000225 = exp(2*x) - exp(x)
gfun(A000225).as_egf()   
Out[39]:
[0, 1, 3, 7, 15, 31, 63, 127, 255, 511, 1023, 2047]

Some Riordan arrays

n=2: A113214, n=3: A212634, parametrized bivariate LGF

In [40]:
x, t = SR.var('x, t')
rarr = lambda n: -log((1/x+sum((-1)^(j+1)*t^j for j in (1..n)))^(-1))

Since our enumeration is always relative to n ≥ 0 and k ≥ 0 whereas A113214 and A212634 are listed starting from n ≥ 1, k ≥ 1 we divide by 'x':

rarr(2)/x = (log(-t^2+t+1/x))/x

In [41]:
gfun(rarr(2)/x).coeffs('lgf')     
Out[41]:
[[],
 [1],
 [2, 1],
 [0, 3, 1],
 [0, 2, 4, 1],
 [0, 0, 5, 5, 1],
 [0, 0, 2, 9, 6, 1],
 [0, 0, 0, 7, 14, 7, 1]]
 

rarr(3) / x = (log(t^3-t^2+t+1/x))/x

In [42]:
gfun(rarr(3)/x).coeffs('lgf')   
Out[42]:
[[],
 [1],
 [2, 1],
 [3, 3, 1],
 [0, 6, 4, 1],
 [0, 5, 10, 5, 1],
 [0, 3, 14, 15, 6, 1],
 [0, 0, 14, 28, 21, 7, 1]]
 

Now, to what limit does the sequence of these triangles (in their non-truncated form) converge to for n → oo? It's A206735, a variant of Pascal's triangle!

In [43]:
x, t = SR.var('x, t')
A206735 = gfun((1-2*t+(1+x)*t^2)/(1-2*t+(1+x)*t^2-t*x))
print A206735.as_ogf(5)
A206735.coeffs('ogf')   
Out[43]:
[1, x, x^2 + 2*x, x^3 + 3*x^2 + 3*x, x^4 + 4*x^3 + 6*x^2 + 4*x]
                  
[[1],
 [0, 1],
 [0, 2, 1],
 [0, 3, 3, 1],
 [0, 4, 6, 4, 1],
 [0, 5, 10, 10, 5, 1],
 [0, 6, 15, 20, 15, 6, 1],
 [0, 7, 21, 35, 35, 21, 7, 1]]
 

Series inversion, the multiplicative inverse.

The call gfun(g, 'inv') returns an object which represents the multiplicative inverse of g. That is, seen as a formal power series, g multiplied with the inverse of g is the formal power series equivalent to 1. g has an inverse in this sense if and only if g(0) ≠ 0. In the case g(0) = 0 you will get the error message "ValueError: Series must have valuation zero for inversion."

Partition numbers

A000041, inverse OGF

In [44]:
g = lambda n: mul((1 - x^k) for k in (1..n))
n = 20
print gfun(g(n), 'inv').as_ogf(n)
Out[44]:
[1, 1, 2, 3, 5, 7, 11, 15, 22, 30, 42, 56, 77, 101, 135, 176, 231, 297, 385, 490]

Euler numbers

A122045, A155585, inverse EGF

In [45]:
x = SR.var('x')
euler = cosh(x)
s = gfun(euler, 'inv')
print s.as_egf()
Out[45]:
[1, 0, -1, 0, 5, 0, -61, 0, 1385, 0, -50521, 0]
In [46]:
x = SR.var('x')
gf = exp(-x)*cosh(x)
s = gfun(gf, 'inv')
print s.as_egf()
Out[46]:
[1, 1, 0, -2, 0, 16, 0, -272, 0, 7936, 0, -353792]

Swiss-Knife Polynomials

A153641, bivariate EGF

In [47]:
x, t = SR.var('x, t')
sk_poly = gfun(exp(x*t)*sech(t))
print sk_poly.as_egf(5)
sk_poly.coeffs('egf')
Out[47]:
[1, x, x^2 - 1, x^3 - 3*x, x^4 - 6*x^2 + 5]
                  
[[  1],
 [  0,    1],
 [ -1,    0,  1],
 [  0,   -3,  0,   1],
 [  5,    0, -6,   0,   1],
 [  0,   25,  0, -10,   0,   1],
 [-61,    0, 75,   0, -15,   0,  1],
 [  0, -427,  0, 175,   0, -21,  0,  1]]
 
In [48]:
sk_poly.values('egf')
Out[48]:
[n\k][0][1] [2]  [3]   [4]   [5]    [6]     [7] 
[0]   1, 0, -1,   0,    5,    0,   -61,      0, A122045
[1]   1, 1,  0,  -2,    0,   16,     0,   -272, A155585
[2]   1, 2,  3,   2,   -3,    2,    63,      2, A119880
[3]   1, 3,  8,  18,   32,   48,   128,    528, A119881
[4]   1, 4, 15,  52,  165,  484,  1395,   4372, 
[5]   1, 5, 24, 110,  480, 2000,  8064,  32240, A225116
[6]   1, 6, 35, 198, 1085, 5766, 29855, 151878, 
A000012,A001477,A005563,A058794,.. 
   

Note that the first two rows are the two flavors of the Euler numbers. Thus the Swiss-Knife polynomials can be seen as a generalization of the Euler numbers.

In [69]:
sk_poly.succ('egf')
Out[69]:
[[1],
 [1, 1],
 [0, 3, 1],
 [-2, 4, 6, 1],
 [0, -3, 19, 10, 1],
 [16, -14, 30, 55, 15, 1],
 [0, 63, 1, 200, 125, 21, 1],
 [-272, 274, 126, 511, 735, 245, 28, 1]]
 
In [69]:
sk_poly.pred('egf')
Out[69]:
[[1],
 [1, 1],
 [1, 3, 1],
 [3, 8, 6, 1],
 [17, 32, 29, 10, 1],
 [85, 189, 165, 75, 15, 1],
 [449, 1239, 1174, 585, 160, 21, 1],
 [3143, 8812, 9457, 5159, 1645, 301, 28, 1]]
  

Reversion, the compositional inverse.

The call gfun(g, 'rev') returns an object which represents the compositional inverse of g.

  • For reversion g (as a series) must have valuation one (the coefficient g(0) must be 0). The returned series is then the compositional inverse of g (with respect to the formal power series u with one nonzero coefficient, u(1) = 1).
  • If g is not invertible in the sense above (i. e. if g(0) != 0) then the reversion will be computed as follows:
    r = g / g[0]
    r = r.shift(1)    
    r = r.reversion()
    r = r.shift(-1)
    r = r * g[0]

If you wish to turn off this extension you can call

    g.strict_reversion(true)

and revert this by setting g.strict_reversion(false).

If strict reversion is in effect you will get instead the error message "ValueError: Series must have valuation one for reversion."

Note that the default behavior is the extended form as this is in the context of the OEIS more useful in many situations.

Large Schröder numbers

A006318, reversion OGF

In [49]:
x = SR.var('x')
schroeder_L = gfun((1 - x)/(1 + x), 'rev')
schroeder_L.as_ogf(9)
Out[49]:
[1, 2, 6, 22, 90, 394, 1806, 8558, 41586]

Generalized Motzkin numbers

  parametrized reversion OGF

In [50]:
x = SR.var('x')
genMotzkin = lambda n: 1/(1+sum(x^k for k in (1..n)))  
for n in range(9):
print gfun(genMotzkin(n), 'rev').as_ogf()    
Out[50]:
[1, 0, 0, 0,  0,  0,   0,   0,    0,    0,     0,     0]
[1, 1, 1, 1,  1,  1,   1,   1,    1,    1,     1,     1]
[1, 1, 2, 4,  9, 21,  51, 127,  323,  835,  2188,  5798]
[1, 1, 2, 5, 13, 36, 104, 309,  939, 2905,  9118, 28964]
[1, 1, 2, 5, 14, 41, 125, 393, 1265, 4147, 13798, 46476]
[1, 1, 2, 5, 14, 42, 131, 421, 1385, 4642, 15795, 54418]
[1, 1, 2, 5, 14, 42, 132, 428, 1421, 4807, 16510, 57421]
[1, 1, 2, 5, 14, 42, 132, 429, 1429, 4852, 16730, 58422]
[1, 1, 2, 5, 14, 42, 132, 429, 1430, 4861, 16785, 58708]

Limiting case n → oo Catalan numbers, A000108. Also note that the main diagonal are the Catalan numbers.

In [51]:
catalan = gfun((1-sqrt(1 - 4*x))/(2*x))
catalan.as_ogf() 
Out[51]:
[1, 1, 2, 5, 14, 42, 132, 429, 1430, 4862, 16796, 58786]

Searching the OEIS

Let's come back to our first example.

In [52]:
x = SR.var('x')
riordan = gfun(2/(1+x+sqrt((1+x)*(1-3*x))))
riordan.as_ogf()
Out[52]:
[1, 0, 1, 1, 3, 6, 15, 36, 91, 232, 603, 1585]

If you call as_ogf() with the additional parameter 'search=true' you get:

In [53]:
riordan.as_ogf(search=true)
Out[53]:
A005043 (1, 0, 1, 1, 3, 6, 15, 36, 91, 232, 603, 1585)
A099323 (1, 1, 0, 1, -1, 3, -6, 15, -36, 91, -232, 603)
A174297 (1, -1, -1, 0, -1, 1, -3, 6, -15, 36, -91, 232)
[1, 0, 1, 1, 3, 6, 15, 36, 91, 232, 603, 1585]

You will receive up to four proposals for related sequences from the OEIS (including the first terms so that you can immediately check the similarity of the terms). The prerequisite is that the computer is connected to the Internet. Of course the same works for the functions as_egf(), as_lgf() and as_bgf().

Exploring the generating function

Putting everything together we get the method gfun.explore(). The output has the format:

'op' as_xgf [0, 1, 2, ...]
A000000 (1, 1, 2, ...)
A111111 (1, 1, 1, ...)
A222222 (1, -1, -1, ...)
.....

'op' will be one of the eight operations

[None, 'rev','inv','exp','log','der','logder','int']

and 'as_xgf' one the four representations

['as_ogf', 'as_egf', 'as_lgf', 'as_bgf'].

All 32 combinations will be tested and those giving meaningful results will be reported. You have to be online to get results and it takes a while. The function will print 'Done!' when finished.

After the method has finished it displays a plot which is a kind of fingerprint of the generating function. A green path indicates that there are related sequences in the OEIS (which are listed in the output), a red path indicates that in this case a meaningful integer sequence exists which is apparently not in the database. In the other cases for one reason or another there is no related integer sequence.

In [54]:
x = SR.var('x')
riordan = (1+x-sqrt(1-2*x-3*x^2))/(2*x*(1+x))
gfun.explore(riordan)
Formal power series:  1/2*(x-sqrt(-3*x^2-2*x+1)+1)/((x+1)*x)

None as_ogf [1, 0, 1, 1, 3, 6, 15, 36, 91, 232, 603, 1585]
A005043 (1, 0, 1, 1, 3, 6, 15, 36, 91, 232, 603, 1585)
A099323 (1, 1, 0, 1, -1, 3, -6, 15, -36, 91, -232, 603)
A174297 (1, -1, -1, 0, -1, 1, -3, 6, -15, 36, -91, 232)
['A005043', 'A099323', 'A174297']

None as_egf [1, 0, 2, 6, 72, 720, 10800, 181440, 3669120]
None as_lgf [0, 0, -2, 3, -12, 30, -90, 252, -728, 2088, -6030]
None as_bgf [1, 0, 4, 8, 48, 192, 960, 4608, 23296, 118784]

rev as_ogf [1, 0, -1, -1, 0, 1, 1, 0, -1, -1, 0, 1]
A010892 (1, 1, 0, -1, -1, 0, 1, 1, 0, -1, -1, 0)
A128834 (0, 1, 1, 0, -1, -1, 0, 1, 1, 0, -1, -1)
A000484 (1, 1, 0, -1, -1, 0, 1, 1, 0, -1, -1, 0)
A000494 (0, 1, 1, 0, -1, -1, 0, 1, 1, 0, -1, -1)
['A010892', 'A128834', 'A000484', 'A000494']

rev as_egf [1, 0, -2, -6, 0, 120, 720, 0, -40320, -362880 ]
A212158 (1, 2, 6, 120, 720, 40320, 362880, 39916800, 87178291200]
['A212158']

rev as_lgf [0, 0, 2, -3, 0, 5, -6, 0, 8, -9, 0, 11]
A128214 (1, 0, 0, -2, 3, 0, -5, 6, 0, -8, 9, 0)
['A128214']

rev as_bgf [1, 0, -4, -8, 0, 32, 64, 0, -256, -512, 0, 2048]
A120580 (1, 0, -4, -8, 0, 32, 64, 0, -256, -512, 0, 2048)
A104538 (1, 0, -4, 8, 0, -32, 64, 0, -256, 512, 0, -2048)
['A120580', 'A104538']

inv as_ogf [1, 0, -1, -1, -2, -4, -9, -21, -51, -127, -323, -835]
A168051 (1, 0, -1, -1, -2, -4, -9, -21, -51, -127, -323, -835)
A001006 (1, 1, 2, 4, 9, 21, 51, 127, 323, 835, 2188, 5798)
A086246 (0, 1, 1, 1, 2, 4, 9, 21, 51, 127, 323, 835)
A168049 (1, 0, 1, 1, 2, 4, 9, 21, 51, 127, 323, 835)
['A168051', 'A001006', 'A086246', 'A168049']

inv as_egf [1, 0, -2, -6, -48, -480, -6480, -105840, -2056320]
A052735 (0, 0, 2, 6, 48, 480, 6480, 105840, 2056320, 46085760)
['A052735']

inv as_lgf [0, 0, 2, -3, 8, -20, 54, -147, 408, -1143, 3230]

inv as_bgf [1, 0, -4, -8, -32, -128, -576, -2688, -13056, -65024]
A103970 (1, 4, 8, 32, 128, 576, 2688, 13056, 65024, 330752)
['A103970']

der as_ogf [0, 2, 3, 12, 30, 90, 252, 728, 2088, 6030, 17435]
der as_egf [0, 2, 6, 72, 720, 10800, 181440, 3669120, 84188160]
der as_lgf [0, 2, -6, 36, -120, 450, -1512, 5096, -16704, 54270]
der as_bgf [0, 4, 12, 96, 480, 2880, 16128, 93184, 534528]
log as_egf [0, 0, 2, 6, 60, 600, 8520, 141120, 2792160, 63262080]

log as_lgf [0, 0, -2, 3, -10, 25, -71, 196, -554, 1569, -4477]
A246437 (1, 0, 2, 3, 10, 25, 71, 196, 554, 1569, 4477, 12826)
['A246437']

logder as_ogf [0, 2, 3, 10, 25, 71, 196, 554, 1569, 4477, 12826]
A246437 (1, 0, 2, 3, 10, 25, 71, 196, 554, 1569, 4477, 12826)
['A246437']

logder as_egf [0, 2, 6, 60, 600, 8520, 141120, 2792160, 63262080]
logder as_lgf [0, 2, -6, 30, -100, 355, -1176, 3878, -12552]
logder as_bgf [0, 4, 12, 80, 400, 2272, 12544, 70912, 401664]
int as_egf [0, 1, 0, 2, 6, 72, 720, 10800, 181440, 3669120]

int as_lgf [0, 1, 0, 1, -1, 3, -6, 15, -36, 91, -232, 603]
A099323 (1, 1, 0, 1, -1, 3, -6, 15, -36, 91, -232, 603)
A005043 (1, 0, 1, 1, 3, 6, 15, 36, 91, 232, 603, 1585)
A174297 (1, -1, -1, 0, -1, 1, -3, 6, -15, 36, -91, 232)
['A099323', 'A005043', 'A174297']

Done!

The plot which will now show up is given in the introduction above.