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)
Allows to specify the desired length as optional 2nd argument. (Notes: (1) The order of the arguments in select()
has changed in PARI/GP version 2.4.2; for older versions, change select(vector, function)
to select(function, vector)
. (2) The local
declaration makes the modifications of L
in the function persistent.)
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,F); name = Str(name); while(#name < 6, name = Str(0,name)); name = Str("b"name".txt"); F=fileopen(name, "w"); for(i=1,#v, if (#Str(v[i]) > limit, print("Next term has "#Str(v[i])" digits; exiting."); break ); my(s=Str(cur++, " ", v[i])); filewrite(F, s); ); fileclose(F); } 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 v is a vector of strings as it results from
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]].
Various tools
- Automate the OEIS, CodeGolf StackExchange, 2016. A collection of methods for retrieving terms of OEIS sequences with various tools and/or programming languages.
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.