

######################################################################
##BruteTwoFone:  Save this file as BruteTwoFone  To use it, stay in  #
##the same directory, get into Maple (by typing: maple <Enter> )     #
##and then type:  read BruteTwoFone : <Enter>                        #
##Then follow the instructions given there                           #
##                                                                   #
##Written by Moa Apagodu (Virginia Commonwealth University)          #
## and Doron Zeilberger (Rutgers University)                         #
#zeilberg at math dot rutgers dot edu                                #
######################################################################
 
#Created: Feb., 2008
 
print(`Created: Feb. 2008`):
print(` This is BruteTwoFone `):
print(`to conejcutre, by brute force, strange 2F1 hypergemoetric`):
print(`identities. It accompanies the paper `):
print(`"Searching for Strange Hypergeometric Identities By Sheer `):
print(` Brute Force " `):
print(`by Moa Apagodu and Doron Zeilberger`):
print(``):
print(`Please report bugs to zeilberg at math dot rutgers dot edu`):
print(``):
 print(`The most current version of this  package and paper`):
 print(` are  available from`):
 print(`http://www.math.rutgers.edu/~zeilberg/  .`):
 print(`For a list of the procedures type ezra();, for help with`):
 print(`a specific procedure, type ezra(procedure_name);   .`):
 print(``):

with(combinat):

ezra1:=proc()

if args=NULL then
 print(` The supporting procedures are: AlmostKummerOpeEven`):
 print(` AlmostKummerPolEven, ApaZpol, ApaZpolD `):
 print( `Buddies21, Buddies21a, Buddies21C, Buddies21Cs,  Canon21, `):
  print(` EvH, EvHpol1, EvR, EvRpol1, Find2F1, `):
 print(` FindTips, Iceberg, IsApaZ, `):
 print(` IsApaZbuddy, IsKummerian, IsAlmostKummerian, `):
 print(` IsAlmostKummerianBuddy ` ):
 print(` IsKummerianBuddy, Iceberg, Kulam, NakhDpol1, Sefer21Iceberg,`):
 print(` Target2F1pol1, Theorem, Panekh, QuadBuddies21, `):
 print(` QuadBuddies21S, Reci, , TestAlmostKummerC, WeedOut, WeedOutC `):
else
ezra(args):
fi:

end:



ezra:=proc()

if args=NULL then
 print(`The main procedures are: AlmostKummerPf, AlmostKummerPolD `):
 print(` AlmostKummerPolEvenB, ApaZclosedForm, ApaZope,  ApaZpolB  `):
 print(` Find2F1x,  NakhD, NakhDEqs, NakhDx ,`):
print(` PreComputed21 `):
 print(` Sefer21,  Sefer21Gamma, Target2F1 `):



elif nops([args])=1 and op(1,[args])=AlmostKummerOpeEven then
print(`AlmostKummerOpeEven(n,b,r,N): The Almost-Kummer Operator in n, b`):
print(`that stands in front of 2F1([-2*n,b],[2*r-2*n-b],-1);`):
print(`Here n and b are symbols, with symbolic (or numeric) r`):
print(`For example, try:`):
print(`AlmostKummerOpeEven(n,b,r,N);`):



elif nops([args])=1 and op(1,[args])=AlmostKummerPf then
print(`AlmostKummerPf(n,b,r,N): The Almost-Kummer Proof in n, b`):
print(`that stands in front of 2F1([-2*n,b],[r-2*n-b],-1);`):
print(`Here n and b are symbols, while r is a pos. integer`);
print(`For example, try:`):
print(`AlmostKummerPf(n,b,2,N);`):

elif nops([args])=1 and op(1,[args])=AlmostKummerPolD then
print(`AlmostKummerPolD(n,b,r): The Almost-Kummer Polynomial in n, b`):
print(`that stands in front of 2F1([-2*n,b],[r-2*n-b],-1);`):
print(`Here n and b are symbols, while r is a pos. integer`):
print(`For example, try:`):
print(`AlmostKummerPolD(n,b,2);`):

elif nops([args])=1 and op(1,[args])=AlmostKummerPolEven then
print(`AlmostKummerPolEven(n,b,r): The Almost-Kummer Polynomial in n, b`):
print(`that stands in front of 2F1([-2*n,b],[2*r-2*n-b],-1);`):
print(`Here n and b are symbols, while r is a pos. integer`):
print(`This is the fast way`):
print(`For example, try:`):
print(`AlmostKummerPolEven(n,b,2);`):

elif nops([args])=1 and op(1,[args])=AlmostKummerPolEvenB then
print(`AlmostKummerPolEvenB(n,b,r,B): The Almost-Kummer Polynomial in n, b`):
print(`that stands in front of 2F1([-2*n,b],[2*r-2*n-b],-1);`):
print(`Here n and b are symbols, while r is a pos. integer`):
print(`This is the fast way. The solution are expressed in terms`):
print(`of B(n,i)'s where B(n,i) stands for binomial(n,i) `):
print(`For example, try:`):
print(`AlmostKummerPolEvenB(n,b,2,B);`):



elif nops([args])=1 and op(1,[args])=ApaZclosedForm then
print(`ApaZclosedForm(n,i,j,R): the closed-form expression for F(-2n,-1/2+i,-3n-1/2+j,-3)`):
print(`where i and j are integers, and R is a letter for the rising factorial`):
print(`function R(a,k)=a(a+1)...(a+k-1). `):
print(`For example, try:`):
print(`ApaZclosedForm(n,2,3,R);`):

elif nops([args])=1 and op(1,[args])=ApaZpol then
print(`ApaZpol(n,i,j): The Apagodu-Zeilberger Polynomial in n`):
print(`using the operator.`):
print(`Here n is a symbol, while i j are a pos. integer`):
print(`For example, try:`):
print(`ApaZpol(n,1,1);`):

elif nops([args])=1 and op(1,[args])=ApaZpolB then
print(`ApaZpolB(n,i,j,B): The Apagodu-Zeilberger Polynomial in n`):
print(`using the operator.`):
print(`Here n is a symbol, while i j are a pos. integer`):
print(`In terms of B(n,i):=binomial(n,i) .`):
print(`For example, try:`):
print(`ApaZpolB(n,1,1,B);`):

elif nops([args])=1 and op(1,[args])=ApaZpolD then
print(`ApaZpolD(n,i,j): The Apagodu-Zeilbeberger polynomial in n`):
print(`(computed directly)`):
print(`that stands in front of 2F1([-2*n,-1/2+3*i],[-3*n-1/2+3*j],-3);`):
print(`Here n is a symbol, while i and j area non-negative integers`):
print(`For example, try:`):
print(`ApaZpolD(n,2,3);`):

elif nops([args])=1 and op(1,[args])=ApaZope then
print(`ApaZope(n,i,j,N): The Apagodu-Zeilbeger Operator in n,`):
print(`that stands in front of 2F1([-2*n,-1/2+3*i],[-3*n-1/2+3*j],-3);`):
print(`Here n is a symbol, with symbolic (or numeric) i,j`):
print(`if i and j are symbolic, it only returns the operator. If they are both numeric`):
print(`then it also returns the two first values.`):
print(`For example, try:`):
print(`ApaZope(n,3,2,N);`):
print(` and: `):
print(`ApaZope(n,i,j,N);`):

elif nops([args])=1 and op(1,[args])=Buddies21 then
print(`Buddies21(H): all the distance <=k buddies of the 2F1 series`):
print(`H, For example try: Buddies21([[a,b],[c],x],3);`):

elif nops([args])=1 and op(1,[args])=Buddies21a then
print(`Buddies21a(H): all the immediate buddies of the 2F1 series`):
print(`H, For example try: Buddies21a([[a,b],[c],x]);`):

elif nops([args])=1 and op(1,[args])=Buddies21C then
print(`Buddies21C(H,n): all the buddies of H in canonical form`):
print(`For example, try:`):
print(`Buddies21C([[-3*n,n+1],[-2*n+1/2],1/2],n);`):

elif nops([args])=1 and op(1,[args])=Buddies21Cs then
print(`Buddies21Cs(SetOf2F1s,n): all the buddies of the`):
print(`members of SetOf2F1s in canonical form`):
print(`For example, try:`):
print(`Buddies21Cs({[[-3*n,n+1],[-2*n+1/2],1/2]},n);`):

elif nops([args])=1 and op(1,[args])=Canon21 then
print(`Canon21(H,n): Given a hypergeometric series H=[H1,H2,x]`):
print(`phrased in terms of n, finds the canonical form, `):
print(`for example, try: Canon21([[-2*n-1,4*n],[3*n+1/3],1/4],n);`):


elif nops([args])=1 and op(1,[args])=EvH then
print(`EvH(N1,D1,x,n,n0):Evaluates a hypegeometric terminating`):
print(`series whose first item of numerator is -a*n`):
print(`a integer, featuring the distrete variable n, with`):
print(`argument x. For example, try: EvH([-n,a],[b],1,n,4);`):

elif nops([args])=1 and op(1,[args])=EvHpol1 then
print(`EvHpol1(N1,D1,pol,x,k,n,n0):Evaluates a hypegeometric terminating`):
print(`series, with a polynomial pol(n,k) multiplied in the summand`):
print(` whose first item of numerator is -a*n`):
print(`a integer, featuring the distrete variables n and k, with`):
print(`argument x. For example, try: EvHpol1([-n,a],[b],n+2*k,1,k,n,4);`):


elif nops([args])=1 and op(1,[args])=EvR then
print(`EvR(N1,D1,x,n,n0): `):
print(`the sequence of ratios of 2F1(N1,D1,x) up to n0`):
print(`For example, do:`):
print(`EvR([-2*n,n+1/2],[1/3],2,n,10);`):

elif nops([args])=1 and op(1,[args])=EvRpol1 then
print(`EvRpol1(N1,D1,pol,x,k,n,n0): `):
print(`the sequence of ratios of 2F1(N1,D1,x,pol1) up to n0`):
print(`For example, do:`):
print(`EvRpol1([-2*n,n+1/2],[1/3],n+2*k,2,k,n,10);`):

elif nops([args])=1 and op(1,[args])=Find2F1 then
print(`Find2F1(N,M,den,x,n,deg): all the strange 2F1(-a*n,b*n+b1,c*n+c1;x)`):
print(`with a pos. int. between 1 and N, b and c integers`):
print(`between -N and N, and b1,c1 rational numbers with`):
print(`denominator=den. For example, try:`):
print(`Find2F1(2,1,1,4,n,2);`):

