#VERSION OF April 13, 1995 #First version: March 3, 1995; A package that implements Sylvester's #enhancement of Tchebychev's method for finidng upper and lower #bounds for psi(x)/x where psi(x) is the sum of log(p) over all #prime powers p^m <=x print(`Version of April 13, 1995`): print(`SYLVESTER: A Maple package written by Doron Zeilberger`): print(`For general help, and a list of functions, type "ezra()"`): print(`For specific help, type ezra(procedure_name)`): ezra:=proc() if args=NULL then print(`This is SYLVESTER, a Maple package implementing Sylvester's`): print( `obsolete(?) method given, in final form in his 1892 paper`): print(` In CW IV 687-731`): print(`Contains the following procedures: stigser,parsepos,parseneg,zugotpos`): print(`'zugotneg' ,'matri' ,'Iter' `): fi: if nops([args])=1 and op(1,[args])=`Iter` then print(` Iter(scheme,A_l,A_u) inputs a scheme and the current`): print(`lower and upper bounds for psi(x)/x, x large `): print(`and outputs improved ones`): print(`see Sylvester's CW IV, p. 717`): fi: if nops([args])=1 and op(1,[args])=`matri` then print(` matri(scheme,cutof) inputs a scheme and a numerical cutoff`): print(` finds the 2 by 2 matrix [[a,b],[c,d]] such that `): print(`u[i+1]=M+a*u[i]-b*v[i] ; v[i+1]=M+c*v[i]-d*u[i]`): print(`see Sylvester's CW IV, p. 713`): fi: if nops([args])=1 and op(1,[args])=`stigser` then print(`stigser(scheme) gives the stignatic series corresponding to the`): print(`scheme given as a list of lists [[a_1,...,a_r];[b_1,...,b_s]]`): print(`Corresponding to forming Sum_{i=0}^r T(x/a_i)-Sum_{i=0}^s T(x/b_i)`): print(`where T(x)=log(x!); The stigmatic series is the coding of the`): print(`periodic expression in psi(x). It is given as a list,each `): print(`entry of which is a list of two elements [a,b] where b is +1 or -1`): print(`and it represents the term b*psi(x/a), in the first period`): fi: if nops([args])=1 and op(1,[args])=`parsepos` then print(`parsepos(stig) inputs a stimatics series, in the form that is`): print(` outputted from stigser(), and outputs the decomposition into`): print(`an initial segment, folowed by "Irred. ballot paths", i.e. hills`): fi: if nops([args])=1 and op(1,[args])=`parseneg` then print(`parseneg(stig) inputs a stimatics series, in the form that is`): print(` outputted from stigser(), and outputs the decomposition into`): print(`an initial segment, folowed by "inverted Irr.ballot paths",valleies`): fi: if nops([args])=1 and op(1,[args])=`zugotpos` then print(`zugotpos(IP): given a list of 2-element lists [n,e] such that`): print(`the e's form an "irreducible upper ballot sequence", pairs up`): print(` like parentheses the corresponding pairs. `): print(`The output is given as a list of pairs of the n s`): fi: if nops([args])=1 and op(1,[args])=`zugotneg` then print(`zugotneg(IP): given a list of 2-element lists [n,e] such that`): print(`the e's form an "irreducible lower ballot sequence", pairs up`): print(` like parentheses the corresponding pairs. `): print(`The output is given as a list of pairs of the n s`): fi: end: #pol is a poly. ra is a rational function ple:=proc(pol,ra,x) local gu,i,pol1,gun,gud: pol1:=expand(pol): gu:=0: for i from 1 to degree(pol1,x) do gu:=gu+coeff(pol1,x,i)*subs(x=x^i,ra): gu:=normal(gu): od: gun:=expand(numer(gu)*(1-x)): gud:=expand(denom(gu)*(1-x)): gun:=taylor(gun,x=0,degree(gun)+1): gun,gud: end: #stigesr: Given a scheme [[a_1, .., a_r],[b_1,..., b_s]] finds #the `Stigmatic Series' stigser:=proc(scheme) local lu,schpos,schneg,i,j,pol, ra,gu,gun,gud,resh,x : schpos:=op(1,scheme): schneg:=op(2,scheme): ra:=x/(1-x): pol:=0: for i from 1 to nops(schpos) do pol:=pol+x^op(i,schpos): od: for i from 1 to nops(schneg) do pol:=pol-x^op(i,schneg): od: gu:=ple(pol,ra,x): gun:=gu[1]: gud:=gu[2]: resh:=[]: for i from 1 to degree(gud,x) do lu:=coeff(gun,x,i): if lu>0 then for j from 1 to lu do resh:=[op(resh),[i,1]]: od: elif lu<0 then for j from 1 to -lu do resh:=[op(resh),[i,-1]]: od: fi: od: resh: end: #parsepos(stig) intputs a stigmatics series given as a list of #2-element list [a,e] where e=+-1 and a in an integer that corresponds # to e*psi(x/a), and divides them into groups, just like in #Sylvester's CW IV, p. 707 parsepos:=proc(stig) local makh,i,gu,mu,parsum,hakhi,orekh,makom: #makh is the `makhzor, the period; parsum is the partial sum, hakhi is #minimum of the partial sums ; makom is the place where the recod takes #place orekh:=nops(stig): makh:=op(1,op(orekh,stig)): parsum:=0: hakhi:=0: makom:=0: for i from 1 to orekh do parsum:=parsum+op(2,op(i,stig)): if parsumhakhi then hakhi:=parsum: makom:=i: fi: od: mu:=[[op(1..makom,stig)]]: parsum:=0: lu:=[]: for i1 from makom+1 to orekh do parsum:=parsum+op(2,op(i1,stig)): lu:=[op(lu),op(i1,stig)]: if parsum=0 then mu:=[op(mu),lu]: lu:=[]: fi: od: for i from 1 to makom do parsum:=parsum+op(2,op(i,stig)): lu:=[op(lu),[op(1,op(i,stig))+makh,op(2,op(i,stig))]]: if parsum=0 then lu1:=[]: for i1 from 1 to nops(lu) do if op(1,op(i1,lu))cutof then a:=a+1/op(2,zug): lista:=[op(lista),1/op(2,zug)]: b:=b+1/op(1,zug): listb:=[op(listb),1/op(1,zug)]: if (op(2,zug)+makhzor)/(op(1,zug)+makhzor) >cutof then for i1 from 1 while (op(2,zug)+i1*makhzor)/(op(1,zug)+i1*makhzor)> cutof do a:=a+1/(op(2,zug)+i1*makhzor): lista:=[op(lista),1/(op(2,zug)+i1*makhzor)]: b:=b+1/(op(1,zug)+i1*makhzor): listb:=[op(listb),1/(op(1,zug)+i1*makhzor)]: od: fi: fi: od: od: mu:=op(1,parseneg1): mu1:=op(1,mu): if not (op(1,mu1)=1 and op(2,mu1)=1 ) then ERROR(`Something went wrong`): fi: for i from 2 to nops(mu) do mu11:=op(i,mu): if op(2,mu11)=-1 then c:=c+1/op(1,mu11): listc:=[op(listc),1/op(1,mu11)]: elif op(2,mu11)=1 then d:=d+1/op(1,mu11): listd:=[op(listd),1/op(1,mu11)]: else ERROR(`Something is wrong`): fi: od: for i from 2 to nops(parseneg1) do mu:=op(i,parseneg1): zugotneg1:=zugotneg(mu); for j from 1 to nops(zugotneg1) do zug:=op(j,zugotneg1): if op(2,zug)/op(1,zug)>cutof then c:=c+1/op(1,zug): listc:=[op(listc),1/op(1,zug)]: d:=d+1/op(2,zug): listd:=[op(listd),1/op(2,zug)]: if (op(2,zug)+makhzor)/(op(1,zug)+makhzor) >cutof then for i1 from 1 while (op(2,zug)+i1*makhzor)/(op(1,zug)+i1*makhzor)> cutof do c:=c+1/(op(1,zug)+i1*makhzor): listc:=[op(listc),1/(op(1,zug)+i1*makhzor)]: d:=d+1/(op(2,zug)+i1*makhzor): listd:=[op(listd),1/(op(2,zug)+i1*makhzor)]: od: fi: fi: od: od: ku1:=fsolve(rho^2-(a+c)*rho+(a*c-b*d)=0,rho): print(`The latent roots are`, ku1): E:=(1-b-c)/((1-a)*(1-c)-b*d)*M: F:=(1-a-d)/((1-a)*(1-c)-b*d)*M: print(`It follows from the Sylvester-Tchebycheff method that`): print(`If we already know that there exist A_u and A_l such that`): print(`for large x, psi(x)<=A_u x and psi(x)>=A_l x, with A_u/A_l larger `): print(`than`,cutof): print(`Then the new A_u is`): print(E,`=`,evalf(E),`...`): print(`and the new A_l is`): print(F,`=`,evalf(F),`...`): [[a,b],[d,c]],lista,listb,listd,listc,evalf(E),evalf(F),evalf(E/F): end: #Iter: Given a scheme and current best known upper and lower #bounds A_u and A_l finds new, possibly better ones Iter:=proc(scheme,A_l,A_u) local stigser1,parsepos1,parseneg1,a,b,c,d,mu,mu1,mu11,zugotpos1,zugotneg1, i1,zug,makhzor,i,j,lista,listb,listc,listd,schel,scher,M,E,F,cutof,lu: cutof:=A_u/A_l: M:=0: schel:=op(1,scheme): scher:=op(2,scheme): for i from 1 to nops(schel) do M:=M-log(op(i,schel))/op(i,schel): od: for i from 1 to nops(scher) do M:=M+log(op(i,scher))/op(i,scher): od: print(`The schematic multiplier is`): print(M): print(`Which is roughly`,evalf(M)): a:=0: b:=0: c:=0: d:=0: stigser1:=stigser(scheme): makhzor:=op(1,op(nops(stigser1),stigser1)): parseneg1:=parseneg(stigser1): parsepos1:=parsepos(stigser1): mu:=op(1,parsepos1): mu1:=op(1,mu): if not (op(1,mu1)=1 and op(2,mu1)=1 ) then ERROR(`Something went wrong`): fi: lista:=[]:listb:=[]:listc:=[]:listd:=[]: for i from 2 to nops(mu) do mu11:=op(i,mu): if op(2,mu11)=-1 then a:=a+1/op(1,mu11): lista:=[op(lista),1/op(1,mu11)]: elif op(2,mu11)=1 then b:=b+1/op(1,mu11): listb:=[op(listb),1/op(1,mu11)]: else ERROR(`Something is wrong`): fi: od: for i from 2 to nops(parsepos1) do mu:=op(i,parsepos1): zugotpos1:=zugotpos(mu); for j from 1 to nops(zugotpos1) do zug:=op(j,zugotpos1): if op(2,zug)/op(1,zug)>evalf(cutof) then a:=a+1/op(2,zug): lista:=[op(lista),1/op(2,zug)]: b:=b+1/op(1,zug): listb:=[op(listb),1/op(1,zug)]: if (op(2,zug)+makhzor)/(op(1,zug)+makhzor) >evalf(cutof) then for i1 from 1 while (op(2,zug)+i1*makhzor)/(op(1,zug)+i1*makhzor)> evalf(cutof) do a:=a+1/(op(2,zug)+i1*makhzor): lista:=[op(lista),1/(op(2,zug)+i1*makhzor)]: b:=b+1/(op(1,zug)+i1*makhzor): listb:=[op(listb),1/(op(1,zug)+i1*makhzor)]: od: fi: fi: od: od: mu:=op(1,parseneg1): mu1:=op(1,mu): if not (op(1,mu1)=1 and op(2,mu1)=1 ) then ERROR(`Something went wrong`): fi: for i from 2 to nops(mu) do mu11:=op(i,mu): if op(2,mu11)=-1 then c:=c+1/op(1,mu11): listc:=[op(listc),1/op(1,mu11)]: elif op(2,mu11)=1 then d:=d+1/op(1,mu11): listd:=[op(listd),1/op(1,mu11)]: else ERROR(`Something is wrong`): fi: od: for i from 2 to nops(parseneg1) do mu:=op(i,parseneg1): zugotneg1:=zugotneg(mu); for j from 1 to nops(zugotneg1) do zug:=op(j,zugotneg1): if op(2,zug)/op(1,zug)>evalf(cutof) then c:=c+1/op(1,zug): listc:=[op(listc),1/op(1,zug)]: d:=d+1/op(2,zug): listd:=[op(listd),1/op(2,zug)]: if (op(2,zug)+makhzor)/(op(1,zug)+makhzor) >evalf(cutof) then for i1 from 1 while (op(2,zug)+i1*makhzor)/(op(1,zug)+i1*makhzor)> evalf(cutof) do c:=c+1/(op(1,zug)+i1*makhzor): listc:=[op(listc),1/(op(1,zug)+i1*makhzor)]: d:=d+1/(op(2,zug)+i1*makhzor): listd:=[op(listd),1/(op(2,zug)+i1*makhzor)]: od: fi: fi: od: od: E:=M+a*A_u-b*A_l: F:=M+c*A_l-d*A_u: print(`It follows from the Sylvester-Tchebycheff method that`): print(`by taking the scheme`,scheme): print(`if we already know that there exist A_u and A_l such that`): print(`for large x, psi(x)<=A_u x and psi(x)>=A_l x`): print(`with A_u=`,evalf(A_u),`and A_l=`,evalf(A_l)): print(`Then the new A_u can be taken to be `): print(E,`=`,evalf(E),`...`): if evalf(E)evalf(A_l) then print(`Since this is a better lower bound, we adopt it`): else print(`Since this is a worse lower bound, we do not adopt it`): F:=A_l: fi: F,E,[[a,b],[d,c]],lista,listb,listd,listc,evalf(F),evalf(E): end: