
# Author: Harm Derksen               hderksen@sci.kun.nl
lprint(`for help type: ?guesss`);
lprint(`guesss stands for GUESS Sequence`);

`guesss/cfraction`:=proc(list,acc,x)
local n,i,j,a,guess,val,lco,newguess,newval,newlco,result,newresult;
n:=nops(list);
a:=linalg[matrix](n,acc+n,0);
for i from 1 to n do
	for j from 1 to acc do
		a[i,j]:=coeff(list[i],x,j-1);
	od;
	a[i,acc+i]:=1;
od;
a:=linalg[submatrix](linalg[gausselim](a),1..n,(acc+1)..(acc+n));
for i from 1 to n do guess[i]:=linalg[row](a,i); od;
result:=linalg[multiply](a,list);
for i from 1 to n do
	val[i]:=ldegree(result[i],x);
	lco[i]:=tcoeff(result[i],x);
od;
while true do
	newguess:=map(expand,linalg[scalarmul](guess[1],x^(val[2]-val[1])));
	newresult:=expand(x^(val[2]-val[1])*result[1]);newval:=val[2];
	newlco:=lco[1];val[n+1]:=val[n]+1;
for i from 2 to n do
	while (newval<val[i+1]) do
		newresult:=rem(expand(newresult-newlco/lco[i]*result[i]*
			x^(newval-val[i])),x^acc,x);
		newguess:=linalg[add](newguess,guess[i],1,-newlco/lco[i]*x^(newval-val[i]));
		if newresult=0 then RETURN(op(newguess)) fi;
		newval:=ldegree(newresult);
		newlco:=tcoeff(newresult);
	od;
od;
for i from 1 to n-1 do
	result[i]:=result[i+1];
	guess[i]:=eval(guess[i+1]);
	val[i]:=val[i+1];
	lco[i]:=lco[i+1];
od;
result[n]:=newresult;
guess[n]:=eval(newguess);
val[n]:=newval;
lco[n]:=newlco;
od;
end:

`guesss/monomials`:=proc(list,d,acc,x)
local i,monsmall,mon,jj;
if list=[] then RETURN([1]) fi;
mon:=[];
for i from 0 to d do
	monsmall:=`guesss/monomials`([list[2..nops(list)]],d-i,acc,x);
	mon:=[op(mon),seq(rem(expand(list[1]^i*monsmall[jj]),x^acc,x),jj=1..nops(monsmall))];
od;
mon;
end:

`guesss/searchbinomial`:=proc(n)
local i,j,c;
c:=0; while(n>=binomial(2*c,c)) do c:=c+1 od;c:=c-1;
for j from c by -1 to 1 do
	i:=1;while (n>binomial(j+i,j)) do i:=i+1 od;
	if n=binomial(j+i,j) then RETURN([i,j]) fi;
od;
end:

`guesss/makelist`:=proc(f,n,d,acc,x)
local g,list,i;
g:=f;list:=[f];
for i from 1 to n-1 do
	g:=diff(g,x);list:=[op(list),expand(x^i*g)]
od;
`guesss/monomials`(list,d,acc,x);
end:

# GUESS Sequence
guesss:=proc()
local sequ,j,jj,n,f,g,polyrel,guess,level,list,result,eqns,solutions,var,pq,numextension,x;
sequ:=args[1];
if nargs>1 then
	numextension:=args[2]
else
	numextension:=6;
fi;
n:=nops(sequ);
for level from 2 to trunc(n/2) do
userinfo(1,guesss,`level `,level-1);
pq:=`guesss/searchbinomial`(level);
f:=sum(sequ[j]*x^(j-1),j=1..(n-1));
list:=`guesss/makelist`(f,pq[1],pq[2],n-1,x);
polyrel:=`guesss/cfraction`(list,n-1,x);
g:=f+sum(guess[j]*x^(n-2+j),j=1..numextension);
list:=`guesss/makelist`(g,pq[1],pq[2],n+numextension-1,x);
result:=expand(sum(list[j]*polyrel[j],j=1..level));
eqns:={seq(coeff(result,x,jj),jj=(n-1)..(n+numextension-2))};
var:={seq(guess[jj],jj=1..numextension)};
solutions:=solve(eqns,var);
solutions:=subs(solutions,[seq(guess[jj],jj=1..numextension)]);
if solutions[1]=sequ[n] then RETURN(solutions) fi;
od;
lprint(`Sorry, this one is too hard. You could try giving a longer sequence.`);
[];
end:



`help/text/guesss`:=TEXT(
``,
`FUNCTION:  guesss - guess a sequence of numbers.`,
``,
`CALLING SEQUENCE: guesss(l,n)`,
``,
`PARAMETERS:`,
` l  - a list of numbers`,
` n  - (optional) the number of numbers guesss guesses`,
``,
`SYNOPSIS:`,
`- This procedure guesss tries to guess the next numbers in a sequence`,
`  of numbers. For difficult sequences guesss will need a longer input list.`,
`  If the input list is long then guesss will use higher search levels.`,
``,
`EXAMPLES:`,
``,
`v:=[seq(op([i^2,2^i]),i=1..10)];`,
`guesss(v);`,
`guesss(v,20);`,
``,
`v:=[seq(combinat[stirling1](i,3),i=1..25)];`,
`guesss(v);`,
``,
`v:=[seq(numtheory[bernoulli](i)/i!,i=1..14)];`,
`guesss(v,10);`,
`# It can handle this sequence, but can't handle the sequence of the`,
`# Bernoulli numbers itself.`,
``
):

#save `guesss.m`;
#quit
