This site is supported by donations to The OEIS Foundation.

# Sequence Tools

This page is dedicated to links and code snippets for checking and formatting sequences.

## Contents

## Restricting a list to a fixed number of characters

Historically, the Data OEIS sequence entry field had enough terms to fill about three lines on the screen—maybe 260 characters including [decimal] digits, signs, commas and whitespaces (spaces and newlines; tabs NOT ALLOWED). For a larger number of terms, the contributors can submit a b-file containing an index and a term on each line and as many lines as needed.

### Mathematica

*(From: T.D. Noe)*

OEISTrim[lst_List, maxLen_Integer: 260] := Module[{newLst = {}, len = 0}, Do[len = len + 2 + Length[IntegerDigits[term]] + Boole[term < 0]; If[len <= maxLen, AppendTo[newLst, term], Break[]], {term, lst}]; newLst]

It defaults to a length of 260 characters, which seems perfect. Example: the sequence of numbers 1 to 100 is trimmed by

OEISTrim[Range[100]]

producing a list of just the first 67 numbers.

### Maple

*(From Peter Luschny)*

OEIStrim := proc(f, offset) local L, n, len, fn, s, islist; L := NULL; len := 0; islist := whattype(f) = list; n := `if`(islist, 1, offset); do fn := `if`(islist, f[n], f(n)); s := `if`(fn <= 0, 1, 0); len := len + s + length(fn); if len > 260 then break fi; len := len + 2; L := L, fn; n := n + 1; od; L end:

Usage:

OEIStrim(n -> n, 0); f := n -> -n: OEIStrim(f, 0); F := [seq(n, n = 0..100)]: OEIStrim(F, ignore);

### Pari/GP

*(from Robert Gerbicz)*

{ OEISTrim(v) = L=260; len=0; w=[]; for(i=1,length(v), len+=3+(v[i]<0); x=abs(v[i])\10; while(x,len++;x\=10); if(len>L,break); w=concat(w,v[i]); ); return(w) }

Usage:

OEISTrim(vector(100,i,i))

returns the first 67 positive integers.

**Alternate code:**

*(from MFH)*

select()changed between versions; to use in 2.4.2 change

select(function, vector)to

select(vector, function).