elif nops([args])=1 and op(1,[args])=Find2F1x then
print(`Find2F1x(N,M,den,n,deg): all the strange 2F1(-a*n,b*n+b1,c*n+c1;x)`):
print(`with a pos. int. between 1 and N, b and c integers`):
print(`between -N and N, and b1,c1 rational numbers with`):
print(`denominator=den, and x whatever. For example, try:`):
print(`Find2F1x(2,1,1,n,2);`):


elif nops([args])=1 and op(1,[args])=FindTips then
print(`FindTips(H,n,Deg): Given a set of Hypergeometric nice`):
print(`evaluations, H,  (phrased in terms of n),`):
print(`finds those that are tips of icebergs`):
print(`(up to degree Deg)`):
print(`For example, try:`):
print(`FindTips(PreComputed21(),n,4);`):

elif nops([args])=1 and op(1,[args])=Iceberg then
print(`Iceberg(H,n,d): Does H=[N1,D1,x] seem to be part of`):
print(`an infinite family with D1 replaced by adding integers`):
print(`where H is given by a closed form of degree d .`):
print(`For example, try:`):
print(`Iceberg([[-2*n,b],[1-2*n-b],-1],n,2);`):

elif nops([args])=1 and op(1,[args])=IsApaZ then
print(`IsApaZ(H,n): Is the 2F1 hypergeometric evaluation`):
print(`H of the form Apagodu-Zeilberger nice 2F1 evaluation`):
print(`2F1([[-2*n,-1/2+integer],[-3*n-1/2+integer],-3] `):

elif nops([args])=1 and op(1,[args])=IsApaZbuddy then
print(`IsApaZbuddy(H,n): Is the 2F1 hypergeometric evaluation`):
print(`H a buddy of the Apagodu-Zeilberger nice 2F1 evaluation`):
print(`2F1([[-2*n,-1/2+integer],[-3*n-1/2+integer],-3] `):

elif nops([args])=1 and op(1,[args])=IsKummerian then
print(`IsKummerian(H): is H Kummerian? For example, try: `):
print(`IsKummerian([[a,b],[1+a-b],-1]):`):

elif nops([args])=1 and op(1,[args])=IsAlmostKummerian then
print(`IsAlmostKummerian(H): is H Almost Kummerian? For example, try: `):
print(`IsAlmostKummerian([[a,b],[-5+a-b],-1]);`):

elif nops([args])=1 and op(1,[args])=IsKummerianBuddy then
print(`IsKummerianBuddy(H,n): is H Kummerian or one of its buddies?`):
print(` For example, try: `):
print(`IsKummerianBuddy([[-2*n,b],[2*b],2],n); `):

elif nops([args])=1 and op(1,[args])=IsAlmostKummerianBuddy then
print(`IsAlmostKummerianBuddy(H,n): is H Almost Kummerian,`):
print(` or one of its buddies?`):
print(` For example, try: `):
print(`IsAlmostKummerianBuddy([[-2*n,b],[2*b],2],n):`):

elif nops([args])=1 and op(1,[args])=Kulam then
print(`Kulam(N,M,den,n,Maxdeg): All the strange evaluations`):
print(`of the form 2F1(-a*n,b*n+b1,c*n+c1;x) where`):
print(`1<=a, |b|,|c| <=N, |b1|,|c1|<=M, the denominator of`):
print(`b1, c1 is <=den, and the evaluation is of degree<=Maxdeg`):
print(`For example, try:`):
print(`Kulam(2,2,2,n,2);`):

elif nops([args])=1 and op(1,[args])=NakhD then
print(`NakhD([N1,D1,x],n,d): Given lists of expressions in n`):
print(`N1 and D1 containing linear-affine expressions in n`):
print(`with N1[1] of the form -a*n for some pos. integer a`):
print(`and a number x, and a non-neg. integer d`):
print(`guesses, if possible a rational function, in n,`):
print(`whose top and bottom degrees are d, for the sequence`):
print(`of ratios: 2F1(N1;D1;x)(n+1)/2F1(N1;D1;x)(n) `):
print(`For example, to guess the Pfaff-Saalschutz try:`):
print(` NakhD([[-n,a,b],[c,-n+1+a+b-c],1],n,2); `):

elif nops([args])=1 and op(1,[args])=NakhDpol1 then
print(`NakhDpol1([N1,D1,x],pol,k,n,d): Given lists of expressions in n`):
print(`N1 and D1 containing linear-affine expressions in n`):
print(`with N1[1] of the form -a*n for some pos. integer a`):
print(`and a number x, and a non-neg. integer d`):
print(`and also given a polynomial pol in the variables k,n `):
print(`guesses, if possible a rational function, in n,`):
print(`whose top and bottom degrees are d, for the sequence`):
print(`of ratios: 2F1(N1;D1;x,pol)(n+1)/2F1(N1;D1;,pol,x)(n) `):
print(`For example, to guess the Pfaff-Saalschutz try:`):
print(` NakhDpol1([[-n,a,b],[c,-n+1+a+b-c],1],1,k,n,2); `):

elif nops([args])=1 and op(1,[args])=NakhDx then
print(`NakhDx(N1,D1,n,d): Given lists of expressions in n`):
print(`N1 and D1 containing linear-affine expressions in n`):
print(`with N1[1] of the form -a*n for some pos. integer a`):
print(`and a non-neg. integer d`):
print(`returns the (possibly empty) set of x  such that`):
print(` NakhD([N1,D1,x],n,d) does not fail. It takes away x=1 `):
print(`if it belogs to it, because x=1 is not strange`):
print(`For example, try:`):
print(` NakhDx([-2*n,2*n+1],[-n+3/4],n,2); `):

elif nops([args])=1 and op(1,[args])=NakhDEqs then
print(`NakhDEqs(N1,D1,x,n,d,Vars): Given a F(N1,D1,x), in terms`):
print(`of parameters in Vars, finds a set of algebraic equations`):
print(`that these parameters must satisfy, in order to`):
print(`have a closed form evaluation of degree d`):
print(`For example, try:`):
print(`NakhDEqs([-n,-n+1/2],[4*n+3/2],1/5,n,4,{}):`):


elif nops([args])=1 and op(1,[args])=Panekh then
print(`Panekh(f,n,R): solves the equation x(n+1)/x(n)=f(n) in terms`):
print(`of n and the raising factorial R(a,n)`):
print(`For example, try: Panekh((n+1/2)/(n+1/3),n,R);`):

elif nops([args])=1 and op(1,[args])=PreComputed21 then
print(`PreComputed21(): a set of pre-computed good`):
print(`2F1 strange evaluations, neither Almost Kumerian`):
print(`nor of Apagodu-Zeilberger type`):


elif nops([args])=1 and op(1,[args])=Theorem then
print(`Theorem(H,n,R,Deg): Given a good hypergeometric 2F1, phrased`):
print(`in terms of H, (with exact evaluation of degree Deg)`):
print(`states the exact evaluation using R(a,n)`):
print(`to denote the rising factorial (a)_n:=a(a+1)*...*(a+n-1);`):
print(`For example try: `):
print(`Theorem([[-n,a],[b],1],n,R,4);`):

elif nops([args])=1 and op(1,[args])=QuadBuddies21 then
print(`QuadBuddies21(HG): The quadratic buddies of the 2F1 HG`):
print(`For example, try:`):
print(`QuadBuddies21([[a,b],[2*a],x]);`):

elif nops([args])=1 and op(1,[args])=QuadBuddies21S then
print(`QuadBuddies21S(SetOf2F1s,n): The quadratic buddies of the 2F1 HG`):
print(`For example, try:`):
print(`QuadBuddies21S({[[a,b],[2*a],x]},n);`):

elif nops([args])=1 and op(1,[args])=Reci then
print(`Reci(Tri,n): Given a triple [A,B,x], phrased in terms of n`):
print(` where A is a list`):
print(`of length two, B a list of length 1, and C a number`):
print(`representing a 2F1(A,B;x), outputs the triple that`):
print(`corresponds to the reciprocal series`):
print(`For example, try:`):
print(`Reci([[-n,2*n],[-2*n],2],n);`):

elif nops([args])=1 and op(1,[args])=Sefer21 then
print(`Sefer21(H,n,Deg): Given a set of pre-computed hypergeometric`):
print(`2F1's, outputs the list of theorems.`):
print(`For example, try:`):
print(`Sefer21(PreComputed21(),n,4); `);

elif nops([args])=1 and op(1,[args])=Sefer21Gamma then
print(`Sefer21Gamma(H,n,Deg): Given a set of pre-computed hypergeometric`):
print(`2F1's, outputs the list of theorems, in terms of the Gamma function`):
print(`For example, try:`):
print(`Sefer21Gamma(PreComputed21(),n,4); `);

elif nops([args])=1 and op(1,[args])=Sefer21Iceberg then
print(`Sefer21Iceberg(H,n,Deg): Given a set of pre-computed hypergeometric`):
print(`2F1's, outputs the list of theorems, plus indicating`):
print(`whether it is the tip of an iceberg. `):
print(`For example, try:`):
print(`Sefer21Iceberg(PreComputed21(),n,4); `);

elif nops([args])=1 and op(1,[args])=Target2F1 then
print(`Target2F1(A,B,C,x,n,d,N0): Given a 0-parameter 2F1(A,B;C;x)`):
print(`tries to conjecture a one-parameter generalization`):
print(`in the form 2F1(-a*n,b*n+b1,c*n+c1;x)`):
print(`with 1<=a<=N0, -N0<=b,c<=N0 closed-form of degree d. `):
print(`For example, try:`):
print(` Target2F1(1/2,1/2,1,1/2,n,2,2);`):

elif nops([args])=1 and op(1,[args])=Target2F1pol1 then
print(`Target2F1pol1(A,B,C,x,n,d,N0,k): Given a 0-parameter 2F1(A,B;C;x)`):
print(`tries to conjecture a one-parameter generalization`):
print(`in the form 2F1(-a*n,b*n+b1,c*n+c1;x,pol1), where pol1 is`):
print(`a linear polynomial in n and k`):
print(`with 1<=a<=N0, -N0<=b,c<=N0 closed-form of degree d`):
print(`For example, try Target2F1pol1(1/2,1/2,1,1/2,n,2,2,k);`) :

