atlas Library · Script File
lazy_lists.at
This file demonstrates how axis can handle lazy infinite lists (of any type)
Definitions in source order
infinite_list, infinite_node type
set_type T [
infinite_list
= (->infinite_node) { defers creating of |inf_node| until called with () }
, infinite_node
= (T head, infinite_list thunk) { initial term, thunk for remaining terms }
]Fields: head, thunk
inf_list type
set_type inf_list = infinite_list<int>
inf_node type
set_type inf_node = infinite_node<int>
series
initial
get initial |n| terms of the list, and return them as ordinary list
prepend
shift
also defined in hodge_tensor.at, hodgeParamPol.at, laurentPolynomial.at
constant_term
coefficient
also defined in hodgeParamLaurentPol.at, hodgeParamPol.at, hodge_functions.at
extend
extend_0
extend_0 ([int] pol) = inf_listseries_0
series_0 : inf_listadditive unit for power series
series_1
series_1 : inf_listmultiplicative unit for power series
X
X : inf_listneutral element for power series composition
also defined in cyclotomic_Lie_algebra.at, bracket.at
inf_ones
inf_ones : inf_listinfinite list of '1', algebraically 1/(1-X)
arithmetic_progression
arithmetic_progression (int stride)more general then |ones|, we can define arithmetic and geometric progressions
geometric_progression
geometric_progression (int lambda)It can be important to avoid evaluating the thunk defining an infinite list more than once, but instead store the values that have already been computed. Indeed this will make it possible to define a non-pure function as thunk that simply assumes that each successive call is done to produce the coefficient following the one of the previous call; this assumes that no access to the function is exported other than the one given to the |memoize| function below. Another application is when we want to solve a recursion like that of Fibonacci by directly referring, via a |shift|, to previous values of the list under construction. This remains delicate, since a simple application of |memoize| will not suffice, and probably will not often prove to be the best choice of strategy to solve a recurrence relation. The function |memoize| adds the necessary storage on top of an infinite list: before actually calling the thunk, it defines a variable that can store the node produced, but initially stores nothing. The first time the memoized function is called, the thunk is called and the result stored, from which further calls will retrieve it. The magic comes from applying |memoize| recursively to the tail, before storage.L62
memoize
Formal power seriesL94
sum
rec_fun sum (inf_list f, inf_list g) = inf_listlazy sum of two infinite lists
also defined in basic.at, sommers.at, character_tables.at, cyclotomic_Lie_algebra.at
scale_by
scale_by (int a) = (inf_list->inf_list)downscale_by
downscale_by (int n) = (inf_list->inf_list)+
+ = sum@(inf_list,inf_list)also in this file at line 116, line 117; also defined in basic.at, extParamPol.at, modules.at, ratmat.at, cyclotomic.at, polynomial.at, hodgeParamLaurentPol.at, hodgeParamPol.at, laurentPolynomial.at, cyclotomic_Lie_algebra.at, cyclotomicMat.at, bracket.at, hodge_functions.at
-
- = (inf_list->inf_list)also in this file at line 119, line 120, line 121; also defined in basic.at, extParamPol.at, modules.at, ratmat.at, cyclotomic.at, polynomial.at, hodgeParamLaurentPol.at, hodgeParamPol.at, laurentPolynomial.at, cyclotomicMat.at, hodge_functions.at
+ 2 overloads
+ (int n,inf_list f) = inf_list+ (inf_list f,int n) = inf_listalso in this file at line 114; also defined in basic.at, extParamPol.at, modules.at, ratmat.at, cyclotomic.at, polynomial.at, hodgeParamLaurentPol.at, hodgeParamPol.at, laurentPolynomial.at, cyclotomic_Lie_algebra.at, cyclotomicMat.at, bracket.at, hodge_functions.at
*
* (int n,inf_list f) = inf_listalso in this file at line 135; also defined in basic.at, extParamPol.at, complex.at, modules.at, hodge_tensor.at, tits_centralizer.at, stable.at, synthetic.at, Weylgroup.at, group_operations.at, ratmat.at, tits.at, twisted_root_datum.at, cyclotomic.at, polynomial.at, hodgeParamLaurentPol.at, hodgeParamPol.at, laurentPolynomial.at, cyclotomic_Lie_algebra.at, cyclotomicMat.at, bracket.at, hodge_functions.at, sparse.at
- 3 overloads
- (int n,inf_list f) = inf_list- (inf_list f,int n) = inf_list- (inf_list f,inf_list g) = inf_listalso in this file at line 115; also defined in basic.at, extParamPol.at, modules.at, ratmat.at, cyclotomic.at, polynomial.at, hodgeParamLaurentPol.at, hodgeParamPol.at, laurentPolynomial.at, cyclotomicMat.at, hodge_functions.at
\
\ (inf_list f,int n) = inf_listalso defined in basic.at, polynomial.at
arithmetic of $\Z[[X]]$, using |inf_list| to represent the elementsL124
multiply
multiply (inf_list f, inf_list g) = inf_listalso defined in tits.at
*
* = multiply@(inf_list,inf_list)also in this file at line 118; also defined in basic.at, extParamPol.at, complex.at, modules.at, hodge_tensor.at, tits_centralizer.at, stable.at, synthetic.at, Weylgroup.at, group_operations.at, ratmat.at, tits.at, twisted_root_datum.at, cyclotomic.at, polynomial.at, hodgeParamLaurentPol.at, hodgeParamPol.at, laurentPolynomial.at, cyclotomic_Lie_algebra.at, cyclotomicMat.at, bracket.at, hodge_functions.at, sparse.at
multiply_by
multiply_by ([int] pol) = (inf_list->inf_list)divide_by
divide_by ([int] pol) = (inf_list->inf_list)also in this file at line 202; also defined in basic.at, polynomial.at
divide
divide (inf_list N, inf_list denom) = inf_listWe provide two ways to divide power series $N$ by $D$, with constant term $1$. The first is done similarly to |multiply|, but instead of retaining an increasing number of coefficients from both arguments, we retain them from $D$ and from the quotient $Q$; those from $N$ can be forgotten once used. As in |multiply|, this imperative style together with |memoize| allow the thunk being used to actually be the same non-pure function |m| at all levels. The second is more slick and pure, producing the thunk by calls of a recursive function with different arguments (representing the remainder at each step), each next one being produced from the previous by a transformation involving |sum| and |scale_by|. We need to ensure $D$ can be traversed multiple times without needlessly repeating its computation, which is done by applying |memoize| to the tail of $D$ (this can be unnecessary depending on how $D$ was constructed, but whether that is the case cannot be found out here). The ever more complicated thunk represents another, hidden, form of storage use that goes on here. All in all, while slick, this might be less efficient.
also defined in polynomial.at
divide_by
divide_by (inf_list f) = (inf_list->inf_list)also in this file at line 157; also defined in basic.at, polynomial.at
here the final result is not passed through |memoize|; if that is desired the caller should take care to do soL207
inverse
inverse (inf_list f) = inf_listalso defined in basic.at, combinatorics.at, ratmat.at, parameters.at, tits.at, affine.at, cyclotomic.at, Gaussian_elim.at, cyclotomic_Gaussian_elim.at
/ 3 overloads
/ = (inf_list->inf_list)/ (int n,inf_list f) = inf_list/ (inf_list f,inf_list g) = inf_listalso defined in basic.at, ratmat.at, cyclotomic.at, polynomial.at
^
^ (inf_list F,int n) = inf_listalso defined in basic.at, ratmat.at, tits.at, cyclotomic.at, polynomial.at, sparse.at
As a proof of concept we show how an infinite list can be recursively defined using itself (taking care to not make any coefficient require itself) and use |memoize| to avoid re-evaluating previous terms while computing new ones. The standard example is to compute the Fibonacci sequence F as 0, 1, followed by |sum(f,shift(1,F))| (where the first argument to |sum| gives the coefficient two steps before, the second argument the preceding coefficient). Using |memoize| remains delicate here, since the |rec_fun| syntax does not allow anything being done before introducing arguments, as might be thought: |rec_fun signs = inf_list: memoize(@:(1,@:(-1,signs)))| (NOT SYNTACTIC). And calling |memoize| inside the function body, necessarily multiple times if there are multiple recursive uses as is the case for Fibinacci, creates separate memo tables for each call (even with identical arguments) which solves nothing (as a general rule, the argument to |memoize| should not be allowed to be named and accessed elsewhere, lest the efficiency be lost when those other accessed recompute anyway what |memoize| stores). A solution is to tie the recursive knot by hand, rather than have |rec_fun| do it for us.L240
Fibonacci
Fibonacci = inf_listthe Fibonacci sequence can be defined |divide_by([1,-1,-1])(extend_0([0,1]))|, however we now show how it can be defined in a directly recursive fashion
Note that leaving out |memoize| would be possible here, but makes the runtime increase exponentially with the list length because of repeated evaluations of the same list elements. That inefficient version would also be obtained by | set rec_fun Fibo () = inf_node:(0,@:(1,sum(Fibo,shift(1,Fibo))))) |L265
and note Fibonacci is also |inverse([1,-1,-1].extend_0)|, easy and efficientL271
The pentagonal numbers are those obtained by adding to a perfect square $k^2$ either the "lower" |binom(k,2)| or "upper" |binom(n+1,2)| triangular number; call these the lower and uppoer pentagonal numbers for $k$. Euler's pentagonal series has entries $(-1)^k$ at indices the lower and upper pentagonal numbers for $k$, for every $k\in\N$, and $0$ at all other indices. The relavance of Euler's pentagonal series is that its inverse is the generating series for the number of partitions of a natural number. A practical way to generate it is to start at index 0, the upper pentagonal number for 0, with variables k=0, lower=false and a timer i=1. Then to generate a term, decrement the timer; if still positive return a term 0. Otherwise return (-1)^k, and if lower holds set the timer i:=k else (not lower) increment k and set i to the sum of the old and new values of k; also invert lower in all productive cases. The code below is a bit slicker and clearer.L273
pentagonal_series
pentagonal_series : inf_listn_partitions
n_partitions = (int->int)substitute
substitute (inf_list g) = (inf_list->inf_list)f->f[X:=g]
e.g., |substitute ([0,1,1].extend_0)(ones)| gives series 1/(1-X-X^2)L316
compositional_inverse
compositional_inverse (inf_list g) = inf_liste.g., compositional_inverse([0,1,-1].extend_0) solves $f-f^2=X$L329
series_precision
series_precision = 12show
use |series_precision| only when |f| is there
also defined in modules.at, K_Nilpotent.at, good_W_representatives.at, arthur_parameters.at, sub_cells.at, associated_variety_annihilator.at, geck_generic.at, L_packet.at, ratmat.at, Levi_subgroups.at, nilpotent_orbits.at, subgroups.at, poset.at, cyclotomic.at, polynomial.at, character_tables.at, springer_tables.at, hodgeParamLaurentPol.at, hodgeParamPol.at, laurentPolynomial.at, weak_packets.at, cyclotomic_Lie_algebra.at, cyclotomicMat.at, bracket.at, exceptional.at, nilpotent_posets.at
Generated from atlas-scripts at commit 648506c (2026-10-13).
Commented-out code, lines 15–21 (6 lines)