OEIS_trim(v,L=260)=local(L=L);select(t->-3<L-=#Str(t)+2,v) \\ (correct syntax for PARI/GP version 2.4.3 and later)

### Haskell

*(from Reinhard Zumkeller)*

import Data.List (unfoldr) oeisTrim xs = take (length $ unfoldr t (260, xs)) xs where t (_, []) = Nothing t (still, u:us) | len > still = Nothing | otherwise = Just (len, (still - len, us)) where len = length (show u) + 2

Usage:

oeisTrim [] == [] oeisTrim [1..] == [1..67] oeisTrim [1..10] == [1..10] oeisTrim [1..100] == [1..67] oeisTrim [10..1000] == [10..74]

### Sage

*(from Peter Luschny)*

def OEIStrim(L) : n = 0 leng = 0 T = [] for l in L : s = 1 if l < 0 else 0 leng = leng + s + len(str(l)) if leng > 260 : break leng += 2 T.append(l) n += 1 print n, "terms" return T

For example:

OEIStrim(range(100))

### GAP

*(from Eric M. Schmidt)*

OEISTrim := function(seq) local i, len; i := 0; len := -2; while len <= 260 do i := i + 1; if i > Length(seq) then break; fi; len := len + Length(String(seq[i])) + 2; od; return seq{[1..i-1]}; end;

Example:

OEISTrim([1..100]);

## Formatting a b-file

An important point is the format of line ends, which should be Unix (single `LF`).

### Julia

*(from Peter Luschny)*

using Dates function write_oeis_bfile(anum, range, seq, comments, targetdir) if !occursin(r"^A[0-9]{6}$", anum) @warn("Not a valid A-number! Exiting.") return end filename = joinpath(targetdir, "b" * anum[2:end] * ".txt") @info("Writing " * anum * " to " * filename) file = open(filename, "w") timestamp = Dates.format(now(), "yyyy-mm-dd HH:MM") println(file, "# ", timestamp) for c in comments println(file, "# ", c) end for n in range val = seq(n) if length(string(val)) > 1000 @error("Term too long, exiting.") break end println(file, n, " ", val) end print("\n") close(file) end

Example use:

path = "C:/Users/Home/" comments = ["Author: Julia Verona", "The divergent series par excellence."] a(n) = factorial(BigInt(n)) R = 11:200 write_oeis_bfile("A000142", R, a, comments, path)

Example use:

write_oeis_bfile("A000290", 0:100, n -> n * n, "", path)

### Maple

*(from Robert Israel)*

This will output a time-stamped b-file given an A-number, either a procedure or a list, an offset, and a final index value. In the case of a procedure, the file will be truncated before producing a number of more than 999 digits.

Makebfile := proc(anumber, A, offset, N) local bfile, n, v, dn; bfile := StringTools:-SubstituteAll(sprintf("b%6d.txt",anumber)," ","0"); fopen(bfile, WRITE); fprintf(bfile,StringTools:-FormatTime("# Produced using Maple, %B %d %Y\n")); if type(A,procedure) then for n from offset to N do v := A(n); if length(v) > 999 then break end if; fprintf(bfile,"%d %d\n",n,v); end do else for n from offset to N do fprintf(bfile,"%d %d\n",n,A[n+1-offset]) end do end if; fclose(bfile) end proc:

Example usage:

Makebfile(217, n -> n*(n+1)/2, 0, 10000);

### Mathematica

*(from Charles Greathouse)*

This is a basic implementation that needs polishing, but it will output a b-file given an A-number, a List, and an optional offset.

bFile[aNum_Integer, v_List, offset_Integer: 1] := Module[{s = OpenWrite[ "b" <> StringTake["00000", 6 - IntegerLength[aNum]] <> ToString[aNum] <> ".txt"]}, For[i = 1, i <= Length[v], i++, WriteString[s, i + offset - 1, " ", v[[i]], "\n"]]; Close[s]] bFile::usage = "bFile[aNum, v] writes a b-file with terms given in the List v, \ using offset 1.\nbFile[aNum, v, offset] writes a b-file with the \ specified offset.";

### PARI/GP

*(from Charles Greathouse)*

This GP script takes a name (as a string or as a number, e.g. "b000000.txt" or 0) and a vector, plus an optional offset. It outputs a b-file along with boilerplate text for inclusion into the OEIS. The created b-file follows the strict format, including the recommendation that numbers not exceed 1000 digits.

bfile(name, v, offset=1, limit=1000)={ my(cur=offset-1); name = Str(name); while(#name < 6, name = Str(0,name)); name = Str("b"name".txt"); for(i=1,#v, if (#Str(v[i]) > limit, print("Next term has "#Str(v[i])" digits; exiting."); break ); write(name, cur++" "v[i]); ) }; addhelp(bfile, "bfile(name, v, offset=1): Creates a b-file with the values of v for A-number name (given as a number or a filename).");

### Python

*(from Peter Luschny)*

import re from datetime import date def write_oeis_bfile(anum, range, seq, comments, targetdir): if not re.match("^A[0-9]{6}$", anum): print("Not a valid A-number! Exiting.") return filename = targetdir + "b" + anum[1:] + ".txt" print("Writing " + anum + " to " + filename) file = open(filename, "w+") file.write("# OEIS: " + anum + "\n") today = date.today() timestamp = today.isoformat() file.write("# " + timestamp + "\n") for c in comments: file.write("# " + c + "\n") for n in range: val = seq(n) if len(str(val)) > 1000: print("Term too long, exiting.") break file.write(str(n) + " " + str(val) + "\n") file.write("\n") file.close()

Usage:

comments = ["Author: Pythia Delphi", "Software: SageMath 9.2", "The divergent series par excellence." ] def a(n): return factorial(n) path = "C:/Users/Home/" write_oeis_bfile("A000142", range(11), a, comments, path)

## Reading b-files

### PARI/GP

Unfortunately, PARI has very limited power for handling files and even strings. The following may be used to get a vector of values from a b-file, using#Axxx=b2v(readstr("/tmp/bxxx.txt"));in particular it supports empty and comment lines (starting with "#") in the b-file. The argument

*is a vector of strings as it results from*

**v**readstr("bxxx.txt").

b2v(v)=apply(s->for(i=2,#s=Vecsmall(s),s[i-1]>=48&&s[i]<48&&return(eval(Strchr(s[i+1..#s])))),select(s->#s>2&&Vecsmall(s)[1]!=35,v)) \\ (c) 2014 by [[User:M. F. Hasler|M. F. Hasler]].

## Guess generating function

*See also User:Charles_R_Greathouse_IV/Pari#Recurrences for snippets to detect linear recurrences.*

### PARI/GP

*(From M. F. Hasler. IIRC, this was originally inspired by code from Max Alekseyev, but as of today I'm unable to trace back, e.g. via his page of GP scripts.)*

This PARI/GP script takes a vector of at least 8 elements and looks for a (rational) generating function. In case of failure, it returns various error messages. It also does some additional checks: In particular, after computation of the g.f., it checks whether this indeed reproduces all terms of the vector.

ggf(v)={ my( p, q, B=#v\2 ); if( B<4, "Need at least 8 values!", if( !#q=qflll(matrix(B,B,x,y,v[x-y+B+1]),4)[1], "QFLLL returned empty result.", polcoeff(p=Ser(q[,1]),0)<0 && p=-p; /* adjust sign */ q=Pol(Ser(v)*p); if( Ser(v)==q/=Pol(p), q, Str("I guessed ",q,", but it doesn't reproduce the last value!") )))}

A drawback of this code is PARI's representation of numerator and denominator as polynomials printed in order of decreasing powers. They can be reformatted using the following snippets:

p( P )=concat( vecextract( Vec(Str( P+O(x^99) )), "..-11")) /* write polynomial with increasing powers */ pgf( f )=Str/*or: print*/("(",p(numerator(f)),")/(",p(denominator(f)),")") /* prettyprint rational g.f. */

## Formatting a linear recurrence signature

### AutoHotKey

*(from Harvey P. Dale)*

This script runs in the background, and when you type "indexp " it replaces those characters with a link to the recurrence index page. You can either install AutoHotKey and run this script or use the executable.