elif nops([args])=1 and op(1,[args])=TestAlmostKummerC then
print(`TestAlmostKummerC(n0,b,r): tests the Almost Kummer Theorem for`):
print(`n=n0 and integer r. b is a symbol. For example, try:`):
print(`TestAlmostKummerC(4,b,3);`):

elif nops([args])=1 and op(1,[args])=WeedOut then
print(`WeedOut(S,n): Given a set of Hypergeometric 2F1's`):
print(`reduces it so that no memeber will have`):
print(`any buddies. For example, try:`):
print(`WeedOut({[ [-n,2*n+1],[-3*n],-1]},n);`):

elif nops([args])=1 and op(1,[args])=WeedOutC then
print(`WeedOutC(S,n): Given a set of Hypergeometric 2F1's`):
print(`reduces it so that no memeber will have`):
print(`any buddies. Then it kicks out all almost Kumerian`):
print(`ones. For example, try:`):
print(`WeedOutC({[ [-n,2*n+1],[-3*n],-1]},n);`):

else
print(`There is no ezra for`,args):
fi:
 
end:


####Begin precomputed set of good hypergeometics 2F1




###No longer needed, lead to the discovery of Apagodu-Zeilbegrer types
PreComputed21T:=proc():
{[[-2*n, -1/2], [-3*n-3/2], -3], [[-3*n, -n-1/2], [-3*n-1/2], -3], [[-2*n, 3/2], [-3*n-3/2], -3], [[-3*n, -n-3/2], [-3*n-1/
2], -3], [[-3*n, -n-3/2], [-3*n+1/2], -3], [[-3*n, -n-1/2], [-3*n-3/2], -3], [[-2*n, -3/2], [-3*n+1/2], -3], [[-3*n, -n-1/2
], [-3*n+1/2], -3], [[-2*n, 1/2], [-3*n-3/2], -3], [[-2*n, -3/2], [-3*n-1/2], -3], [[-3*n, -n+1/2], [-3*n-1/2], -3], [[-3*n
, -n+1/2], [-3*n+3/2], -3], [[-2*n, 5/2], [-3*n+5/2], -3], [[-2*n, 3/2], [-3*n+5/2], -3], [[-2*n, 5/2], [-3*n-1/2], -3], [[
-2*n, 5/2], [-3*n+3/2], -3], [[-2*n, 5/2], [-3*n+1/2], -3], [[-2*n, -1/2], [-3*n+5/2], -3], [[-2*n, 1/2], [-3*n+5/2], -3]}
:
end:

###No longer needed, lead to the discovery of Apagodu-Zeilbegrer types


PreComputed21:=proc():
{[[-n, n+1], [-2*n], 1/2-1/2*I*3^(1/2)], [[-n, -n+1/4], [2*n+5/4], 1/9], [[-n, -n-1/4], [2*n+7/4], 1/9], [[-2*n, n+1/2], [2
*n+3/2], 2], [[-2*n, 1/2], [4*n+3/2], 1/4], [[-2*n, 2*n+1], [3*n+2], 1/2-1/2*5^(1/2)], [[-n, -n+1/3], [n+4/3], -1/8], [[-n,
-n+1/2], [2*n+3/2], -1/3], [[-n, n+1/2], [3*n+3/2], 1/2], [[-n, -n+1/2], [2*n+3/2], 1/9], [[-2*n, 2*n+1], [-3*n], 1/2-1/2*5
^(1/2)], [[-3*n, -n+3/2], [-3*n+1/2], -3], [[-2*n, n+1], [-4*n], 1/2*5^(1/2)-1/2], [[-2*n, n+1], [3*n+2], 1/2*5^(1/2)+3/2],
[[-n, -n+1/2], [4*n+3/2], 1/5], [[-2*n, n+1/2], [3*n+3/2], 3/2-1/2*5^(1/2)], [[-n, -n-1/3], [n+5/3], -1/8], [[-2*n, 2*n+1],
[4*n+2], 1/2+1/2*I*3^(1/2)], [[-n, n+1], [2*n+2], 1/2-1/2*I*3^(1/2)]}:
end:



####End precomputed set of good hypergeometics 2F1

ez:=proc(): print(` rf(a,k), EvH(N1,D1,x,n,n0)  `): 
print(` Nakh(N1,D1,x,n,n0) , GR1(S,x), `):
print(` IsKosher(N1,D1,n)`):
print(`Target2F1(A,B,C,x,n,n0,N0)`):
print(`Find2F1(N,M,d,x,n,deg) `):
print(`NakhD(N1,D1,x,n,d)`):
print(`GRdP(L,d,n,Vars)`):
print(`NakhDP(N1,D1,x,n,d,Vars) `):
print(`GRdPEqs(L,d,n,Vars,a,b)`):
print(`NakhDPeqs(N1,D1,x,n,d,Vars,a,b)`):
print(`GRdPx(L,d,n,x) `):
print(`NakhDx(N1,D1,n,d)`):
print(`NakhDEqs(N1,D1,n,d,Vars)`):
end:


with(linalg):


#####One variable rational-function geussing

with(SolveTools):
#Bdok1(DS1,P,x): checks that P in the single variable x  indeed fits the data set DS1
Bdok1:=proc(DaS,P,x) local i:

for i from 1 to nops(DaS) do
if subs(x=DaS[i][1],denom(P))<>0 and
normal(subs(x=DaS[i][1],P)-DaS[i][2])<>0 then

  RETURN(false):
fi:
od:
true:
end:

#GenRat1(x,dxt,dxb,a): a generic (monic top)
#rational function of degree of top dxt 
#and degree of bottom dxb
#with coeffs.parametrized by a[i] followed by the set
#of coeffs.
GenRat1:=proc(x,dxt,dxb,a) local i:

(add(a[i]*x^i,i=0..dxt))/
add(a[i+dxt+1]*x^i,i=0..dxb)
,{seq(a[i],i=0..dxt+dxb+1)}:
end:


#GR1d1d2(S1,x,d1,d2): guesses a rational function in x of degree d1/d2
#that fits the data in DS1
GR1d1d2:=proc(S1,x,d1,d2)
local eq,var,P,a,var1,i:
P:=GenRat1(x,d1,d2,a):
var:=P[2]:
P:=P[1]:

if nops(S1)<=d1+d2+3 then
# print(`Insufficient data`):
 RETURN(FAIL):
fi:

eq:={seq(numer(normal(subs(x=S1[i][1],P)-S1[i][2])),i=1..d1+d2+3)}:

var1:=Linear(eq,var):
if expand(subs(var1,numer(P)))=0 then
  RETURN(FAIL):
fi:
P:=subs(var1,P):
if Bdok1(S1,P,x) then 
   RETURN(factor(normal(P))):
 else
 RETURN(FAIL):
fi:

end:


#GR1(S1,x): guesses a polynomial from the data-set S1
GR1:=proc(S1,x) local d1,d2,gu,L,i1:
if {seq(S1[i1][2],i1=1..nops(S1))}={0} then
   RETURN(0):
fi:


for L from 0 to nops(S1)-4 do
 for d1 from 0 to L do
   d2:=L-d1:
 gu:=GR1d1d2(S1,x,d1,d2):
  if gu<>FAIL then
    RETURN(gu):
  fi:
 od:
od:

FAIL:
end:



####End one-variable rational function guessing

rf:=proc(a,k) local i: mul(a+i,i=0..k-1):end:

#EvH(N1,D1,x,n,n0):Evaluates a hypegeometric terminating
#series whose first item of numerator is -a*n
#a integer, featuring the distrete variable n, with
#argument x. For example, try: EvH([-n,a],[b],1,n,n0);
EvH:=proc(N1,D1,x,n,n0) local k,a,i,N10,D10:

a:=-coeff(N1[1],n,1):

if not ( type(a,integer)  and a>0 ) then
ERROR(`Bad input `):
fi:

N10:=subs(n=n0,N1):
D10:=subs(n=n0,D1):

normal(add(mul(rf(N10[i],k),i=1..nops(N10))/
mul(rf(D10[i],k),i=1..nops(D10))/k!*x^k,k=0..a*n0)):

end:






IsKosher:=proc(N1,D1,n) local i,j,a:
for i from 1 to nops(N1) do
for j from 1 to nops(D1) do
  if type(expand(N1[i]-D1[j]),integer) then
     RETURN(false):
  fi:
od:
od:

a:=abs(coeff(N1[1],n,1)):

for i from 1 to nops(N1) do
 if type(coeff(N1[i],n,0),integer) and coeff(N1[i],n,1)=0 then
    RETURN(false):
 fi:
od:
    

if member(0,{op(D1)}) then
  RETURN(false):
fi:

for j from 1 to nops(D1) do
 if coeff(D1[j],n,1)*coeff(D1[j],n,0)<0 and 
    type(coeff(D1[j],n,0),integer) then
    RETURN(false):
  fi:

 if type(D1[j],integer) and D1[j]<0 then
      RETURN(false):
 fi:
 if abs(coeff(D1[j],n,1))<a then
    RETURN(false):
 fi:
od:

true:

end:



#Target2F1(A,B,C,x,n,d,N0): Given a 0-parameter 2F1(A,B;C;x)
#tries to conjecture a one-parameter generalization
#in the form 2F1(-a*n,b*n+b1,c*n+c1;x)
#with 1<=a<=N0, -N0<=b,c<=N0 closed-form of degree d
#For example, try Target2F1(1/2,1/2,1,1/2,n,2,2);
Target2F1:=proc(A,B,C,x,n,d,N0) local a,b,c,b1,c1,N1,D1,mu:

for a from 1 to N0 do
 for b from -N0 to N0 do
  for c from -N0 to N0 do
    b1:=B+b*A/a:
    c1:=C+c*A/a:
    N1:=[-a*n,b*n+b1]: D1:=[c*n+c1]:

    if IsKosher(N1,D1,n) then  

     mu:=NakhD([N1,D1,x],n,d):
       if mu<>FAIL then
         RETURN([N1,D1,x],mu):
       fi:
    fi:
  od:
 od:
od:
FAIL:
end:





#GRd(L,d,n): guesses whether the sequence L 
#is represented by a rational function of degree d
GRd:=proc(L,d,n) local i,a,b,P,Q,eq,var:
if nops(L)<2*d+4 then
 ERROR(`L must be of length at least`, 2*d+4):
fi:
P:=add(a[i]*n^i,i=0..d):
Q:=add(b[i]*n^i,i=0..d):
var:={seq(b[i],i=0..d),seq(a[i],i=0..d)}:
eq:={seq(L[i]*subs(n=i,Q)-subs(n=i,P),i=1..2*d+4)}:

var:=solve(eq,var):

P:=subs(var,P): Q:=subs(var,Q):

if Q<>0 then
 RETURN(normal(P/Q)):
else
 RETURN(FAIL):
fi:

end:



#EvR(N1,D1,x,n,n0): the sequence of ratios of 2F1(N1,D1,x) up to n0
EvR:=proc(N1,D1,x,n,n0) local gu,i:
gu:=normal([seq(EvH(N1,D1,x,n,i),i=1..n0+1)]):

if member(0,{op(gu)}) then
 RETURN(FAIL):
fi:

[seq(gu[i+1]/gu[i],i=1..n0)]:

end:








NakhD:=proc(H,n,d) local mu,vu,N1,D1,x:
N1:=H[1]: D1:=H[2]: x:=H[3]:
if type(N1[1],numeric) then
  RETURN(FAIL):
fi:
mu:=EvR(N1,D1,x,n,2*d+4):
if mu=FAIL then
 RETURN(FAIL):
fi:
vu:=factor(GRd(mu,d,n)):
mu:=normal(EvR(N1,D1,x,n,2*d+10)):

if [seq(normal(subs(n=i,vu)-mu[i]),i=1..nops(mu) )]<>[0$nops(mu)] then
 RETURN(FAIL):
else
  RETURN(vu):
fi:

end:




#Find2F1(N,M,den,x,n,deg): all the strange 2F1(-a*n,b*n+b1,c*n+c1;x)
#with a pos. int. between 1 and N, b and c integers
#between -N and N, and b1,c1 rational numbers with
#denominator=den. For example, try:
#Find2F1(2,1,1,1/2,n,2);
Find2F1:=proc(N,M,d,x,n,deg)
local N1,D1,a,b,c,H,b1,c1,mu:

H:={}:

for a from 1 to N do
 for b from -N to N do
  for c from -N to N do
     for b1 from -M*d to M*d do
      for c1 from -M*d to M*d do
      if igcd(b1,d)=1  and igcd(c1,d)=1 then
          N1:=[-a*n,b*n+b1/d]:
          D1:=[c*n+c1/d]:


 if IsKosher(N1,D1,n) then
           mu:=NakhD([N1,D1,x],n,deg):
            if mu<>FAIL then
              H:=H union {[[N1,D1,x],mu]}:
            fi:
 fi:
fi:

      od:
  od:
od:
od:
od:

H:

end:



NakhDP:=proc(N1,D1,x,n,d,Vars) local mu:
mu:=EvR(N1,D1,x,n,2*d+4+nops(Vars)+2):
if mu=FAIL then
 RETURN(FAIL):
fi:
GRdP(mu,d,n,Vars):
end:

#GRdP(L,d,n,Vars): guesses whether the sequence L 
#of rational functions in the set of variables Vars
#is represented by a rational function of degree d
#for some assignments of the variables in Vars
GRdP:=proc(L,d,n,Vars) local i,a,b,P,Q,eq,var,lu,
gu,P1,Q1,v,lu1:
if nops(L)<2*d+4+nops(Vars)+2 then
 ERROR(`L must be of length at least`, 2*d+4+nops(Vars)+2):
fi:
P:=add(a[i]*n^i,i=0..d):
Q:=add(b[i]*n^i,i=0..d):
var:={seq(b[i],i=0..d),seq(a[i],i=0..d)}:
eq:={seq(L[i]*subs(n=i,Q)-subs(n=i,P),i=1..2*d+4+nops(Vars)+2)}:
eq:={seq(numer(i),i in eq)}:

lu:=[solve(eq,var union Vars)]:

gu:=[]:
for i from 1 to nops(lu) do
 lu1:=lu[i]:
 Q1:=subs(lu1,Q):
 P1:=subs(lu1,P):

   if Q1<>0 then
    gu:=[op(gu),[factor(P1/Q1),{seq(v=subs(lu1,v),v in Vars)}]]:
   fi:
od:
gu:


end:




#GRdPEqsOld(L,d,n,Vars,a,b): Outputs the set of equations
#in Vars and the coeffs. variables, that will
#make the sequence L, expressed in terms of the
#variables of Vars and the coeffs. of the generic
#rational function, realizable in terms of that
#rational function
GRdPEqsOld:=proc(L,d,n,Vars,a,b) local i,P,Q,eq,var:

if nops(L)<2*d+4+nops(Vars)+2 then
 ERROR(`L must be of length at least`, 2*d+4+nops(Vars)+2):
fi:
P:=add(a[i]*n^i,i=0..d):
Q:=add(b[i]*n^i,i=0..d):
var:={seq(b[i],i=0..d),seq(a[i],i=0..d)}:
eq:={seq(L[i]*subs(n=i,Q)-subs(n=i,P),i=1..2*d+4+nops(Vars)+2)}:
eq:={seq(numer(i),i in eq)}:

eq,Vars,var:

end:



NakhDPeqs:=proc(N1,D1,x,n,d,Vars,a,b) local mu:
mu:=EvR(N1,D1,x,n,2*d+4+nops(Vars)+2):
if mu=FAIL then
 RETURN(FAIL):
fi:
GRdPEqs(mu,d,n,Vars,a,b):
end:




#GRdPx(L,d,n,x): guesses whether the sequence L 
#of rational functions in x
#is represented by a rational function of degree d
#for some assignments of the variables in Vars
GRdPx:=proc(L,d,n,x) local i1,a,b,P,Q,eq,M,i,j,M1,mu,mu1,lu,lu1:
if nops(L)<2*d+4 then
 ERROR(`L must be of length at least`, 2*d+4):
fi:
P:=add(a[i1]*n^i1,i1=0..d):
Q:=add(b[i1]*n^i1,i1=0..d):
eq:={seq(L[i1]*subs(n=i1,Q)-subs(n=i1,P),i1=1..2*d+4)}:
eq:={seq(numer(i1),i1 in eq)}:

M:=matrix(2*d+2,2*d+2):

for i from 1 to 2*d+2 do

for j from 0 to d do
M[i,j+1]:=coeff(eq[i],a[j],1):
od:
for j from 0 to d do
M[i,d+2+j]:=coeff(eq[i],b[j],1):
od:

od:

M1:=matrix(2*d+2,2*d+2):
for i from 1 to 2*d+1 do
for j from 1 to 2*d+2 do
 M1[i,j]:=M[i,j]:
od:
od:

for j from 0 to d do
M1[2*d+2,j+1]:=coeff(eq[2*d+3],a[j],1):
od:
for j from 0 to d do
M1[2*d+2,d+2+j]:=coeff(eq[2*d+3],b[j],1):
od:


mu:=gcd(det(M),det(M1)):


M1:=matrix(2*d+2,2*d+2):
for i from 1 to 2*d+1 do
for j from 1 to 2*d+2 do
 M1[i,j]:=M[i,j]:
od:
od:

for j from 0 to d do
M1[2*d+2,j+1]:=coeff(eq[2*d+4],a[j],1):
od:
for j from 0 to d do
M1[i,d+2+j]:=coeff(eq[2*d+4],b[j],1):
od:


mu1:=gcd(det(M),det(M1)):

lu:={solve(mu,x)} minus {0,1}:

lu1:={solve(mu1,x)} minus {0,1}:

lu intersect lu1:


end:



NakhDx:=proc(N1,D1,n,d) local mu,x:
mu:=EvR(N1,D1,x,n,2*d+4):
if mu=FAIL then
 RETURN(FAIL):
fi:
GRdPx(mu,d,n,x):
end:






#GRdPEqs(L,d,n,Vars): guesses whether the sequence L 
#of rational functions in n
#is represented by a rational function of degree d
#for some assignments of the variables in Vars
GRdPEqs:=proc(L,d,n,Vars) local i1,a,b,P,Q,eq,M,i,j,dets1,r:


if nops(L)<2*d+4+nops(Vars) then
 ERROR(`L must be of length at least`, 2*d+4+nops(Vars)):
fi:
P:=add(a[i1]*n^i1,i1=0..d):
Q:=add(b[i1]*n^i1,i1=0..d):
eq:={seq(L[i1]*subs(n=i1,Q)-subs(n=i1,P),i1=1..2*d+4+nops(Vars))}:
eq:={seq(numer(i1),i1 in eq)}:

dets1:={}:


for r from 0 to nops(Vars)+1 do

M:=matrix(2*d+2,2*d+2):

for i from 1 to 2*d+1 do

for j from 0 to d do
M[i,j+1]:=coeff(eq[i],a[j],1):
od:
for j from 0 to d do
M[i,d+2+j]:=coeff(eq[i],b[j],1):
od:

od:


for j from 0 to d do
M[2*d+2,j+1]:=coeff(eq[2*d+2+r],a[j],1):
od:
for j from 0 to d do
M[2*d+2,d+2+j]:=coeff(eq[2*d+2+r],b[j],1):
od:


dets1:=dets1 union {det(M)}:

od:

dets1:

end:



#NakhDEqs(N1,D1,x,n,d,Vars): Given a F(N1,D1,x), in terms
#of parameters in Vars, finds a set of algebraic equations
#that these parameters must satisfy, in order to
#have a closed form evaluation of degree d
#For example, try:
#NakhDEqs([-n,-n+1/2],[4*n+3/2],1/5,n,4,{}):
NakhDEqs:=proc(N1,D1,x,n,d,Vars) local mu,eq:
mu:=EvR(N1,D1,x,n,2*d+6+nops(Vars)):
if mu=FAIL then
 RETURN(FAIL):
fi:

eq:=GRdPEqs(mu,d,n,Vars):

eq,Vars:
end:



#Find2F1x(N,M,den,n,deg): all the strange 2F1(-a*n,b*n+b1,c*n+c1;x)
#where the right x's are also outputted
#with a pos. int. between 1 and N, b and c integers
#between -N and N, and b1,c1 rational numbers with
#denominator=den. For example, try:
#Find2F1x(2,1,1,n,2);
Find2F1x:=proc(N,M,d,n,deg)
local N1,D1,a,b,c,H,b1,c1,mu,m,x,lu:

H:={}:

for a from 1 to N do
 for b from -a to a do
  for c from -N to N do
     for b1 from -M*d to M*d do
      for c1 from -M*d to M*d do
      if igcd(b1,d)=1  and igcd(c1,d)=1 then
          N1:=[-a*n,b*n+b1/d]:
          D1:=[c*n+c1/d]:


 if IsKosher(N1,D1,n)  then
           mu:=NakhDx(N1,D1,n,deg):
                         
         for m in mu do
           if  (not IsAlmostKummerianBuddy([N1,D1,m],n) 
                and not IsApaZbuddy([N1,D1,m],n) ) then
                lu:=NakhD([N1,D1,m],n,deg):
                 if lu<>FAIL then
                     H:=H union {[N1,D1,m]}:
                 fi:
            fi:
         od:
fi:
fi:
      od:
  od:
od:
od:
od:

WeedOutC(H,n):

end:



#Kulam(N,M,den,n,Maxdeg): All the strange evaluations
#of the form 2F1(-a*n,b*n+b1,c*n+c1;x) where
#1<=a, |b|,|c| <=N, |b1|,|c1|<=M, the denominator of
#b1, c1 is <=den, and the evaluation is of degree<=Maxdeg
#For example, try:
#Kulam(2,2,2,n,2);
Kulam:=proc(N,M,den,n,Maxdeg) local lu,deg,gu,den1:

gu:={}:

for deg from 0 to Maxdeg do
for den1 from 1 to den do

lu[deg,den1]:=Find2F1x(N,M,den1,n,deg):

print(`The strange evaluations with denominator`,den1):
print(`and degree<=`, deg,` are`):

print(lu[deg,den1]):

gu:=gu union lu[deg,den1]:
od:
od:

op(lu),gu:

end:


pas1:=proc(a) local a1,a2,a2c:
a1:=numer(a):
a2:=denom(a):

if type(a2,`+`) then
  a2c:=Conj11(a2):
fi:
a1:=simplify(expand(a1*a2c)):
a2:=simplify(expand(a2*a2c)):

normal(a1/a2):
end:


#Reci(Tri,n): Given a triple [A,B,x] where A is a list
#of length two, B a list of length 1, and C a number
#representing a 2F1(A,B;x), outputs the triple that
#corresponds to the reciprocal series
#For example, try:
#Reci([[-n,2*n],[-2*n],2],n);
Reci:=proc(Tri,n) local T1,T2,x,A,B,C,lu:
if not type(Tri,list) or nops(Tri)<>3 then
ERROR(`Bad input`):
fi:

T1:=Tri[1]:T2:=Tri[2]: x:=Tri[3]:

if not (type(T1,list) and type(T2,list) and nops(T1)=2 and nops(T2)=1) then
 ERROR(`Bad input`):
fi:

A:=T1[1]: B:=T1[2]: C:=T2[1]:

lu:=[[A,-(C-A-1)],[-(B-A-1)],pas1(1/x)]:


if IsKosher(lu[1],lu[2],n) then
 lu:
else
 FAIL:
fi:

end:




##########################
#PfaffT1(HG):Applies (2.3.14) in AAR
PfaffT1:=proc(HG):
if not (nops(HG)=3 and nops(HG[1])=2 and nops(HG[2])=1) then
 print(`Not a 2F1`):
 RETURN(FAIL):
fi:
normal([HG[1],[HG[1][1]+HG[1][2]+1-HG[2][1]],1-HG[3]]):end:

#PfaffT2(HG): Applies (2.2.6) in AAR
PfaffT2:=proc(HG):
if not (nops(HG)=3 and nops(HG[1])=2 and nops(HG[2])=1) then
 print(`Not a 2F1`):
 RETURN(FAIL):
fi:
normal([[HG[1][1], HG[2][1]-HG[1][2]],HG[2],HG[3]/(HG[3]-1)]):end:


#Euler(HG): Applies (2.2.7) in AAR
Euler:=proc(HG):
if not (nops(HG)=3 and nops(HG[1])=2 and nops(HG[2])=1) then
 print(`Not a 2F1`):
 RETURN(FAIL):
fi:
normal([[HG[2][1]-HG[1][1], HG[2][1]-HG[1][2]],HG[2],HG[3]]):end:

#Quad1(HG): Applies (3.1.3) in AAR
Quad1:=proc(HG):
if not (nops(HG)=3 and nops(HG[1])=2 and nops(HG[2])=1) then
 print(`Not a 2F1`):
 RETURN(FAIL):
fi:

if 2*HG[2][1]-HG[1][1]-HG[1][2]-1<>0 then

RETURN(FAIL):
fi:

[[HG[1][1]/2,HG[1][2]/2],HG[2],simplify(4*HG[3]*(1-HG[3]))]:end:

#Quad2a(HG): Applies (3.1.7) in AAR
Quad2a:=proc(HG):
if not (nops(HG)=3 and nops(HG[1])=2 and nops(HG[2])=1) then
 print(`Not a 2F1`):
 RETURN(FAIL):
fi:

if 2*HG[1][1]-HG[2][1]<>0 then
RETURN(FAIL):
fi:

[[HG[1][2]/2,(HG[1][2]+1)/2],[HG[1][1]+1/2], 
simplify((HG[3]/(2-HG[3]))^2)]:end:


#Quad2b(HG): Applies (3.1.7) in AAR
Quad2b:=proc(HG):
if not (nops(HG)=3 and nops(HG[1])=2 and nops(HG[2])=1) then
 print(`Not a 2F1`):
 RETURN(FAIL):
fi:

if 2*HG[1][2]-HG[2][1]<>0 then
RETURN(FAIL):
fi:

[[HG[1][1]/2,(HG[1][1]+1)/2],[HG[1][2]+1/2], 
simplify((HG[3]/(2-HG[3]))^2)]:end:



#Canon21(H,n): Given a hypergeometric series H=[H1,H2,x]
#phrased in terms of n, finds the canonical form, 
#for example, try: Canon([[-2*n-1,4*n],[3*n+1/3],1/4]);
Canon21:=proc(H,n) local A1,A2,B1,a1,a0,a11,a21,gu:
if not (type(H,list) and nops(H)=3 and type(H[1],list) and nops(H[1])=2
and type(H[2],list) and nops(H[2])=1 ) then
 ERROR(`Not 2F1 `):
fi:

A1:=H[1][1]:
A2:=H[1][2]:
B1:=H[2][1]:

a11:=coeff(A1,n,1):
a21:=coeff(A2,n,1):

if abs(a11)<abs(a21) then
 A1:=H[1][2]:
 A2:=H[1][1]:
fi:

gu:=[[A1,A2],[B1],H[3]]:

a1:=coeff(A1,n,1):

if a1>0 then
 gu:=subs(n=-n,gu):
fi:

A1:=gu[1][1]:

a1:=coeff(A1,n,1):

if a1=0 then
 RETURN(gu):
fi:
a0:=coeff(A1,n,0):


gu:=expand(subs(n=n-a0/a1,gu)):

if not type(coeff(gu[1][1],n),integer) then
 gu:=subs(n=n*denom(coeff(gu[1][1],n)),gu):
fi:
gu:

end:


#Buddies21a(H): all the immediate buddies of the 2F1 series
#H, For example try: Buddies21a([[a,b],[c],x]);
Buddies21a:=proc(H) :

{Euler(H), PfaffT1(H),PfaffT2(H)}:

end:

#Buddies21(H,k): all the distance <=k buddies of the 2F1 series
#H, For example try: Buddies21([[a,b],[c],x],3);
Buddies21:=proc(H,k) local gu,g:

if k=0 then
 RETURN({H}):
elif k=1 then
RETURN(Buddies21a(H)):
else
gu:=Buddies21a(H,k-1) :
RETURN(gu union {seq(op(Buddies21a(g)), g in gu)}):
fi:

end:



#IsKummerian(H): is H Kummerian? For example, try: 
#IsKummerian([[a,b],[1+a-b],-1]):
IsKummerian:=proc(H)

if H[3]=-1 and 
( (H[1][1]+1=H[1][2]+H[2][1]) or (H[1][2]+1=H[1][1]+H[2][1]) ) then
true:
else
false:
fi:
end:

#IsKummerianBuddy(H,n): is H a buddy of a Kummerian? For example, try: 
#IsKummerianBuddy([[a,b],[1+a-b],-1]):
IsKummerianBuddy:=proc(H,n) local gu,g:
gu:=Buddies21C(H,n):

for g in gu do

if g[3]=-1 and (g[1][1]+1=g[1][2]+g[2][1] or g[1][2]+1=g[1][1]+g[2] ) then
RETURN(true):
fi:

od:

false:

end:

#Buddies21C(H,n): all the buddies of H in canonical form
#For example, try:
#Buddies21C([[-3*n,n+1],[-2*n+1/2],1/2],n);
Buddies21C:=proc(H,n) local gu,g:
gu:=Buddies21(H,2):

{seq(Canon21(g,n), g in gu)}:
end:


Conj11:=proc(a):
if not type(a,`+`) then
 RETURN(FAIL):
else
 op(1,a)-op(2,a):
fi:
end:

Conj1:=proc(H) local a,a1:
a:=H[3]:

a1:=Conj11(a):

if a1<>FAIL then
 RETURN([H[1],H[2],a1]):
else
 RETURN(FAIL):
fi:

end:

CONJ1:=proc(S) local s,gu:
gu:={}:

for s in S do
 if Conj1(s)<>FAIL then
   gu:=gu union {Conj1(s)}:
 fi:
od:
gu:
end:

RECI1:=proc(S,n) local s,gu:
gu:={}:

for s in S do
 if Reci(s,n)<>FAIL then
   gu:=gu union {Reci(s,n)}:
 fi:
od:
gu:
end:



#WeedOut(S,n): Given a set of Hypergeometric 2F1's
#reduces it so that no memeber will have
#any buddies. For example, try:
#WeedOut({[[-n,3*n+1],[2*n],-1],n]});
WeedOut:=proc(S,n) local gu,mu:

if S={} then
 RETURN(S):
fi:

gu:={S[1]}:
mu:=S minus Buddies21C(S[1],n):

