In Praise of Sequence (Co-)Algebra and its implementation in Haskell
Kieran Clenaghan

TL;DR
This paper introduces sequence algebra, demonstrating its foundational role across mathematics and computer science, and provides a comprehensive Haskell implementation to facilitate understanding and experimentation.
Contribution
It consolidates various sequence algebra concepts into one accessible overview and offers a complete Haskell implementation as a teaching and experimentation tool.
Findings
Sequence algebra is foundational across multiple disciplines.
A complete Haskell implementation is provided for experimentation.
The paper invites broader mathematical engagement with sequence algebra.
Abstract
What is Sequence Algebra? This is a question that any teacher or student of mathematics or computer science can engage with. Sequences are in Calculus, Combinatorics, Statistics and Computation. They are foundational, a step up from number arithmetic. Sequence operations are easy to implement from scratch (in Haskell) and afford a wide variety of testing and experimentation. When bits and pieces of sequence algebra are pulled together from the literature, there emerges a claim for status as a substantial pre-analysis topic. Here we set the stage by bringing together a variety of sequence algebra concepts for the first time in one paper. This provides a novel economical overview, intended to invite a broad mathematical audience to cast an eye over the subject. A complete, yet succinct, basic implementation of sequence operations is presented, ready to play with. The implementation also…
Peer Reviews
No public reviews on file for this paper yet. If you reviewed it on a platform where reviews are public (OpenReview, ICLR, NeurIPS, ICML), you can paste yours below so the community can read it here.
Videos
No videos yet. Explain this paper in a talk, walkthrough, or lecture? Add one.
Taxonomy
TopicsLogic, programming, and type systems · Computability, Logic, AI Algorithms · Numerical Methods and Algorithms
In Praise of Sequence (Co-)Algebra and its implementation in Haskell
Kieran Clenaghan
Abstract
What is Sequence Algebra? This is a question that any teacher or student of mathematics or computer science can engage with. Sequences are in Calculus, Combinatorics, Statistics and Computation. They are foundational, a step up from number arithmetic. Sequence operations are easy to implement from scratch (in Haskell) and afford a wide variety of testing and experimentation. When bits and pieces of sequence algebra are pulled together from the literature, there emerges a claim for status as a substantial pre-analysis topic. Here we set the stage by bringing together a variety of sequence algebra concepts for the first time in one paper. This provides a novel economical overview, intended to invite a broad mathematical audience to cast an eye over the subject. A complete, yet succinct, basic implementation of sequence operations is presented, ready to play with. The implementation also serves as a benchmark for introducing Haskell by mathematical example.
1 Introduction
Consider these titles: Formal Power Series [64], Power Series, Power Serious [57], A Coinductive Calculus of Streams [72], and Concrete Stream Calculus [39]. The mixing of the classical and the modern in these papers is stimulating and suggests a re-telling of the elementary theory and application of sequences. Casting our net wider than the citations in those four papers, brings up a number of corroborating works, including [85, 8, 83, 84], in which the authors call attention to the intrinsic qualities and utility of an elementary calculus or algebra of sequences. We do more than re-advertise this work – we endeavour to tease out the common ground, emphasising economy of statement and notation, whilst embracing variety of approach.
Our aim is to attract those who are less well acquainted with sequence work, or those who are unfamiliar with Haskell or both. It is so that others can enjoy “messing about”, as Hayman [34] might put it, with sequences and their implementation. Elementary sequence algebra provides a good answer to the question, ‘What is the smallest coherent chunk of mathematics to set undergraduates to implement, from scratch, so that they get the greatest reward?’.
First we must say that sequence algebra is an umbrella title for algebraic manipulations of finite and infinite sequences, , over some given element set, . It encompasses, prominently, formal power series algebra, but is not restricted to it. A finite sequence, viewed as a sequence of coefficients for powers of , can be expressed as a formal polynomial. Thus , or we may say that is implemented by . Similarly, . A finite sequence can also be interpreted as an infinite sequence by appending an infinite sequence of zeros. An infinite sequence can be expressed as a formal power series:
[TABLE]
We write or for the element at position , called the th term of ; it is the coefficient of in the power series view. The zeroth term can also be written , but otherwise the notation is reserved for function application: let , then , but ; contrast . This example reveals that the symbol is overloaded, it stands for a function of type and also for another of type , and we must be careful to distinguish them.
It seems that in spite of Niven’s paper [64] receiving the Lester R Ford award, the algebra of formal power series (FPS) has not entered the standard introductory university texts in any substantial way. Niven’s paper has, however, been a key reference for the first chapters of both [36, 31], neither of which is standard undergraduate fare. In general, we find that elements of FPS/sequence algebra appear throughout a vast literature, but the algebra itself is treated minimally, perfunctorily, or is taken for granted, as might be expected in research work [21] and specialist texts [61, 2]. It also comes under generatingfunctionlogy [86, 32]. The term “generating function” has proven to be a bit awkward, because of the “function” part. Notice how many times Wilf [86] and others have to remind readers when convergence is not as issue. So, where some might use “generating function”, we use the plain “sequence expression”. The term “generating function” is more applicable when an analytic function interpretation is intended [19, Ch. VII]. However, we freely use the standard names of core analytic functions for their Taylor sequences, but rather than say, , we use just for the sequence.
The extent of material that fits into elementary sequence algebra is perhaps under-appreciated. Our goal is to raise appreciation through a modest “survey” of examples, presented in section 3. Various notations and proof-styles appear in the literature, and an effort has been made to be inclusive and to harmonise. The one-word term “sequence” is often preferred to the three-word “formal power series”, but both have their merits, the latter being preferred in the multivariate case, and when formal variable substitution is involved.
The sequence algebra we exhibit is on the same elementary level as Niven’s paper [64]. Much detail has to be omitted so that we can cover more examples. Enough detail is included to convey the foundational concreteness of the topic, and omitted detail is in the literature. The Haskell implementation is given in full in section 4 so that the reader can be in no doubt about how succinct it is, and can type it all up (or download it), and “own” it. The more mathematically-inclined reader may dwell on section 3, and reflect on the potential of a sequence algebra topic in the mathematical curriculum. The more programming-inclined may dwell on sections 4, 5 and 6, and engage with the proposition that sequence algebra provides an excellent vehicle for exploring learning-mathematics-through-programming, or vice-versa. There is great scope for making a contribution to the consolidation, refinement, and application of sequence algebra as an introductory subject.
To help catch, at a glance, some of the things that come under sequence algebra, we have included a number of tables. Tables 1, 2 and 3 are instantly recognisable as belonging to a calculus text, but here, uncommonly, the objects being related are sequences, not analytic functions. Of course, they herald identities that hold for analytic functions, but in agreement with Niven [64] and Tutte [84], there is something to celebrate in the fact that the identities can be established on very elementary grounds. There is more to celebrate in tables 4 and 5, because many of the sequence expressions therein have a dual interpretation as a set-theoretic structure specification [25]. Yet more satisfaction is to be had from table 7, because the solutions to the defining differential equations for the core sequences transliterate trivially into Haskell definitions [58].
Therefore a grounding in sequence algebra and its implementation surely pays off. This claim is validated at least in the study of the two texts, Concrete Mathematics [32] and Analytic Combinatorics [25]. There we see numerous examples where sequence algebra is at play, and the implementation can be used for testing, for reinforcement, or just for fun. Some of these appear in the next section. For example, in item W we derive the bivariate power series that appears in [32, sect. 7.6]. This generates a sequence such that is a polynomial, and . That is, . It is striking how accessible the mathematics behind is, and how easy it is to define the infinite and in a program.
2 The basics
Two sequences and are equal if they are equal at all indices: . There are many instances when it is obvious that a statement is subject to universal quantification, and in such cases we leave the part to be inferred by the reader. Becoming fluent with the clumsy-looking coefficient extraction operator, , pays dividends [31, 51]. It obeys the precedence rules, , , and . Moreover, it is a linear operator:
[TABLE]
The generalisation will be used to identify a term in a bivariate sequence. Let be the tail or shift-left operator: . In formal power series language, , and ; this is referred to as the head-tail property (in [72] it is the “fundamental theorem of stream calculus”, see section 3, item P). We also have and the head-tail expansion rule, . We are free to mix notations – here is the definition of convolution product, , in which, typically, the is suppressed:
[TABLE]
Observe that, since is the only non-zero element of , we have
[TABLE]
Thus , and can be viewed as a right-shift operator. The absorption law, , is simple but effective. The product in both and is convolution product, is pointwise addition, the element is automatically identified with the singleton sequence, , as required, and . A recursive equation for product is easily derived (and just as easily translated into Haskell); is abbreviated to :
[TABLE]
Sequences, , over an integral domain or field (known from context) form an integral domain [64, 55] ( is the standard notation for formal power series in over ). We will keep in mind. The subsets and comprise sequences with zeroth term 0, 1, and non-zero, respectively. A subset of comprises sequences in which , that is . Unique square (and th) roots exist for sequences in . Sequence composition is defined for . A unique compositional inverse, , called converse, exists for . The notation follows [6] and distinguishes converse from multiplicative inverse . The latter exists for . Differentiation, , is term-wise, as for formal polynomials: . A little induction gives the Maclaurin expansion rule: . From the definition of as a right inverse to , , we deduce . Setting , the fundamental theorem of sequence calculus (FTC) is immediate:
[TABLE]
The familiar rules in tables 1 and 2 have easy sequence-algebraic proofs (the third -product rule is called the differential Baxter axiom in [10]). For example, here is a typical proof of the differential composition rule, or chain rule [36, Ch. 1]. A proof by coinduction is presented for contrast in item Q of the next section. Let , then,
[TABLE]
3 Sequence Algebra examples
The following itemization (A-Z) of snippets provides a brief survey of the character of sequence algebra. It is, of course, only a small fraction of the subject.
(A) Sequence algebra is foundational in the sense that it is a low-level concrete extension of arithmetic. To appreciate this, try making the following simpler. Define by the sequence differential equation . Then, by the Maclaurin rule, . Define by the sequence difference equation ; then, by the head-tail property, ; the notation is based on the Kleene star [19]. Let where lgn (for which there is no established name other than ) is the converse of ; that is, . Observe that implies , so . The FTC gives , and the coefficients can be calculated:
[TABLE]
Some well-known rules relating to and , derivable from the differential equation for using sequence algebra, appear in table 3 (preconditions are omitted to avoid clutter). Most of these are meticulously proven by Niven [64]. However, Niven does not use composition , but by using composition and its associativity and distributivity laws [36], his theorem 17 and proof can be rendered as follows: let ,
[TABLE]
Proof of Euler’s identity, , illustrates appeal to the uniqueness of solution to certain differential equations. Let , , and . Then both and satisfy , and therefore must be equal. De Moivre’s theorem follows:
[TABLE]
(B) A counting sequence, , is either ordinary, or exponential, . In either case, counts the number of objects of size generated by some structure specification, . In the former case , and in the latter case . Roughly speaking, a structure is built from nodes, and its size is the number of nodes it has. The nodes may be labelled or unlabelled. Exponential sequences are used for labelled objects because, in that case, convolution product automatically counts all possible labellings in making an ordered product. Let and count labelled structures (generated by some and , respectively); then ordered pairs of such structures are counted by
[TABLE]
The ordered -fold product, , has counting sequence . Ordered lists of -objects are counted by . If the order does not count, then we use
The fact that permutations can be written as sets of cycles can be made explicit in the definition of the counting sequence for permutations [25, 11]:
[TABLE]
Just put and . The sequence perm is regarded as an exponential sequence, . Removal of the factorial divisors is performed by , and , , the number of permutations of symbols. There are cyclic permutations of symbols, and the exponential counting sequence for these is:
[TABLE]
(C) The number of ways, , of inserting brackets into a list of symbols, subject to well-formedness, is counted by the Hipparchus-Schröder sequence [76, 79], . This can be derived from the specification of a bivariate counting sequence for Schröder trees:
[TABLE]
Here . The coefficient of in schroeder(z,u) gives the number of Schröder bracketings of symbols using pairs of brackets. Observe that equation (2) can also be read [25] as a set-theoretic specification of Schröder trees, with and naming different kinds of nodes. Using , the above definition of derives, via the quadratic formula, from the equation . Here is a foretaste of computing the Schröder numbers in Haskell, which is explained in section 4:
schroeder = z + u*(pluralList ‘o‘ schroeder)
> takeBiv [1..6] schroeder
[[0],[1,0],[0,1,0],[0,1,2,0],[0,1,5,5,0],[0,1,9,21,14,0]]
> takeW 11 ((1+x-sqroot(1-6*x+x^2))/4)
[0,1,1,3,11,45,197,903,4279,20793,103049]
This reveals, for example, , that is 9 bracketings of 5 symbols with 2 pairs of brackets. One can see that the elements of the second sequence are totals of corresponding elements of the first. We remark that the sequence is called the large Schröder sequence [25, p. 474] (it solves ).
(D) The dual interpretation of sequence expressions as set-theoretic structure specifications, is exploited in [24, 25] (influenced by [44]). One might write the set-theoretic counterpart of say, , as , indicating by the initial capital letters a set-theoretic interpretation. Essentially this is done in [25], but for brevity we only give the equations defining the counting sequences. Table 4 lists some univariate examples, and table 5 some bivariate ones. These can be typed more-or-less verbatim into Haskell, as illustrated in section 5. Many more could be lifted from chapters I-III of [25], from the appendices of [4], and from [15, 31, 79, 76].
Let us examine a less-than-obvious expression, ascents from table 5, the origin of which illustrates the principle of inclusion-exclusion [25, 90]. It counts permutations according to the number of ascents. For example, the permutation of has 4 up-runs demarcated with vertical bars, 3 descents, and 5 ascents. If there are descents then there are up-runs. The reversal of a permutation with descents delivers a permutation with ascents. The count is called an Eulerian number, and gives the number of permutations of with ascents [32]. To come up with the sequence expression, first note that an up-run with at least one ascent corresponds to a plural set. The counting sequence for such a set in which the of records the ascents is . Let us specify permutations in which some parts of up-runs are identified as sets, and other elements are undistinguished: . Now propose that is the exact counting sequence we are after, then the inclusion-exclusion principle says that and , which is cited in the table.
(E) The sequence defined by is the Maclaurin expansion of the tangent function (the is explicit just for emphasis). The numbers in are called tangent numbers. The tangent numbers count certain kinds of alternating permutations (or ordered binary trees) [78]. One can define also by , where is shuffle (or Hurwitz [47]) product. Convolution product (1) and shuffle product can be defined in head-tail form ():
[TABLE]
The rule matches and we have the Leibniz formulae
[TABLE]
Applying to the latter gives the pointwise definition of (note that when and are scalars):
[TABLE]
A shuffle inverse, , derives from the specification together with the shuffle product rule (in exactly the same way that the rule for is derived):
[TABLE]
(F) Let denote the ring , of sequences over some field (of characteristic 0) with the availability of inverses implied. Then is an integro-differential algebra [10], and so too is , where is the right-shift operator: . The transform is an isomorphism between them, and is a formal Laplace transform [67, 26]. In the previous example, the equation defining is transformed by into the equation defining . The sequence of factorial numbers , , can be defined by applying to to get . From this we deduce . Observe, for :
[TABLE]
Also, leads to the differential equation for the factorials:
[TABLE]
Furthermore,
[TABLE]
(G) We recall a classic proof [64] of the binomial theorem. Let , (the falling factorial), and (the rising factorial):
[TABLE]
A corollary is [x^{k}](x^{*})^{r}=[x^{k}](1-x)^{-r}=(-1)^{k}(-r)^{\underline{k}}/k!=r^{\overline{k}}/k!=\left(\begin{array}[]{c}r+k-1\\ r-1\end{array}\right). This result, and , are basic ingredients in the search for th term formulas. They are applied next.
(H) A Lagrange inversion formula [77, 59, 60, 29] gives an expression for the th term of the converse of a sequence. For example, let , then , so is the converse of . Below is the Lagrange inversion formula for this case, followed by its application to the counting sequences for Catalan trees, , and Cayley trees, :
[TABLE]
For a history of the Catalan numbers, see [66]. Cayley trees are rooted versions of the connected acyclic graphs counted by Cayley in [13]. Cayley also counted the Catalan trees in [12], and the first part of Niven [64] sets out to legitimise the sequence algebra underlying Cayley’s proof (Niven cites [42], not Cayley; but Raney [71] cites both).
A slightly more general statement of Lagrange inversion is that it solves (equivalently ) for , where . The theory of Lagrange inversion sometimes employs Laurent series – series with negative powers (or sequences with negative indicies). In the following formula for the th term of , the coefficient of (called the residue) is identified:
[TABLE]
Let , , and ; then Lagrange inversion applied to , gives, for , the th term formula . This result specialises, when , to a variant of the cycle lemma [17], called Raney’s lemma in [32], which has a history in statistics [69] related to Ballot numbers [25, p. 68]. There are various Lagrange inversion formulas and many proofs; [14] takes an approach that also facilitates proof of Faà di Bruno’s formula formula for [43].
(I) The (forward) difference operator, produces the sequence of term-to-term differences, . The definition of an anti-difference operator on sequences is calculated [37] as a right identity to , with :
[TABLE]
Thus, computes all the prefix sums of (including the empty one). Applied to we get:
[TABLE]
There follows the fundamental theorem of discrete calculus (FDC) on sequences: s=s_{0}^{\tiny\mbox{\tiny\,\bullet\,}}+\Sigma\Delta s;\ s=\Delta\Sigma s, where a^{\tiny\mbox{\tiny\,\bullet\,}}=ax^{*} is the sequence with everywhere.
(J) Here are the to translations extended to powers:
[TABLE]
The identity \left(\begin{array}[]{c}n\\ k\end{array}\right)=[x^{n}]x^{k}/(1-x)^{k+1} turns equation (9) into the Euler expansion, . This expansion can also be derived from , plus the facts , and (see [3] and items K and P):
[TABLE]
Let , whence , and apply Euler’s expansion to ,
[TABLE]
It is instructive to use this to approximate .
(K) The sequence is the sequence of Newton coefficients [3]. It may also be specified by . The operator , called the Newton transform in [3], has the converse , called the Binomial transform in [39]. The identity holds because the head of is 1, and the tail is
[TABLE]
The following products introduce two new rings, the Hadamard ring (S_{R},+,-,\odot,0,1^{\tiny\mbox{\tiny\,\bullet\,}}), and the infiltration ring [3]:
[TABLE]
The rules in table 6 apply, and is an isomorphism between the Hadamard and infiltration rings. The following is a point-wise definition of :
[TABLE]
The proof that is a morphism from to the new product can be re-imagined as a discovery of what the definition of should be. The morphism presumption is signalled on the right below.
[TABLE]
(L) The following defines permutation cycle numbers, \left[\begin{array}[]{c}n\\ k\end{array}\right]=n![u^{k}z^{n}]\mbox{\sf cycles}, and set partition numbers \left\{\begin{array}[]{c}n\\ k\end{array}\right\}=n![u^{k}z^{n}]\mbox{\sf parts}. These are also called Stirling numbers of the first and second kind, respectively.
[TABLE]
The well-known recurrences [32],
[TABLE]
translate, using and , into
[TABLE]
where and are the partial differentiation operators with respect to and . To see this, note that \left[\begin{array}[]{c}n+1\\ k\end{array}\right]=(n+1)![u^{k}z^{n+1}]c=n![u^{k}z^{n}]D_{z}c, \left[\begin{array}[]{c}n\\ k-1\end{array}\right]=n![u^{k-1}z^{n}]c=n![u^{k}z^{n}]uc, and so on. The recurrences can be checked: first, ; and second, . We may write . The cycles recurrence can also be written , which follows from .
(M) A factorial polynomial uses falling factorials instead of powers. For example, let , then the falling factorial counterpart is . Coefficients in are identified by , for example .
The symbols and are overloaded as operators on factorial polynomials and obey rules identical to those for and on polynomials: let denote a polynomial in falling factorials, then and . The fundamental theorem of the discrete calculus on factorial polynomials is immediate: . In [32], the theorem provides one of seven ways of deducing the polynomial for summing squares: given , apply to both sides,
[TABLE]
Note that if is a polynomial th term formula for sequence , , then and .
(N) An analogue of the Maclaurin rule holds: . The latter equality involves yet another interpretation of : . Gregory-Newton (interpolation) formulas for of degree follow; the second (see also (9)) uses n^{\underline{k}}/k!=\left(\begin{array}[]{c}n\\ k\end{array}\right):
[TABLE]
Let be the sequence , for which we seek the polynomial such that . Then the above expansions produce the polynomial(s) in (17). By contrast, the Euler expansion (16) produces the sequence expression .
(O) We have seen [x^{k}]x^{\overline{n}}=\left[\begin{array}[]{c}n\\ k\end{array}\right], so we can express the polynomial for in terms of cycle numbers, and by change of signs, also the polynomial for :
[TABLE]
This shows how to translate falling factorials into powers. The converse is
[TABLE]
and for a proof see [9, p. 343] and [32, p. 262].
(P) Infinite sequences are called streams when they are identified with the final object in a category of head-tail coalgebras [41, 72]. This accounts for the name “stream” in the following:
[TABLE]
The co-algebraic stream calculus [72] introduces a proof principle called coinduction. For example, the identity used in the proof of (16) can be proved using coinduction (it can also be proved from the point-wise definition of and the binomial theorem). Here is the gist of the coinductive proof. Propose the relation . This is used as a coinductive hypothesis. Head-equality holds, . The proof is completed by showing that the tails are equal under the hypothesis, signified below by the use of :
[TABLE]
The bracketed (co-) in the paper’s title indicates that we only touch lightly on co-algebraic concepts. There is more to coinduction than the above example suggests, and we refer to the survey [33] for background.
(Q) One can check from the pointwise definitions of and that . Alternatively, equality can be proved by showing that these expressions satisfy the same head-tail equations. The head-tail equation for is calculated:
[TABLE]
Hence, and . Now let . We find , and . Thus, since they satisfy the same head-tail equations.
To give a little more feeling for the coinduction game, let us reveal the machine-level minutiae that proves . We use head-tail properties such as (see section 4, equation (33)). We will also make use of . Head equality is confirmed:
[TABLE]
Tails are proved equal under the coinductive hypothesis, :
[TABLE]
(R) Coinduction is also used in [73] to show how continued fractions can be obtained from combinatorially-inspired automata. For example, the tangent sequence can be defined by , where . Thus can be displayed as a continued fraction:
[TABLE]
More combinatorially-inspired continued fraction expressions for sequences appear in [23, 31, 73]. Below is one for ( removes the factorial divisors of powers of ).
[TABLE]
Setting and gives a continued fraction for the factorials, .
(S) A th-order linear ordinary homogeneous differential equation,
[TABLE]
can be written . Similarly, a difference equation (also called a recurrence equation) can be written . Let be the reverse of . Klarner [48] presents this fact: the solution to is
[TABLE]
where inits are the initial elements of . Also
[TABLE]
For example, has solution , and , the Maclaurin expansion for , that is, the solution to . Another example is , where is a Chebyshev polynomial [9] in . Then, , and
[TABLE]
By the translation rules of item J, difference equations can be written using either or . The equation transforms into , or , where . The converse is , reflecting . Clearly, .
(T) A sequence is called rational if it is the quotient, , of polynomials; it is called a LODE solution, written LODE(), if it is a solution of a linear ordinary homogeneous difference equation; and it is called recognizable if it is the behaviour of a finite automaton. Then,
[TABLE]
Following [19], a finite automaton can be modelled as a system of linear equations over sequences, . Here, matrix records transition labels connecting pairs of states, and is a vector of sequences, one for each state, with initial values . The solution is where
[TABLE]
is the Kleene star. Notice that can be viewed as a matrix of sequences or as a sequence of matrices. Using , we get and Cramer’s rule applies: (column replaced by ). Thus is rational. Justification of the above equivalences is completed by noting that a LODE can be transformed into a system of linear equations. We remark that a quotient of polynomials, , can also be written as the solution to a system of linear equations [72].
(U) Let be the characteristic polynomial of matrix . The Cayley-Hamilton theorem [19, 49] can be stated as , or as . This will hold if, taking the sequence of matrix powers, , now as a matrix of sequences, we have , which in turn holds if . We have . So we are done if we come up with an such that
[TABLE]
Let , and , where is the vector with 1 at position and zero elsewhere. Then, and Cramer’s rule delivers the we are looking for:
[TABLE]
(V) Consider the matrix exponential, as a matrix of sequences. We know that solves , and . Cayley-Hamilton says that , where is the characteristic polynomial of , of degree , say. By uniqueness of solution, we have [54, 56, 53] if and . Let be a vector of sequences such that and . Set
[TABLE]
Clearly , and because
[TABLE]
(W) The elements of the sequence are called Bernoulli numbers. The corresponding recurrence is calculated from :
[TABLE]
Bernoulli numbers are used by Graham et al [32] for the most impressive of their deductions of the polynomial that sums squares – impressive because it defines the formulas for all powers at once. Let be the sequence such that is the sum of the th powers of the naturals to . Then
[TABLE]
Now replace by and by to get the expression advertised in the introduction:
[TABLE]
Then is a polynomial of degree in , and .
(X) Observe that is non-zero whilst all the other odd-degree coefficients of appear to be zero. Perhaps if we make zero then we will have a sequence which can be proved to be even (i.e. with zeros at odd positions). Adding to cancels :
[TABLE]
Recall , so , from which eveness, , can be deduced. Thus,
[TABLE]
Now , and, using and , we get
[TABLE]
With a bit of analysis (reals, an analytic function with period , and uniqueness of series expansion), one can deduce another series for , due to Euler. The omitted analysis [50, 1] is hidden in the first equals sign:
[TABLE]
Equating coefficients with those in the expansion (29) yields, for ,
[TABLE]
Therefore, the values of Riemann’s at even positive integers is given by
[TABLE]
(Y) The Formal Taylor Theorem may be expressed:
[TABLE]
Write . Let , then . Differentiate with respect to : . Note that . Let , then . Differentiate again: . Let , then . And so on. The Maclaurin expansion is the special case with , and the Taylor expansion of is an instance of the binomial theorem. Lipson [55] uses the theorem in the application of Newton’s iterative root-finding algorithm to polynomial equations over sequences (see also [70]).
(Z) The following manipulations, originating with Lagrange, have a captivating charm (even if they lack rigour). We adapt them from [32] to show that elementary sequence algebra plays a role through to the final chapter of that book (where, however, things become more demanding). In the Formal Taylor theorem, let be a polynomial, , , and employ an operator style:
[TABLE]
Putting together with , suggests . Then applied to is , so . Expanding this, and writing for the first term (since ), gives a “template” version of the Euler-Maclaurin summation formula [32, 9].
[TABLE]
Now introduce limits:
[TABLE]
An application to gives yet another derivation [32] of the sum-of-squares formula:
[TABLE]
The way the limits appear on the summation sign has significance: . The definite summation symbol follows the pattern of definite integration:
[TABLE]
Let’s add to both sides of (31) and separate out :
[TABLE]
The Euler-Maclaurin formula can also be applied to non-polynomial functions. Let us illustrate this, without justification. To compute , set and then apply (32) to :
[TABLE]
Applying the formula up to gives .
4 A programming delight
McIlroy [57, 58], influenced by [45] and others, has gifted us some “tiny gems” of program definitions for implementing sequence manipulations. The definitions are written in Haskell, and are effortlessly derived by mathematical reasoning. A textbook introduction appears in [18]. We want to entice the reader to type up and experiment with the Haskell code (but a down-loadable file is available). The code has been tested in the Haskell GHCi system, and also in the Hugs98 system (an older system, but well-suited to beginners). Both GHCi and Hugs98 are freely available on the web at www.Haskell.org.
In this section we present all of the definitions, thus duplicating some of the contents of [57, 58]; however, there are modifications and additions. The fact that the definitions have no pre-requisites, other than the standard Haskell Prelude, means that one can take “deep” ownership, building things from the ground up. This contrasts to using a sophisticated computer algebra system – something perhaps for the newcomer to move on to with greater appreciation.
Haskell [68] has evolved to be a fairly large and sophisticated language, but we shall stick to a modest subset. It is expected that the reader can comprehend Haskell from examples. The language gives types to objects and variables, and within context, the most general type is used. Haskell’s lists are used to represent sequences (some may prefer to introduce a new type for sequences, but that introduces an overhead which we want to avoid). In Haskell, head-tail decomposition becomes s0:s’. Here are some list-processing functions:
take n _ | n<=0 = []
take _ [] = []
take n (s0:s’) = s0: take (n-1) s’
map f [] = []
map f (s0:s’) = f s0 : map f s’
iterate f z = z: iterate f (f z)
foldr f z [] = z
foldr f z (s0:s’) = f s0 (foldr f z s’)
scanl op q s = q: (case s of
[] -> []
s0:s’ -> scanl op (op q s0) s’)
zip (s0:s’) (t0:t’) = (s0, t0): zip s’ t’
zip _ _ = []
zipWith op s t = [op sn tn | (sn,tn) <- zip s t]
These definitions implement the following functions which feature in the algebra of program calculation [7, 6]:
[TABLE]
The types deduced are
take :: Int -> [a] -> [a]
map :: (a -> b) -> [a] -> [b]
iterate :: (a -> a) -> a -> [a]
foldr :: (a -> b -> b) -> b -> [a] -> b
scanl :: (a -> b -> a) -> a -> [b] -> [a]
zip :: [a] -> [b] -> [(a,b)]
zipWith :: (a -> b -> c) -> [a] -> [b] -> [c]
Type expressions are built from type names such as Int, type variables such as a, and type constructors such as -> (which associates to the right). Two more examples of type constructors are: [a] is the type for lists of objects of type a, and [(a,b)] is the type for lists of pairs of objects. Clearly, functions can take functions as arguments, in which case they are called higher-order. Lazy evaluation is used, so that for example, scanl will produce the first element, q, of the result without needing to know anything about its list argument, s. The definition of zipWith illustrates the so-called list comprehension. An alternative definition uses map and uncurry:
uncurry :: (a -> b -> c) -> (a,b) -> c
uncurry op p = op (fst p) (snd p)
zipWith op s t = map (uncurry op) (zip s t)
The partner to uncurry is curry f x y = f (x,y). An alternative definition illustrates use of a lambda expression: curry f = \x y -> f (x,y). The reader may like to supply the type. These two functions are so-named because Haskell Curry was an early advocate of the associated equivalence [40]. The Haskell Standard Prelude defines zipWith without using zip, and then defines zip = zipWith (,).
The following specifies that a type a is classified as Num if it has the operations (or methods) listed here:
class Num a where (+), (-), (*) :: a -> a -> a negate, abs, signum :: a -> a fromInteger :: Integer -> a x - y = x + negate y negate x = 0 - x
All of the foregoing definitions are in the Standard Prelude. From here on, the code needs to be supplied. The program file starts with a few specified lines: the first line hides the Prelude definition of cycle because we are going to re-define it for other purposes; the second line says we need rational numbers; the third line gives the order in which to resolve ambiguity in numerical data.
import Prelude hiding (cycle)
import Data.Ratio
default (Integer, Rational, Double)
We start by declaring how sequences, [a], become an instance of Num. A prerequisite is that a is an instance of Eq and Num, indicated by (Eq a, Num a) =>. The definition of (-) is derived from negate.
instance (Eq a, Num a) => Num [a] where
negate = map negate
f+[] = f
[]+g = g
(f0:f’)+(g0:g’) = f0+g0 : f’ + g’
[]*_ = []
(0:f’)*g = 0 : f’*g
_*[] = []
(f0:f’)*g@(g0:g’) = f0*g0 : (f0*|g’ + f’*g)
fromInteger c = [fromInteger c]
abs _ = error "abs not defined on sequences"
signum _ = error "signum not defined on sequences"
Observe that addition is not defined by f+g = zipWith (+) f g (why?). Convolution product is derived from (1), but there are some things to note. Firstly, if then the zeroth term of the result is 0 and is delivered immediately. This may be regarded as a controversial quirk, but it enables certain equations to be used directly, as in the following (Catalan) example – in examples, definitions (which are placed in a program file) are interspersed with interactive requests for expression evaluation, indicated by the prompt “> ”.
x :: Num a => [a]
x = [0,1]
b = 1 + x*b^2
> take 8 b
[1,1,2,5,14,42,132,429]
Secondly, the notation g@, is read as “g as”. Thirdly, there are clauses for finite sequences – the empty list behaves here like zero (but note that 0 is embedded as [0]). Fourthly, the term becomes an explicit scalar product using *|, which is defined as an infix operator with precedence 7 (the same as , and higher than +). The definition contains (a), illustrating the creation of a function by partial application of an operator (called sectioning).
infix 7 *|
(*|) :: Num a => a -> [a] -> [a]
a *| f = map (a*) f
A function like map is said to be polymorphic because any type can be assigned to its type variables (subject to consistency). By contrast, scalar multiplication (*|) has a qualified (constrained or parametric) polymorphic type: its type variable can range over only instances of class Num. The type stated could be omitted because it can be inferred due to the presence of *. On the other hand, if the explicit type given to x above was omitted, then Haskell would infer x::[Integer] and this is a monomorphic type which would restrict the use of x. With the qualified polymorphic type, x can appear in an expression where a sequence of elements of type N is expected, as long as N is an instance of Num. Any instance N of Num must provide a fromInteger method that shows how to embed integers into N, so x would be interpreted as [N.fromInteger 0, N.fromInteger 1].
The Num class invites comparison with the specification of the signature of a ring. Likewise, Haskell’s Fractional class may be compared to a ring-with-division, because a (partial) division operator (/), or a multiplicative inverse (recip), is required. Rational numbers form the archetypal instance of Fractional, and any instance F must show how to embed the rationals in F by defining fromRational :: Rational -> F. Division on sequences, , requires calculating the quotient satisfying :
[TABLE]
Now we can say, at least approximately, how sequences become a ring-with-division:
instance (Eq a, Fractional a) => Fractional [a] where
recip f = 1/f
_/[] = error "divide by zero."
[]/_ = []
(0:f’)/(0:g’) = f’/g’
(_:f’)/(0:g’) = error "divide by zero"
(f0:f’)/g@(g0:g’) = let q0=f0/g0 in q0:((f’ - q0*|g’)/g)
fromRational c = [fromRational c]
These simple definitions confront us with some of the difficulties in coding a satisfactory division operation that works for both finite and infinite sequences. One should investigate questions like: are and faithfully implemented? To keep things simple, compromises have to be made.
Arithmetic and the convolution product rule are used to calculate a head-tail definition for square root, . The starting point is , and we calculate and :
[TABLE]
We shall trivialise and restrict square root to fractional sequences with constant term 1. In the following code, the first clause is suggested by the identity , and the more general is handled by recursion. An alternative definition of square root is derived in [58] by differentiating , rearranging and then integrating (which the reader may like to try).
sqroot (0:0:f’’) = 0:sqroot f’’
sqroot f@(1:f’) = 1:(f’/(1+sqroot f))
Sequence composition, , is expanded thus:
[TABLE]
When is infinite, is not computable unless . When we get
[TABLE]
However, is computable for when is finite (, a polynomial). So we admit a potentially non-terminating clause and it is up to us to use it with care:
[] ‘o‘ _ = []
(f0:f’) ‘o‘ g@(0:g’) = f0: g’*(f’ ‘o‘ g)
(f0:f’) ‘o‘ g@(g0:g’) = [f0] + (g0*|(f’ ‘o‘ g))+
(0:g’*(f’ ‘o‘ g))
The definition reveals to be a left and right identity of composition. Composition distributes leftwards through sum, product, and quotient.
To calculate the converse, , expand the composition :
[TABLE]
Hence, , and
[TABLE]
The program code is:
converse(0:f’) = g where g = 0: 1/(f’ ‘o‘ g)
For the reciprocal of to be defined, it is necessary that is invertible, which entails that is invertible. The set of such “conversible” sequences forms a group, .
The transforms and are given names e2o and o2e, respectively [18]. Here they are, together with some other useful sequences:
e2o f = zipWith (*) f facs
o2e f = zipWith (/) f facs
from :: Num a=>a->[a]
from = iterate (+1)
nats, pos, zeros, facs :: Num a=>[a]
nats = from 0
pos = from 1
zeros = 0:zeros
facs = scanl (*) 1 pos
Differentiation and integration enjoy the appropriately succinct definitions,
deriv f = zipWith (*) pos (tail f)
integ f = 0:zipWith (/) f pos
The definitions and have the following solutions in Haskell. An x is affixed to prevent name clashes with existing names (for example exp in Haskell implements the function ). One can test by checking the first few terms of their difference.
expx :: (Eq a,Fractional a) => [a]
expx = 1 + integ expx
starx :: (Eq a, Num a) => [a]
starx = 1 : starx
> takeW 6 (starx - e2o expx)
[0,0,0,0,0,0]
A rational is presented in Haskell as a%b. The elements of expx are rationals, and e2o removes the factorial divisors, yielding [1%1,1%1, …]. The following defines takeW n which is take n preceded by the conversion of whole rationals into integers (the (.) is function composition, and properFraction is in the Prelude).
makeWhole r = case properFraction r of
(n,0) -> n
otherwise -> error "not whole"
makeAllWhole = map makeWhole
takeW n = take n . makeAllWhole
Table 7 contains further core sequences defined by differential equations. All should be given the type (Eq a, Fractional a) => [a], like expx above. The core sequence , which we defined earlier, could be defined by starx = 1+integ (starx^2), since (but its elements would then be fractional). For two more examples, let us calculate definitions for and .
[TABLE]
[TABLE]
The latter uses the Pythagorean identity, , which follows from the defining differential equations. Taking initial values into consideration, the solutions rendered in Haskell are immediate:
[TABLE]
Here are checks of (gd is the Guddermanian function) and .
> takeW 6 (expx - ((secx + tanx) ‘o‘ gdx))
[0,0,0,0,0,0]
> takeW 6 (deriv (converse sinx) - (1/(sqroot (1-x^2))))
[0,0,0,0,0,0]
A bivariate sequence, , may be regarded as a (potentially doubly-infinite) matrix, , of coefficients of . It is implemented as a univariate sequence, , of (homogeneous) polynomials such that is the diagonal, of . Thus, is represented by ( becomes , and is redundant). So, ; equivalently . The following depicts the to map on a portion of :
[TABLE]
The ring-with-division and square root operations pertaining to are isomorphically transferred to the diagonal representation . The representations for and are, and . Here is represented by =pascal in Haskell,
u,z, pascal :: (Eq a, Num a) => [[a]]
u = [[0],[1,0]]
z = [[0],[0,1]]
pascal = starx ‘o‘ (u+z)
> take 6 pascal
[[1],[1,1],[1,2,1],[1,3,3,1],[1,4,6,4,1],[1,5,10,10,5,1]]
This displays [u^{n-k}z^{k}](u+z)^{*}=[x^{k}][x^{n}]s=\left(\begin{array}[]{c}n\\ k\end{array}\right). Commonly, we want to show a portion of , where , or perhaps more commonly, such that . For example, let
[TABLE]
Then n![u^{k}z^{n}]b=\left(\begin{array}[]{c}n\\ k\end{array}\right). The functions unDiag and unDiage2o transpose the -representation into the desired -representation (the reverse of the map depicted above). The function unDiage2o first removes factorial divisors associated with . The functions select and selectW take an argument saying what length to take from rows 0 to of . The version selectW converts whole rationals to integers. Bivariate counting sequences, , are typically zero for , and from these we select a lower triangular section. The schroeder sequence from section 3, item C, is an example which is ordinary in and , whilst ebinom below is exponential in . The sequence powerSums of polynomials for summing powers has a polynomial of order at position , so a lower trapezium section is selected.
list, pluralList :: (Eq a, Num a) => [a]
list = starx
pluralList = list - x - 1
schroeder = z + u*(pluralList ‘o‘ schroeder)
> select [1..6] (unDiag schroeder)
[[0],[1,0],[0,1,0],[0,1,2,0],[0,1,5,5,0],[0,1,9,21,14,0]]
ebinom = expx ‘o‘ (z+u*z)
> selectW [1..6] (unDiage2o ebinom)
[[1],[1,1],[1,2,1],[1,3,3,1],[1,4,6,4,1],[1,5,10,10,5,1]]
powerSums = ((expx ‘o‘ (u*z))-1)/((expx ‘o‘ z)-1)
> select [2..4] (unDiage2o powerSums)
[[0 % 1,1 % 1],[0 % 1,(-1) % 2,1 % 2],[0 % 1,1 % 6,(-1) % 2,1 % 3]]
A number of supporting functions are needed. The unDiag function expects its argument to be perfectly triangular, so padTri is first applied to fill out the triangle with zeros if necessary. Then transpose m detaches the heads of the rows of m, which make up the first column, c, and this becomes the first row of the result. A recursive invocation transposes the remaining sub-matrix, m’.
select s t = zipWith take s t
selectW s t = zipWith takeW s t
unDiag :: Num a=> [[a]]->[[a]]
unDiag = transpose . padTri
unDiage2o :: Fractional a=> [[a]]->[[a]]
unDiage2o = unDiag . (map e2o)
padTri t = zipWith padRight t [1..]
padRight r k = r++(take (k-(length r)) zeros)
transpose [] = []
transpose m = c:transpose m’
where (c,m’) = foldr detachHead ([],[]) m
detachHead ([r0]) b = (r0:fst b,snd b)
detachHead (r0:r’) b = (r0:fst b,r’:snd b)
There is plenty of room for adding functions to taste. Perhaps the main difficulty is deciding on an effective naming convention. Here are some examples.
takeEBivW r = (selectW r) . unDiage2o
takeEBiv r = (select r) . unDiage2o
takeBivW r = (selectW r) . unDiag
takeBiv r = (select r) . unDiag
Differentiation with respect to (or ) is performed by dz (or du). Below are the definitions, plus a test based on the set partitions recurrence from section 3, item L. Instead of using allZeros [1..6], the reader may wish to simply use selectW [1..6] and view the zeros (incidentally, one would then observe that the diagonal representation is not always a perfect triangle).
dz s = map deriv (tail s)
du s = map (reverse . deriv . reverse) (tail (padTri s))
set, nonEmptySet, emptySet :: (Eq a, Fractional a) => [a]
set = expx
emptySet = 1
nonEmptySet = set - emptySet
parts = set ‘o‘ (u*(nonEmptySet ‘o‘ z))
allEq c r = foldr (\a b-> (a==c) && b) True r
allZeros s t = allEq True (map (allEq 0) (select s t))
> allZeros [1..6] ((dz parts) - (u*parts +u*du parts))
True
5 Exercising the implementation
As it stands, the implementation facilitates a great range of experimentation. We will demonstrate a few concrete examples. It will be seen that the implementation is a valuable assistant in the study of otherwise theoretical material.
The definitions in tables 4 and 5 transliterate into Haskell. Here are some examples (see items B and D). One has to be vigilant about when to use e2o, take, takeW, select, selectW, unDiag, unDiage2o, etc. It is not necessary to give type declarations to all definitions, but it will be necessary for some. We leave that as a trial-and-error exercise.
cycle, perm :: (Eq a, Fractional a) => [a]
perm = starx
lg g = lgnx ‘o‘ (g-1)
cycle = lg starx
> takeW 6 (perm - (set ‘o‘ cycle))
[0,0,0,0,0,0]
cayleyTree = x*(set ‘o‘ cayleyTree)
connectedAcyclicGraph = cayleyTree - cayleyTree^2 / 2
> takeW 8 (e2o connectedAcyclicGraph)
[0,1,1,3,16,125,1296,16807]
infix 7 |^
(|^) :: (Eq a, Fractional a) => [a] -> a -> [a]
f |^ r = expx ‘o‘ (r *| lg f)
legendre = (1-2*u*z+z^2) |^ [-1%2]
> select [1..4] (unDiag legendre)
[[1 % 1],[0 % 1,1 % 1],[(-1) % 2,0 % 1,3 % 2],
[0 % 1,(-3) % 2,0 % 1,5 % 2]]
hermite = expx ‘o‘ (2*u*z-z^2)
> select [1..4] (unDiage2o hermite)
[[1 % 1],[0 % 1,2 % 1],[(-2) % 1,0 % 1,4 % 1],
[0 % 1,(-12) % 1,0 % 1,8 % 1]]
No attention has been paid to efficiency or prettiness of results – all the computations are expected to work on small examples, resulting in small results. Endless examples could be given related to items A-Z. We must choose only a few, and we aim for variety.
The factorials are defined in the previous section using scanl; below they are generated directly from their differential equation, by a continued fraction recurrence, and by shuffle inverse (see items E and P). Shuffle product can also be defined by (but that involves rationals, even when and are integer sequences).
fac = 1+x*fac + x^2*(deriv fac)
> take 6 fac
[1,1,2,6,24,120]
cf_fac = 1/(cfdenom 1)
where cfdenom n = 1 - x*(2*n-1)-x^2*n^2*(1/(cfdenom (n+1)))
> takeW 6 cf_fac
[1,1,2,6,24,120]
infix 7 |><| -- shuffle product
f@(f0:f’) |><| g@(g0:g’) = (f0 * g0): ((f’ |><| g)+(f |><| g’))
_ |><| [] = []
[] |><| _ = []
shInv f@(f0:f’) = (1/f0): (-f’ |><| ((shInv f) |><| (shInv f)))
> takeW 6 (shInv (1-x))
[1,1,2,6,24,120]
The Newton transform, , is an isomorphism between the Hadamard and infiltration rings (see item K). It is implemented here by (h2i, i2h), with a recursive variant, rh2i. We also translate the definitions of and directly to delta and sigma. Later, we shall define another version of , named prefixSums, which produces a finite result on a finite sequence. Let’s throw into our test the ubiquitous fibonacci sequence, defined by . The first part can be re-expressed , where , with solution (see item S). For illustration, we let Haskell take the last step.
h2i s = (1/(1+x)) |><| s
i2h s = (1/(1-x)) |><| s
rh2i s@(s0:s’) = s0: rh2i (delta s)
delta s = (tail s) - s
sigma s = x*starx*s
recur :: (Eq a, Num a) => a -> [a]
recur a = a:recur a
fib = (take 2 (rb*[1,1]))/rb where rb = reverse (x^2-x-1)
> takeW 10 (recur 1 + sigma (delta fib))
[1,1,2,3,5,8,13,21,34,55]
> takeW 10 (i2h (h2i fib))
[1,1,2,3,5,8,13,21,34,55]
The Hadamard product, |*|, and the infiltration product, |^| (and infProd) are now introduced, and testing them is left as an exercise.
infix 7 |*|
f |*| g = zipWith (*) f g
infix 7 |^|
f@(f0:f’) |^| g@(g0:g’) = (f0*g0): ((f’|^|g)+(f|^|g’))+(f’|^|g’)
_ |^| [] = []
[] |^| _ = []
infProd f g = h2i (i2h f |*| i2h g)
Translation to and from falling factorial polynomials can be exercised as follows. There are, of course, more efficient ways of generating the data used here (cycles, parts), but we stick to a simple translation of the mathematical definitions. In the first test, we use the fact (item N) that is representable by a polynomial of degree 3. The second test compares falling factorials and cycle numbers.
cycles = set ‘o‘ (u* (cycle ‘o‘ z))
fall n m = product [n-i | i<-take m nats]
alt :: Num a => a->[a]
alt r = r:alt (-r)
altMat m = zipWith op (alt 1) m
where op sign r = zipWith (*) (alt sign) r
monom2FacPoly = takeEBiv [1..] parts
facMonom2Poly = altMat (takeEBiv [1..] cycles)
toFacPoly p = sum (zipWith (*|) p monom2FacPoly)
fromFacPoly p = sum (zipWith (*|) p facMonom2Poly)
squaresFacPoly= o2e (take 4 (h2i [0,1,5,14,30,55]))
> fromFacPoly squaresFacPoly
[0 % 1,1 % 6,1 % 2,1 % 3]
> [fall x i | i<- [0..5]] == take 6 facMonom2Poly
True
The Maclaurin and Taylor expansions (item Y) can be coded and tested:
maclaurin f = o2e (map head (iterate deriv f))
taylor f = map o2e (zp (map (‘o‘ u) (iterate deriv f)))
where zp (g0:g’) = g0 + z* (zp g’)
bsinx, tsinx :: [[Rational]]
bsinx = sinx ‘o‘ (u+z)
tsinx = taylor sinx
> select [1..8] bsinx == select [1..8] tsinx
True
Let us move beyond the A-Z items and look at some other examples. The Logan polynomials [32, sect. 6.5], have the tangent numbers as constant terms. Here they are, defined by a closed expression, , and by an iteration.
logan = (((sinx ‘o‘ z)+u*(cosx ‘o‘ z))/
((cosx ‘o‘ z)-u*(sinx ‘o‘ z)))
> takeEBivW [2..5] logan
[[0,1],[1,0,1],[0,2,0,2],[2,0,8,0,6]]
loganPolys = iterate (\p -> (1+x^2) * deriv p) x
> take 4 loganPolys
[[0,1],[1,0,1],[0,2,0,2],[2,0,8,0,6]]
The Entringer triangle, [81, 78], has the tangent numbers on the first column (disregarding the first element), and the secant numbers on the diagonal. Below, the triangle is generated first by a backwards and forwards (boustrophedonic) computation of partial sums, then as the diagonal (homogeneous) presentation of coefficients of (named zigzags in table 5. The bivariate is exponential in both and , and can be shown [32, ex. 6.75]. Forward partial sums are prefix sums. Earlier, in item I, we met for computing them, and we used this above to define sigma. But that operator always results in an infinite sequence, even when applied to a finite one. So here we use a different definition.
prefixSums = scanl (+) 0
suffixSums = reverse.prefixSums.reverse
alternate f g a = a:alternate g f (f a)
entringer = alternate suffixSums prefixSums [1]
> take 7 entringer
[[1],[1,0],[0,1,1],[2,2,1,0],[0,2,4,5,5],[16,16,14,10,5,0],
[0,16,32,46,56,61,61]]
zigzags = (((sinx ‘o‘ u) + (cosx ‘o‘ u))/(cosx ‘o‘ (u+z)))
ue2o :: Fractional a => [a]->[a]
ue2o = reverse.e2o.reverse
> selectW [1..7] (map e2o (map ue2o zigzags))
[[1],[1,0],[0,1,1],[2,2,1,0],[0,2,4,5,5],[16,16,14,10,5,0],
[0,16,32,46,56,61,61]]
The Moessner sieve generates the sequence , given a positive integer . Kozen and Silva [52] cite a variety of proofs including sequence-calculational [38] and coinduction methods [63]. Let us see how easily we can implement some of the computations in [52]. There it is shown that the Moessner procedure can be described as the computation of a succession of bivariate sequences, , usefully represented in diagonal (homogeneous) form, , and that . The sequence of triangles begins with Pascal’s triangle, , represented in diagonal form by . Then the triangle-to-triangle step, , is: take the row , representing , and compute representing . Here is the computation of the first three triangles, followed by the selection of sn!!r!!r from the first 5 triangles. The function x2z converts to in bivariate diagonal form (there are many ways of doing this).
x2z rho = sum (zipWith (\c zn->[[c]]*zn) rho zPowers)
where zPowers = (iterate (*z) 1)
moessnerT r = iterate (\s -> (x2z (s!!r))*pascal) pascal
> select [5,5,5] (moessnerT 4)
[[[1],[1,1],[1,2,1],[1,3,3,1],[1,4,6,4,1]],
[[1],[1,5],[1,6,11],[1,7,17,15],[1,8,24,32,16]],
[[1],[1,9],[1,10,33],[1,11,43,65],[1,12,54,108,81]]]
nats2Power r = [sn!!r!!r | sn <- moessnerT r]
> take 5 (nats2Power 4)
[1,16,81,256,625]
The function moessnerT is easily changed to one which produces the -indexed sequence representing , and this makes way for a generalisation. The iteration step is , and the iteration starts with , representing .
moessnerH r = iterate (\rho -> ((x2z rho)*pascal)!!r) 1
> select [5,5,5,5] (moessnerH 4)
[[1],[1,4,6,4,1],[1,8,24,32,16],[1,12,54,108,81]]
Kozen and Silva generalise Moessner’s theorem to encompass theorems by Long and Paasche [52]. In the generalised implementation, there are two new parameters, (regarded as univariate, to be converted to bivariate by x2z), and , a sequence of non-negative integers. The iteration step implements the following recurrence, in which the final subscript indicates the selection of the homogeneous polynomial of degree :
[TABLE]
Thus, rather than a simple iteration, we scan along , because step requires . Let , be the leading coefficient of (which we extract using last, since the highest-order coefficient is at the end). The generalised theorem entails: (a) when and we get Moessner’s result, ; (b) when and , we get Long’s result, ; and (c) when and , we get Paasche’s result, . Here is a rather succinct implementation.
ksmlp h0 d = map last (scanl step h0 d)
where step hn dn = ((x2z hn)*pascal)!!((length hn - 1)+dn)
moessner r = ksmlp 1 (r:zeros)
long a b r = ksmlp [b,a-b] (r:zeros)
paascheFac = ksmlp 1 [1,1..]
superFac = ksmlp 1 [1,2..]
The above computations convey some Haskell by example, and demonstrate a wealth of experimentation assisted by sequence operations. The core set of definitions are kept to a minimum, so that they are manageable in one file, and should not daunt beginners. In keeping to this principle, we have not implemented an equivalent of formal Laurent series, so we cannot accommodate a sequence for (and , and so on). However, we can define . Then, with reference to item X, let , and test , and (Gaussian rationals, introducing , are in the next section):
xcotx, xcothx :: (Eq a, Fractional a) => [a]
xcotx = (x*cosx)/sinx
xcothx = (x*coshx)/sinhx
xcth r = [r]*(x*(coshx ‘o‘ ([r]*x)))/(sinhx ‘o‘ ([r]*x))
> take 10 xcothx == take 10 ((xcth (1%2)) ‘o‘ (2*x))
True
> take 10 (xcth (1%2)) == take 10 ((xcth (1%2)) ‘o‘ (-x))
True
> take 10 xcotx == take 10 (xcth i)
True
Sometimes there is simply extra work to be done to convert a sequence expression into a form acceptable by our definitions. For example, the following expression for counting permutations by number of valleys is derived in [22]:
[TABLE]
This fails to compute in our implementation for three reasons (can you spot them?). But, by using the double-angle identity for , and , it can be manipulated into the following form [20], which does compute:
[TABLE]
valleys = r/(r - (tanhx ‘o‘ (z*r))) where r = sqroot (1-u)
> takeEBivW [1..6] valleys
[[1],[1,0],[2,0,0],[4,2,0,0],[8,16,0,0,0],[16,88,16,0,0,0]]
The question of how to circumscribe a minimal core set of definitions that perhaps manifest a timeless quality, is a challenging one. It seems only too easy to keep adding stuff, as the next section testifies.
6 Building on the implementation
Implementing sequence algebra is an example of mathematics-programming synergy, as found for example, in [62, 55, 80, 74, 65, 87, 82, 18]. One should note the chronology of language use: [62] uses Fortran, [55] uses pseudo-Algol, [80] uses Pascal, [74] uses Standard ML, [87] uses Maple, [82] uses Scheme, and [65, 18] use Haskell. Haskell is one of the most recent and ambitious in the evolution of programming languages. The story of its development [40] is an informative account of collaborative design in a scientific context. It clearly reveals the tensions between the pursuit of elegant tried-and-tested universal concepts, and pragmatically-motivated more complex and speculative features.
One has to face the fact that Haskell presents the casual newcomer with subtleties, some of which cause bafflement. This slightly detracts from our goal, but also means that the implementation of sequence algebra is a fine benchmark test: Haskell ought to host it well for relative beginners. There are two prominent sources of subtleties: lazy evaluation and type classes. The former might be discovered in working with infinite matrices, for example try rewriting transpose. The latter is likely to cause the most frustration. One could write an elucidation of potential “surprises” centred around implementing sequence algebra. That is beyond our scope, but we draw attention to the fact that some type declarations can be omitted, and some not. To take just one example, the final test of the previous section, take 10 xcotx == take 10 (xcth i), does not go through if the type declaration for xcotx is omitted (then the system doesn’t know to translate the rationals in xcotx to Gaussian rationals for comparison). On the other hand, we may omit an explicit type for xcot and use the test
makeReal (r:&0) = r
makeReal _ = error "not real"
makeAllReal g = map makeReal g
> take 10 xcotx == makeAllReal (take 10 (xcth i))
True
However, if the g is omitted from the definition of makeAllReal, then makeAllReal is given a different type and the test fails to type-check. Of course, such things have interesting explanations, but they are potentially off-putting for beginners.
These remarks notwithstanding, one cannot resist adding to the implementation in a myriad of ways. Here are a few next-steps, which the author has already taken, and which are left as fruitful exercises.
- •
Translate [87], and elements of [80], to use Haskell.
- •
Introduce Gaussian rationals as an instance of Num and Fractional, and test De Moivre’s theorem (item A). Here is part of a definition and a test of Euler’s identity:
infix 6 :&
data Gaussian a = a :& a deriving (Eq, Read, Show)
i :: (Eq a, Num a) => Gaussian a
i = 0:&1
ix :: (Eq a, Num a) => [Gaussian a]
ix = [0,i]
instance (Num a) => Num (Gaussian a) where
-- define negate, +, abs, signum, fromInteger
(x:&y) * (x’:&y’) =(x*x’-y*y’) :& (x*y’+y*x’)
instance (Fractional a) => Fractional (Gaussian a) where
(x:&y) / (x’:&y’) = (x*x’+y*y’) / d :& (y*x’-x*y’) / d
where d = x’*x’ + y’*y’
fromRational a = fromRational a :& 0
> take 10 (cosx + [i]*sinx) == take 10 (expx ‘o‘ ix)
True
- •
Introduce an instance, Shuffle a, of class Num, so that one can write s |><| t as S s * S t, and shuffle power as (S s)^n. Extend the following code, making Shuffle a an instance of Fractional. The first test below illustrates shuffle power. The second test involves the secant numbers, . These can be defined (see items E and F) by applying to the differential equation for to give , and since we get the Haskell secNums = 1:secNums |><| tanNums (where tanNums=e2o tanx). Contrast this to the use of S:
newtype Shuffle a = S [a] deriving (Eq, Read, Show)
unS (S s) = s
instance (Eq a, Num a) => Num (Shuffle a) where
negate (S s) = S (negate s)
(S s) + (S t) = S (s+t)
(S s) * (S t) = S (s |><| t)
fromInteger n = S [fromInteger n]
abs _ = error "abs undefined on Shuffle"
signum _ = error "signum undefined on Shuffle"
> takeW 6 (unS ((S starx)^2))
[1,2,4,8,16,32]
tanNums = e20 tanx
secNums = 1:unS (S secNums * (S tanNums))
> takeW 10 secNums
[1,0,1,0,5,0,61,0,1385,0]
- •
Introduce matrix computations. To keep the definitions simple, use the type [[a]] for a matrix, and presume, controversially, that it is used responsibly, in the sense that a matrix is presented as a list of rows of agreed length. Transpose is already defined in our implementation (written to work also for infinite matrices). Operations to define include determinant, characteristic polynomial, adjugate, Gaussian elimination, and different methods of inversion. Then one can test computations in proofs of the Cayley-Hamilton theorem, and experiment with bivariate Lagrange inversion (using Jacobians).
- •
Sequences of sequences can become confused with matrices, so it is instructive to define:
data Matrix a = M [[a]] | D a deriving (Eq, Read, Show)
instance (Eq a, Num a) => Num (Matrix a) where
negate (M m) = M (map (map negate) m)
negate (D r) = D (negate r)
(M a) + (M b) = M ...
... clauses for + and *
fromInteger n = D (fromInteger n)
The idea is that if s is a square matrix of type [[a]], then we can have M s. Definitions of addition, M s + M t, and multiplication, M s * M t, can (with dereliction of duty) assume that s and t are square of the same dimension. The element D r stands for the square diagonal matrix (of any dimension) with r along the diagonal. The instance definitions of addition and multiplication each require four clauses (MM, DM, MD, DD), negate has two clauses (M, D):
- •
Rewrite part III of [55] to use Haskell, making good use of classes and instances to reflect the algebraic structure. At one level this can be approached as a program translation exercise, and is rewarding in demonstrating Haskell to be a good host language. At other levels it invites study of a good bit of theory (Euclidean domains, finite fields, Chinese Remainder Theorem, interpolation, homomorphic image schemes, Fast Fourier Transform, and Newton’s algorithm applied to power series).
Further to these tried-and-tested steps, there is, of course, unlimited scope for add-ons. Related software can be found in the Hackage repository of the Haskell website (www.Haskell.org).
7 Concluding remarks
It is clear that sequence algebra serves calculus: many sequence identities foretell relationships between analytic functions; it serves combinatorics: many counting sequences for discrete structures can be derived by sequence algebra; and it serves computation: it expresses the behaviour of certain kinds of automata; it leads to interpolation methods and summation formulae, and supports program calculation. The theory could hardly be more foundational, and constructing an implementation from scratch emphasises its concreteness, and has the potential to reinforce understanding.
We have exercised the implementation on examples from [32, 25], demonstrating that it makes a valuable companion to those texts. It could be applied to other texts, for example [15, 31, 4, 79, 77]. It can also serve as a centre-piece in a course on functional programming in mathematics. And, indeed, the experience of typing up and experimenting with the code, confronts one with intriguing issues in programming language design. There is zero-testing on sequence elements, which could be used to open a discussion on computability.
The on-line encyclopaedia of integer sequences [75] has hundreds of thousands of sequences. The sequences we have mentioned can be found using the OEIS search facility. It will be noticed that many of the sequences are accompanied by generating code written in various languages, including Haskell. One may like to investigate how many OEIS entries can be expressed in the “language” of tables 4 and 5. A Haskell interface to the OEIS is reported in [88].
Needless to say, to elaborate the topic more fully, with proof details and examples, one needs a book-sized exposition (draft portions of a book may be requested from the author). Beyond that, the obvious question is how to make a seamless progression. A few programming-oriented suggestions are in section 6. On the theory side, we must acknowledge that sequence algebra is so low in the mathematical hierarchy, that it doesn’t determine a narrow range of follow-up topics. Nevertheless, we mention a few. One is the classification of sequences, taking a lead from [33] and [76, Ch. 6]. Related to this is the computer algebra work done under the heading “generating functions” or “holonomic functions” [35, 46]. It remains to construct a bridge from the elementary level of the present paper to the use of a computer algebra package.
Established results on differential equations, including computer-algebraic, may be revisited with an eye to drawing out those which become particularly accessible when specialised to sequences. One suggestion is to bring the method of characteristics as used, for example in [22], into common parlance for sequence work. Another is to find a smooth passage from the level of the present paper to results obtained using the language of Species, for example those in [4, 70] (an introduction to Species for Haskell programmers is [89]).
Various multivariate directions beckon, including formal languages [5, 3] and multivariate Lagrange inversion [30]. We have also arrived at the threshold of analysis but we have not crossed it, except for bringing into item X. It is natural to ask whether fluency in infinite sequences, as promoted here, has any bearing on how students approach Cauchy sequences and analytic functions. Related to this is the progression from chapter 1 to chapter 2 in [36] (and chapter VII of [19]). On another tack, one may use sequence algebra to motivate abstract algebra. For example, Eilenberg [19, ch. XVI, sect. 10] gives a proof of the Cayley Hamilton theorem using module concepts, and module concepts are used in [26, 27, 28] – papers whose titles echo [48, 49], but which involve a quantum-leap in mathematical sophistication. As a final remark, we note that the eponymous Haskell B. Curry, also abstracted from concrete operations on formal power series [16].
Acknowledgements
This work originated (some years ago) when I was an occasional visitor at the University of York. I am greatly indebted to Colin Runciman for providing that opportunity, and to Colin, Jeremy Jacob, and Detlef Plump for encouragement. Special thanks are due to Daniel Siemssen, Patrik Jansson, Tim Sears and Peter Thiemann for comments on work related to this paper. (Also, if you are an anonymous JFP reviewer of an earlier related paper, then my thanks to you too!) Tim Sears has placed a version of the Haskell code on www.GitHub.com (under TimSears/SequenceAlgebra).
The reference list from the paper itself. Each links out to its DOI / PubMed record.
- 1[1] M. Aigner and G.M. Ziegler. Proofs from THE BOOK, 3rd edn. Springer, 2004.
- 2[2] W. Basler. Formal Power Series and Linear Systems of Meromorphic Differential Equations . Springer, 2000.
- 3[3] H Basold, H Hansen, J-É Pin, and J Rutten. Newton series, coinductively: a comparative study of composition. Mathematical Structures in Computer Science , pages 1–29, 2017.
- 4[4] F. Bergeron, G. Labelle, and P. Leroux. Combinatorial species and tree-like structures , volume 67 of Encyclopaedia of Mathematics . Cambridge University Press, 1998. Translated from 1994 original in French.
- 5[5] J. Berstel and C. Reutenauer. Rational Series and their Languages , volume 12 of EATCS Monographs on Theoretical Computer Science . Springer Verlag, 1988.
- 6[6] R. Bird and O. de Moor. Algebra of Programming . Series in Computer Science. Prentice Hall International, 1997.
- 7[7] R.S. Bird. Algebraic identities for program calculation. Computer Journal , 32(2):122–126, 1989.
- 8[8] L. Brand. A Division Algebra for Sequences and Its Associated Operational Calculus. The American Mathematical Monthly , 71(7):719–728, 1964.
