This site is supported by donations to The OEIS Foundation.

# Sequence Tools

Jump to: navigation, search

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

## 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]

```

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 a 2nd optional argument. The order of the arguments in
`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 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)!=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), "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.