while mu<>{} do
gu:=gu union {mu[1]}:
mu:=(mu minus Buddies21C(mu[1],n)) minus {mu[1]}:
od:
gu:=gu minus subs(n=2*n,gu):
gu:=gu minus subs(n=3*n,gu):
gu:=gu minus subs(n=2*n,gu):

gu:=gu minus CONJ1(gu):

gu:=gu minus RECI1(gu,n):
end:




#QuadBuddies21(HG): The quadratic buddies of the 2F1 HG
#For example, try:
#QuadBuddies21([[a,b],[2*a],x]);
QuadBuddies21:=proc(HG) local gu,mu:
 gu:={}:

 mu:=Quad1(HG):
  if mu<>FAIL then
   gu:=gu union {mu}:
  fi:

 mu:=Quad2a(HG):
  if mu<>FAIL then
   gu:=gu union {mu}:
  fi:

 mu:=Quad2b(HG):
  if mu<>FAIL then
   gu:=gu union {mu}:
  fi:

gu:
end:

#QuadBuddies21S(S,n): all the quadratic buddies of a set of 
#2F1's S. For example, try: QuadBuddies21({[[a,b],[2*a],x]});
QuadBuddies21S:=proc(S,n) local h,gu,vu:
gu:={seq(op(QuadBuddies21(h)), h in S)}:

vu:={}:
for h in gu do
 vu:= vu union {Canon21(h,n)}:
od:
vu:
end:






#Buddies21Cs(SetOf2F1s,n): all the buddies of the
#members of SetOf2F1s in canonical form
#For example, try:
#Buddies21Cs({[[-3*n,n+1],[-2*n+1/2],1/2]},n);
Buddies21Cs:=proc(S,n) local g,gu:
gu:={seq(op(Buddies21C(g,n)),g in S)} :

gu:

end:


#QuadBuddies21S(S,n): all the quadratic buddies of a set of 
#2F1's S. For example, try: QuadBuddies21({[[a,b],[2*a],x]});
QuadBuddies21S:=proc(S,n) local h,gu,vu:
gu:={seq(op(QuadBuddies21(h)), h in S)}:

vu:={}:
for h in gu do
 vu:= vu union {Canon21(h,n)}:
od:
vu:

gu:={}:

for h in vu do
if NakhD(h,n,6)<>FAIL and not IsKummerianBuddy(h,n) 
and Buddies21C(h,n) intersect S ={} then
  gu:=gu union {h}:
fi:
od:

gu:

end:


###begin solving
#PtorOpe(ope,n,N,R): solving the recurrence ope(n,N)x(n)=0, x(0)=1
#in terms of rising factorial R(n,k) (R is a symbol)
#For example try PtorOpe((n+1)*N-1,n,N,R);
PtorOpe:=proc(ope,n,N,R)
local rat,c,t1,b1,t1c,b1c,i:

if degree(ope,N)<>1 then
 RETURN(FAIL):
fi:

rat:=normal(-coeff(ope,N,0)/coeff(ope,N,1)):
t1:=expand(numer(rat)):
b1:=expand(denom(rat)):

t1c:=coeff(t1,n,degree(t1,n)):
b1c:=coeff(b1,n,degree(b1,n)):

c:=t1c/b1c:

t1:=expand(t1/t1c):
b1:=expand(b1/b1c):


t1:=factor(t1):
b1:=factor(b1):

t1:=[solve(t1,n)]:
b1:= [solve(b1,n)]:

c^n* convert([seq(R(-t1[i],n),i=1..nops(t1))],`*`)/
convert([seq(R(-b1[i],n),i=1..nops(b1))],`*`):

end:

#PtorOpeF(ope,n,N): solving the recurrence ope(n,N)x(n)=0, x(0)=1
#in terms of factorials (R is a symbol)
#For example try PtorOpeF((n+1)*N-1,n,N,R);
PtorOpeF:=proc(ope,n,N)
local rat,c,t1,b1,t1c,b1c,i:

if degree(ope,N)<>1 then
 RETURN(FAIL):
fi:

rat:=normal(-coeff(ope,N,0)/coeff(ope,N,1)):
t1:=expand(numer(rat)):
b1:=expand(denom(rat)):

t1c:=coeff(t1,n,degree(t1,n)):
b1c:=coeff(b1,n,degree(b1,n)):

c:=t1c/b1c:

t1:=expand(t1/t1c):
b1:=expand(b1/b1c):


t1:=factor(t1):
b1:=factor(b1):

t1:=[solve(t1,n)]:
b1:= [solve(b1,n)]:

for i from 1 to nops(t1) do
 if type(t1[i],integer) and t1[i]>=0 then
   RETURN(FAIL):
 fi:
od:

for i from 1 to nops(b1) do
 if type(b1[i],integer) and b1[i]>=0 then
   RETURN(FAIL):
 fi:
od:

c^n* 
normal(convert([seq((-t1[i]+n-1)!/(-t1[i]-1)!,i=1..nops(t1))],`*`)/
convert([seq((-b1[i]+n-1)!/(-b1[i]-1)!,i=1..nops(b1))],`*`)):

end:


#ExtractP(f,n): Given a rational function f of n
#finds the largest P(n) such that f(n) can be written
#as P(n+1)g(n+1)/(P(n)g(n)) for some rational function g
#the ouput is P followed by g
#for example, try:ExtractP((n+1)/n,n)
ExtractP:=proc(f,n) local T,B,P,g,r,i:
T:=numer(f):
B:=denom(f):

for r from 1 to 30 while gcd(B,subs(n=n-r,T))=1 do od:

if r=31 then
RETURN(1,f):
else

P:=gcd(B,subs(n=n-r,T)):

P:=mul(subs(n=n+i,P),i=0..r-1):

g:=normal(f/(subs(n=n+1,P)/P)):



if not normal(subs(n=n+1,P)/P*g-f)=0 then
 RETURN(FAIL):
else
RETURN(P,g):
fi:
 
fi:
end:


#Panekh(f,n,R): solves the equation x(n+1)/x(n)=f(n) in terms
#of n and the raising factorial R(a,n)
#For example, try: Panekh((n+1/2)/(n+1/3),n,R);
Panekh:=proc(f,n,R) local ope,N,P,Q,gu,g,gu1:

gu:=ExtractP(f,n):

P:=gu[1]:
g:=gu[2]:

gu1:=ExtractP(1/g,n):

Q:=gu1[1]:
g:=1/gu1[2]:
ope:=denom(g)*N-numer(g):


P/Q*PtorOpe(ope,n,N,R):

end:


#PanekhF(f,n,R): solves the equation x(n+1)/x(n)=f(n) in terms
#of n and factorials
#For example, try: PanekhF((n+1/2)/(n+1/3),n);
PanekhF:=proc(f,n) local ope,N,P,Q,gu,g,gu1:

gu:=ExtractP(f,n):

P:=gu[1]:
g:=gu[2]:

gu1:=ExtractP(1/g,n):

Q:=gu1[1]:
g:=1/gu1[2]:
ope:=denom(g)*N-numer(g):


P/Q*PtorOpeF(ope,n,N):

end:


####solving


#Theorem(H,n,R,Deg): Given a good hypergeometric 2F1, phrased
#in terms of H, (with exact evaluation of degree Deg)
#states the exact evaluation using R(a,n)
#to denote the rising factorial (a)_n:=a(a+1)*...*(a+n-1);
#For example try: 
#Theorem([[-n,a],[b],1],n,R,4);
Theorem:=proc(H,n,R,Deg) local lu:
lu:=NakhD(H,n,Deg):

if lu=FAIL then
  RETURN(FAIL):
fi:

[H,Panekh(lu,n,R)]:

end:





#IsAlmostKummerian(H): is H Almost Kummerian? For example, try: 
#IsKummerian([[a,b],[-4-a-b],-1]):
IsAlmostKummerian:=proc(H)

if H[3]=-1 and 
( type(H[1][1]-H[1][2]-H[2][1],integer) or 
type(H[1][2]-H[1][1]-H[2][1],integer) ) then
true:
else
false:
fi:
end:

#IsAlmostKummerianBuddy(H,n): is H a buddy of a Kummerian? For example, try: 
#IsAlmostKummerianBuddy([[a,b],[1+a-b],-1]):
IsAlmostKummerianBuddy:=proc(H,n) local gu,g:
gu:=Buddies21C(H,n):

for g in gu do

if IsAlmostKummerian(g) then
RETURN(true):
fi:

od:

false:

end:


#WeedOutC(S,n): Given a set of Hypergeometric 2F1's
#reduces it so that no memeber will have
#any buddies. Then removes all the almost Kummerian ones
#and their buddies For example, try:
#WeedOutC({[[-n,3*n+1],[2*n],-1],n]});
WeedOutC:=proc(S,n) local gu,H,h:
H:=WeedOut(S,n):
gu:={}:
for h in  H do
  if not IsAlmostKummerianBuddy(h,n) then
    gu:=gu union {h}:
  fi:
od:
WeedOut(gu,n):
end:



#Theorem21(H,n,R,Deg,F): Given a good hypergeometric 2F1, phrased
#in terms of H, (with exact evaluation of degree Deg)
#states the exact evaluation using R(a,n)
#to denote the rising factorial (a)_n:=a(a+1)*...*(a+n-1);
#For example try: 
#Theorem21([[-n,a],[b],1],n,R,4,F);
Theorem21:=proc(H,n,R,Deg,F) local lu:
lu:=NakhD(H,n,Deg):

if lu=FAIL then
  RETURN(FAIL):
fi:

F(H[1][1],H[1][2],H[2][1],H[3])=Panekh(lu,n,R):
end:




#Sefer21(H,n,Deg): Given a set of pre-computed hypergeometric
#2F1's, outputs the list
#For example, try:
#Sefer21(PreComputed21(),n,Deg);
Sefer21:=proc(H,n,Deg) local i,lu,c,R,F:

print(` Interesting Hypergeometric Theorems `):
print():
print(`By Shalosh B. Ekhad `):
print():
print(`Let R(a,n) denote the rising factorial: a(a+1)...(a+n-1). `):
c:=0:
for i from 1 to nops(H) do
 lu:=Theorem21(H[i],n,R,Deg,F):
  if lu<>FAIL then
  c:=c+1:
  print(`Theorem `, c, `: `, lu):
 fi:
od:

end:





#Iceberg(H,n,d): Does H=[N1,D1,x] seem to be part of
#an infinite family with D1 replaced by adding integers
#where H is given by a closed form of degree d .
#For example, try:
#Iceberg([[-2*n,b],[1-2*n-b+r],-1],n,2);
Iceberg:=proc(H,n,d) local i:

for i from 1 to 4 do
 if NakhD([H[1],[H[2][1]-i],H[3]] ,n,d+i)=FAIL then
  RETURN(false):
 fi:
od:

true:

end:
   


#Sefer21Iceberg(H,n,Deg): Given a set of pre-computed hypergeometric
#2F1's, outputs the list of theorems
#For example, try:
#Sefer21Iceberg(PreComputed21(),n,Deg);
Sefer21Iceberg:=proc(H,n,Deg) local i,lu,c,R,F:

print(` Interesting Hypergeometric Theorems `):
print():
print(`By Shalosh B. Ekhad `):
print():
print(`Let R(a,n) denote the rising factorial: a(a+1)...(a+n-1). `):
c:=0:
for i from 1 to nops(H) do
 lu:=Theorem21(H[i],n,R,Deg,F):
  if lu<>FAIL then
  c:=c+1:
  print(`Theorem `, c, `: `, lu):
   if Iceberg(H[i],n,Deg) then
     print(`Note: Tip of an Iceberg`):
   fi:
 fi:
od:

end:



#FindTips(H,n,Deg): Given a set of Hypergeometric nice
#evaluations, H,  (phrased in terms of n),
#finds those that are tips of icebergs
#(up to degree Deg)
#For example, try:
#FindTips(PreComputed21(),n,4);
FindTips:=proc(H,n,Deg) local gu,h:
gu:={}:

for h in H do
 if Iceberg(h,n,Deg) then
   gu:=gu union {h}:
 fi:
od:
gu:
end:



IsApaZ:=proc(H,n):

if H[3]=-3 and
(H[1][1]=-2*n and type(H[1][2]+1/2,integer) and
 type(H[2][1]+1/2+3*n,integer) ) then
RETURN(true):
fi:

if H[3]=-3 and
(H[1][1]=-3*n and type(H[1][2]+n+1/2,integer) and
 type(H[2][1]+1/2+3*n,integer) ) then
RETURN(true):
fi:

false:

end:





IsApaZbuddy:=proc(H,n) local gu,g:
gu:=Buddies21C(H,n):
gu:=gu union RECI1(gu,n):
if member(true,{seq(IsApaZ(g,n), g in gu)}) then
 RETURN(true):
else
 RETURN(false):
fi:

end:


#EvHpol1(N1,D1,pol,x,k,n,n0):Evaluates a hypegeometric terminating
#series, with a polynomial pol(n,k) multiplied in the summand
# whose first item of numerator is -a*n
#a integer, featuring the distrete variables n and k, with
#argument x. For example, try: EvHpol1([-n,a],[b],n+2*k,1,k,n,n0);
EvHpol1:=proc(N1,D1,pol,x,k,n,n0) local a,i,N10,D10,k1:

a:=-coeff(N1[1],n,1):

if not ( type(a,integer)  and a>0 ) then
ERROR(`Bad input `):
fi:

N10:=subs(n=n0,N1):
D10:=subs(n=n0,D1):

normal(add(
subs({n=n0,k=k1},pol)*mul(rf(N10[i],k1),i=1..nops(N10))/
mul(rf(D10[i],k1),i=1..nops(D10))/k1!*x^k1,k1=0..a*n0)):

end:





#EvRpol1(N1,D1,pol,x,k,n,n0): 
#the sequence of ratios of 2F1(N1,D1,x,pol1) up to n0
#For example, do:
#EvRpol1([-2*n,n+1/2],[1/3],n+2*k,2,n,10);
EvRpol1:=proc(N1,D1,pol,x,k,n,n0) local gu,i:

gu:=normal([seq(EvHpol1(N1,D1,pol,x,k,n,i),i=1..n0+1)]):


if member(0,{op(gu)}) then
 RETURN(FAIL):
fi:

normal([seq(gu[i+1]/gu[i],i=1..n0)]):

end:



#NakhDpol1(H,pol,k,n,d): guesses a rational function
#for EvRpol1(N1,D1,pol,x,k,n,n0)
NakhDpol1:=proc(H,pol,k,n,d) local mu,vu,N1,D1,x,i:
N1:=H[1]: D1:=H[2]: x:=H[3]:
if type(N1[1],numeric) then
  RETURN(FAIL):
fi:
mu:=EvRpol1(N1,D1,pol,x,k,n,2*d+4):
if mu=FAIL then
 RETURN(FAIL):
fi:
vu:=factor(GRd(mu,d,n)):

mu:=normal(EvRpol1(N1,D1,pol,x,k,n,2*d+10)):

if [seq(normal(subs(n=i,vu)-mu[i]),i=1..nops(mu) )]<>[0$nops(mu)] then
 RETURN(FAIL):
else
  RETURN(vu):
fi:

end:




#Target2F1pol1(A,B,C,x,n,d,N0,k): Given a 0-parameter 2F1(A,B;C;x)
#tries to conjecture a one-parameter generalization
#in the form 2F1(-a*n,b*n+b1,c*n+c1;x,pol1), where pol1 is
#a linear polynomial in n and k
#with 1<=a<=N0, -N0<=b,c<=N0 closed-form of degree d
#For example, try Target2F1pol1(1/2,1/2,1,1/2,n,2,2,k);
Target2F1pol1:=proc(A,B,C,x,n,d,N0,k) local a,b,c,b1,c1,N1,D1,
mu,e2,pol1,gu,lu,mu1,mu2,vu:



for a from 1 to N0 do
 for b from -N0 to N0 do
  for c from -N0 to N0 do
 pol1:=k+e2*(n+A/a):
    b1:=B+b*A/a:
    c1:=C+c*A/a:
    N1:=[-a*n,b*n+b1]: D1:=[c*n+c1]:

    if IsKosher(N1,D1,n) then  

    gu:=EvRpol1(N1,D1,pol1,x,k,n,2*d+10):

     mu:=GRdPEqs(gu,d,n,{e2}):
    mu1:=mu[1]:
    mu2:=mu[2]:
     vu:=gcd(mu1,mu2):

       if degree(vu,e2)>0 then
        RETURN([N1,D1,x],vu):
     fi:
    fi:
  od:
 od:
od:
FAIL:
end:


#AlmostKummerPolD(n,b,r): The Almost-Kummer Polynomial in n, b
#that stands in front of 2F1([-2*n,b],[r-2*n-b],-1);
#Here n and b are symbols, while r is a pos. integer
#For example, try:
#AlmostKummerPolD(n,b,2);
AlmostKummerPolD:=proc(n,b,r) local r1,R,gu,mu:

if r mod 2 =0 then
 r1:=r/2:
gu:=Panekh(NakhD([[-2*n,b],[r-2*n-b],-1],n,r1+4),n,R):
mu:=R(1/2,n)*R(b+1-r1,n)/(R(b/2+1-r1,n)*R(b/2+1/2-r1,n)):
normal(gu/mu):
else
r1:=(r-1)/2:
gu:=Panekh(NakhD([[-2*n,b],[r-2*n-b],-1],n,r1+4),n,R):
mu:=R(1/2,n)*R(b-r1,n)/(R(b/2-r1,n)*R(b/2-r1+1/2,n)):
normal(gu/mu):
fi:

end:


RF:=proc(a,k):(a+k-1)!/(a-1)!:end:

with(SumTools[Hypergeometric]):

#AlmostKummerPf(n,b,r,N): The Almost-Kummer Proof in n, b
#that stands in front of 2F1([-2*n,b],[r-2*n-b],-1);
#Here n and b are symbols, while r is a pos. integer
#For example, try:
#AlmostKummerPf(n,b,2,N);
AlmostKummerPf:=proc(n,b,r,N) local P,F,mu,r1,k,ope:



P:=AlmostKummerPolD(n,b,r):


F:=RF(-2*n,k)*RF(b,k)/RF(r-2*n-b,k)/k!*(-1)^k:

if r mod 2=0 then
 r1:=r/2:
 mu:=RF(1/2,n)*RF(b+1-r1,n)/(RF(b/2+1-r1,n)*RF(b/2+1/2-r1,n)):
else
 r1:=(r-1)/2:
 mu:=RF(1/2,n)*RF(b-r1,n)/(RF(b/2-r1,n)*RF(b/2-r1+1/2,n)):
fi:


F:=F/mu:
F:=F/P:
ope:=Zeilberger(F,n,k,N):
evalb(expand(subs(N=1,ope[1]))=0),ope:

end:


#AlmostKummerOpeEven(n,b,r,N): The Almost-Kummer Operator in n, b
#that stands in front of 2F1([-2*n,b],[2*r-2*n-b],-1);
#Here n and b are symbols, with symbolic (or numeric) r
#For example, try:
#AlmostKummerOpeEven(n,b,r,N);
AlmostKummerOpeEven:=proc(n,b,r,N) local F,mu,k,P1,k1,mu1:
option remember:
F:=RF(-2*n,k)*RF(b,k)/RF(2*r-2*n-b,k)/k!*(-1)^k:


 mu:=RF(1/2,n)*RF(b+1-r,n)/(RF(b/2+1-r,n)*RF(b/2+1/2-r,n)):
mu:=simplify(mu):
F:=F/mu:

mu1:=simplify(expand(normal(subs(n=1,mu)))):

P1:=add(rf(-2,k1)*rf(b,k1)/rf(2*r-2-b,k1)/k1!*(-1)^k1,k1=0..2):
P1:=normal(P1/mu1):
Zeilberger(F,n,k,N)[1],[1,P1]:
end:

#HafelOpe(ope,POL,n,N): applies the operator ope(n,N) to the 
#polynomial POL for example, try: HafelOpe(N-1,n^2,n,N);
HafelOpe:=proc(ope,POL,n,N) local i:
expand(add(coeff(ope,N,i)*subs(n=n+i,POL),i=ldegree(ope,N)..degree(ope,N))):
end:






TestAlmostKummer:=proc(n0,b,r) local k,gu,mu,P,n:
gu:=normal(add(rf(-2*n0,k)*rf(b,k)/rf(2*r-2*n0-b,k)/k!*(-1)^k,k=0..2*n0)):

 mu:=rf(1/2,n0)*rf(b+1-r,n0)/(rf(b/2+1-r,n0)*rf(b/2+1/2-r,n0)*rf(b-r+1,r-1)):

P:=AlmostKummerPolD(n,b,2*r):
P:=subs(n=n0,P):
normal(gu/mu/P):



end:





#AlmostKummerPolEven(n,b,r): The Almost-Kummer Polynomial in n, b
#that stands in front of 2F1([-2*n,b],[2*r-2*n-b],-1);
#using the operator
#Here n and b are symbols, while r is a pos. integer
#For example, try:
#AlmostKummerPolEven(n,b,1);
AlmostKummerPolEven:=proc(n,b,r) local gu,a,i,N,pol,eq,
var,ope,pol1,i1:

gu:=AlmostKummerOpeEven(n,b,r,N):

ope:=gu[1]:
gu:=gu[2]:

pol:=add(a[i]*n^i,i=0..r-1):
var:={seq(a[i],i=0..r-1)}:

eq:={subs(n=0,pol)=gu[1],subs(n=1,pol)=gu[2]}:
pol1:=HafelOpe(ope,pol,n,N):

eq:=eq union {seq(coeff(pol1,n,i1),i1=0..degree(pol1,n))}:

var:=solve(eq,var):

if var=NULL then
 RETURN(FAIL):
fi:

factor(subs(var,pol)):

end:



#AlmostKummerPolEvenB(n,b,r,B): The Almost-Kummer Polynomial in n, b
#in terms of binomial(n,r) rather than n^r
#that stands in front of 2F1([-2*n,b],[2*r-2*n-b],-1);
#using the operator
#Here n and b are symbols, while r is a pos. integer
#For example, try:
#AlmostKummerPolEvenB(n,b,1,B);
AlmostKummerPolEvenB:=proc(n,b,r,B) local gu,a,i,N,pol,eq,
var,ope,pol1,i1,Pol:

gu:=AlmostKummerOpeEven(n,b,r,N):

ope:=gu[1]:
gu:=gu[2]:

Pol:=add(a[i]*B(n,i),i=0..r-1):
pol:=expand(add(a[i]*binomial(n,i),i=0..r-1)):
var:={seq(a[i],i=0..r-1)}:

eq:={subs(n=0,pol)=gu[1],subs(n=1,pol)=gu[2]}:
pol1:=expand(HafelOpe(ope,pol,n,N)):

eq:=eq union {seq(coeff(pol1,n,i1),i1=0..degree(pol1,n))}:

var:=solve(eq,var):

if var=NULL then
 RETURN(FAIL):
fi:

Pol:=subs(var,Pol):

add(factor(coeff(Pol,B(n,i),1))*B(n,i),i=0..r-1):

end:





#TestAlmostKummerC(n0,b,r): tests the Almost Kummer Theorem for
#n=n0 and integer r. b is a symbol. For example, try:
#TestAlmostKummerC(4,b,3);
TestAlmostKummerC:=proc(n0,b,r) local k,gu,mu,P,n,i,i1:
gu:=normal(add(rf(-2*n0,k)*rf(b,k)/rf(2*r-2*n0-b,k)/k!*(-1)^k,k=0..2*n0)):

 mu:=rf(1/2,n0)*rf(b+1-r,n0)/(rf(b/2+1-r,n0)*rf(b/2+1/2-r,n0)):

P:=add(binomial(n0,i)*
binomial(r+i-1,2*i)*i!*2^(2*i)/mul(b-r+i1,i1=1..i),i=0..r-1):
normal(gu/mu/P):
end:



Test11:=proc(n,b,r,B) local i,i1,P:
P:=add(B(n,i)*
binomial(r+i-1,2*i)*i!*2^(2*i)/mul(b-r+i1,i1=1..i),i=0..r-1):
evalb(P=AlmostKummerPolEvenB(n,b,r,B)):
end:



#ApaZpolD(n,i,j): The Apagodu-Zeilbeberger polynomial in n
#(computed directly)
#that stands in front of 2F1([-2*n,-1/2+3*i],[-3*n-1/2+3*j],-3);
#Here n is a symbol, while i and j area non-negative integers
#For example, try:
#ApaZpolD(n,2,3);
ApaZpolD:=proc(n,i,j) local R,gu,mu:
gu:=Panekh(NakhD([[-2*n,-1/2+3*i],[-3*n-1/2+3*j],-3],n,3*i+3*j+2),n,R):
mu:=R(i-j+1/3,n)*R(i-j+2/3,n)/(rf(n-3*j+3/2,2*j-1)*R(5/6-j,n)*R(7/6-j,n)):
normal(gu/mu):
end:





#ApaZope(n,i,j,N): The Apagodu-Zeilbeger Operator in n,
#that stands in front of 2F1([-2*n,-1/2+3*i],[-3*n-1/2+3*j],-3);
#Here n is a symbol, with symbolic (or numeric) i,j
#For example, try:
#ApaZope(n,i,j,N);
ApaZope:=proc(n,i,j,N) local F,mu,k,P1,k1:
option remember:
F:=RF(-2*n,k)*RF(-1/2+3*i,k)/RF(-3*n-1/2+3*j,k)/k!*(-3)^k:

 mu:=RF(i+1/3-j,n)*RF(i+2/3-j,n)/(RF(5/6-j,n)*RF(7/6-j,n)*RF(n-3*j+3/2,2*j-1)):


mu:=simplify(mu):
F:=normal(F/mu):


if type(i,integer) and type(j,integer) then
Zeilberger(F,n,k,N)[1],[ApaZpoln0(0,i,j),ApaZpoln0(1,i,j)]:
else
Zeilberger(F,n,k,N)[1]:
fi:

end:




#ApaZpoln0(n0,i,j): The Apagodu-Zeilbeberger polynomial at n0
#(computed directly)
#For example, try:
#ApaZpolD(5,2,3);
ApaZpoln0:=proc(n0,i,j) local n,gu,mu:
gu:=EvH([-2*n,-1/2+3*i],[-3*n-1/2+3*j],-3,n,n0):
mu:=rf(i-j+1/3,n0)*rf(i-j+2/3,n0)/(rf(n0-3*j+3/2,2*j-1)*rf(5/6-j,n0)
*rf(7/6-j,n0)):
normal(gu/mu):
end:


#ApaZpol(n,i,j): The Apagodu-Zeilberger Polynomial in n
#using the operator
#Here n is a symbol, while i j are a pos. integer
#For example, try:
#ApaZpol(n,1,1);
ApaZpol:=proc(n,i,j) local gu,a,N,pol,eq,
var,ope,pol1,i1,r:

gu:=ApaZope(n,i,j,N):

ope:=gu[1]:
gu:=gu[2]:

r:=i+2*j+2:
pol:=add(a[i1]*n^i1,i1=0..r-1):
var:={seq(a[i1],i1=0..r-1)}:

eq:={subs(n=0,pol)=gu[1],subs(n=1,pol)=gu[2]}:

pol1:=expand(HafelOpe(ope,pol,n,N)):

eq:=eq union {seq(coeff(pol1,n,i1),i1=0..degree(pol1,n))}:

var:=solve(eq,var):

if var=NULL then
 RETURN(FAIL):
fi:

factor(subs(var,pol)):

end:




#ApaZpolB(n,i,j,B): The Apagodu-Zeilberger Polynomial in n
#using the operator
#Here n is a symbol, while i j are a pos. integer
#For example, try:
#ApaZpolB(n,1,1,B);
ApaZpolB:=proc(n,i,j,B) local gu,a,N,pol,eq,
var,ope,pol1,i1,r,Pol,coe:

gu:=ApaZope(n,i,j,N):

ope:=gu[1]:
gu:=gu[2]:

r:=i+2*j+2:
pol:=add(a[i1]*expand(binomial(n,i1)),i1=0..r-1):
Pol:=add(a[i1]*B(n,i1),i1=0..r-1):

var:={seq(a[i1],i1=0..r-1)}:

eq:={subs(n=0,pol)=gu[1],subs(n=1,pol)=gu[2]}:

pol1:=expand(HafelOpe(ope,pol,n,N)):

eq:=eq union {seq(coeff(pol1,n,i1),i1=0..degree(pol1,n))}:

var:=solve(eq,var):

if var=NULL then
 RETURN(FAIL):
fi:

Pol:=subs(var,Pol):

coe:=coeff(Pol,B(n,0),1):
coe,add((coeff(Pol,B(n,i1),1)/coe)*B(n,i1),i1=0..degree(pol1,n)):

end:



#ApaZclosedForm(n,i,j,R): the closed-form expression for F(-2n,-1/2+i,-3n-1/2+j,-3)
#where i and j are integers, and R is a letter for the rising factorial
#function R(a,k)=a(a+1)...(a+k-1). 
#For example, try:
#ApaZclosedForm(n,2,3,R);
ApaZclosedForm:=proc(n,i,j,R)
Panekh(NakhD([[-2*n, -1/2+i],[-3*n-1/2+j],-3],n, abs(i)+abs(j)+3),n,R):
end:





#Theorem21Gamma(H,n,R,Deg,F): Given a good hypergeometric 2F1, phrased
#in terms of H, (with exact evaluation of degree Deg)
#states the exact evaluation in terms of the Gamma function
#For example try: 
#Theorem21Gamma([[-n,a],[b],1],n,R,4,F);
Theorem21Gamma:=proc(H,n,Deg,F) local lu:
lu:=NakhD(H,n,Deg):

if lu=FAIL then
  RETURN(FAIL):
fi:

lu:=Panekh(lu,n,RF):

lu:=convert(lu,GAMMA):
F(H[1][1],H[1][2],H[2][1],H[3])=lu:
end:

#Sefer21Gamma(H,n,Deg): Given a set of pre-computed hypergeometric
#2F1's, outputs the list of theorems expressed in terms of the 
#Gamma function.
#For example, try:
#Sefer21Gamma(PreComputed21(),n,Deg);
Sefer21Gamma:=proc(H,n,Deg) local i,lu,c,R,F:

print(` Interesting Hypergeometric Theorems `):
print():
print(`By Shalosh B. Ekhad `):
print():
print(`Let R(a,n) denote the rising factorial: a(a+1)...(a+n-1). `):
c:=0:
for i from 1 to nops(H) do
 lu:=Theorem21Gamma(H[i],n,Deg,F):
  if lu<>FAIL then
  c:=c+1:
  print(`Theorem `, c, `: `, lu):
 fi:
od:

end:
