###################################################################### ##ChowRobbins: Save this file as ChowRobbins # ## To use it, stay in the # ##same directory, get into Maple (by typing: maple ) # ##and then type: read ChowRobbins # ##Then follow the instructions given there # ## # ##Written by Luis A. Medina and Doron Zeilberger, Rutgers University, # #[medina, zeilberg] at math dot rutgers dot edu # ###################################################################### #Created: June 3, 2009 print(`Created: June 3, 2009`): print(` This is the Maple package ChowRobbins. `): print(`It is one of the packages that accompany the article `): print(`"An Experimental Mathematics Perspective on the Old, and`): print(`Still Open, Question of When to Stop" `): print(`by Luis Medina and Doron Zeilberger`): print(`available from Medina's and Zeilberger's websites`): 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 dealing with the criteria`): print(`of maximixing the prob. of supassing a given goal`): print(`type ezraGoal();, for help with`): print(`a specific procedure, type ezra(procedure_name); .`): print(``): print(`For a list of the procedures dealing with general prob. dist.`): print(`type ezraPD();, for help with`): print(`a specific procedure, type ezra(procedure_name); .`): print(``): print(`For a list of the MAIN 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: `): print(` Bd, CRpay, IsBoundaryPt, IsInteriorPt, PayOff, W `): else ezra(args): fi: end: ezraPD:=proc() if args=NULL then print(` The procedures with general prob. distributions are: `): print(`Av, CRt, CRtm, CRtFast, Mom, PrExc, Sd `): else ezra(args): fi: end: ezraGoal:=proc() if args=NULL then print(` The procedures with exceeding a goal are: `): print(` ComparativeGambling, CRg, CRgt `): else ezra(args): fi: end: ezraPreComputed:=proc() if args=NULL then print(`The pre-comuted data procedures are:`): print(` Beta10000, Beta50000, CutOffs2000 `): else ezra(args): fi: end: ezra:=proc() if args=NULL then print(`The main procedures are: BetaSeq,BetaSeqFloat,`): print(` CR, CRFast, CRm, CRmFloat, CRFastFloat, CutOffs, Sipur`): print(` SipurCG,TurningPoint `): print(` `): elif nops([args])=1 and op(1,[args])=Av then print(`Av(F,t): The average of the prob. dist. given by the p.g.f. F(t).`): print(`For example try Av((1+t)/2,t);`): elif nops([args])=1 and op(1,[args])=Bd then print(`Bd(N,beta): the set of boundary points of the discrete region `): print(`{[i,j]; 0<=i,0<=j, i+j<=N, i-j<=beta[i+j]}`): print(`For example, try:`): print(`Bd(4,[1,2,3]);`): elif nops([args])=1 and op(1,[args])=Beta10000 then print(`Beta10000():`): print(`The (sure!, using exact arithmetic, with rational number`): print(`sequence of pre-computed sequene of stopping times for n=1..50`): print(`with N=10000 `): print(`Warning: it is not rigorously proved that this is the same as`): print(`the ultimate sequence, N=inifinty, but it is very likely so`): print(`Do: Beta10000(); `): elif nops([args])=1 and op(1,[args])=Beta50000 then print(`Beta50000()`): print(`The (probably, using floating-point`): print(`sequence of pre-computed sequene of stopping times for n=1..186`): print(`with N=50000 `): print(`Warning: it is not rigorously proved that this is the same as`): print(`the ultimate sequence, N=inifinty, but it is rather likely so`): print(`Do: Beta50000(); `): elif nops([args])=1 and op(1,[args])=BetaSeq then print(`BetaSeq(N,m) the sequence of beta(N,n) the`): print(`for n=1...m of the`): print(`sequence such that you should stop as soon`): print(`as you reach an n such that`): print(`the number of #Heads- #Tails is>=beta(N,n)`): print(`if you are allowed N coin-tosses.`): print(`For example, try: BetaSeq(1000,10);`): elif nops([args])=1 and op(1,[args])=BetaSeqFloat then print(`BetaSeqFloat(N,m):like BetaSeq(N,m)`): print(`but using Floating point.`): print(`For example, try: BetaSeqFloat(1000,10);`): elif nops([args])=1 and op(1,[args])=ComparativeGambling then print(`ComparativeGambling(h,t,N,g): compares`): print(`the the max. expectation and the Goal-oriented`): print(`approaches to gambling if you have h heads and`): print(`t tails, with longevity N and goal g.`): print(`For example, try:`): print(`ComparativeGambling(2,1,200,3/4);`): elif nops([args])=1 and op(1,[args])=CR then print(`CR(i,j,N): In the coin-tossing game`): print(`if right now you have i Heads and j Tails`): print(`and you are allowed to toss a coin up to N times`): print(`and at any time you have the option to collect i/(i+j) or`): print(`to keep playing, hoping to do better, but taking a chance`): print(`of doing worse.`): print(`What is your expected gain?`): print(`It uses backwards induction. `): print(`The output is the expected gain`): print(`Warning: a much faster version is CRFast .`): print(`For example, try:`): print(`CR(2,1,54); `): elif nops([args])=1 and op(1,[args])=CRg then print(`CRg(i,j,N,g): In the coin-tossing game`): print(`if right now you have i Heads and j Tails`): print(`and you are allowed to toss a coin up to N times`): print(`and at any time you have the option to collect i/(i+j) or`): print(`to keep playing, hoping to do better, but taking a chance`): print(`of doing worse.`): print(`Your goal is to maximize your chance of getting>=g `): print(`What is your probability for that?`): print(`Of course if i/(i+j)>=g then it is 1, and you quit.`): print(`It uses backwards induction. `): print(`The output is the prob. of exiting the game with>=g`): print(`Warning: a much faster version is CRFast .`): print(`For example, try:`): print(`CRg(2,1,54,3/4); `): elif nops([args])=1 and op(1,[args])=CRgt then print(`CRgt(i,j,N,g,t): Like CRg(i,j,N,g) `): print(`but second component gives the prob. gen. function of gain`): print(`For example, try:`): print(`CRgt(2,1,54,3/4,t); `): elif nops([args])=1 and op(1,[args])=CRpay then print(`CRpay(i,j,N): same as CR(i,j,N)`): print(`using PayOff `): print(`For example, try:`): print(`CRpay(2,1,54); `): elif nops([args])=1 and op(1,[args])=CRt then print(`CRt(i,j,N,t): like CR(i,j,N)`): print(`but returns in addition to the expectation`): print(`also the prob. gen. function`): print(`Warning: a much faster version is CRFast .`): print(`For example, try:`): print(`CRt(2,1,54,t); `): elif nops([args])=1 and op(1,[args])=CRtFast then print(`CRtFast(N,K1,K2,t) the table of CRt(i,j,N,t)`): print(`from i+j=K1 to i+j=K2. In particular, to get the whole`): print(`table., type CRFast(N,N,0); `): print(`For example, try: `): print(`CRtFast(10,10,0,t);`): print(`CRtFast(10,1,0,t);`): elif nops([args])=1 and op(1,[args])=CRm then print(`CRm(i,j,N): faster version of CR(i,j,N).`): print(`For example, try:`): print(`CRm(2,1,54); `): elif nops([args])=1 and op(1,[args])=CRtm then print(`CRtm(i,j,N): faster version of CRt(i,j,N,t).`): print(`For example, try:`): print(`CRtm(2,1,54,t); `): elif nops([args])=1 and op(1,[args])=CRmFloat then print(`CRmFloat(i,j,N): faster version of CRf(i,j,N).`): print(`For example, try:`): print(`CRmFloat(2,1,54); `): elif nops([args])=1 and op(1,[args])=CRFast then print(`CRFast(N,K1,K2) the table of CR(i,j,N)`): print(`from i+j=K1 to i+j=K2. In particular, to get the whole`): print(`table., type CRFast(N,N,0); `): print(`For example, try: `): print(`CRFast(10,10,0);`): print(`CRFast(10,1,0);`): elif nops([args])=1 and op(1,[args])=CRFastFloat then print(`CRFastFloat(N,K1,K2): a (faster) floating-point`): print(`version of CRFast(N,K1,K2)`); print(`For example, try: `): print(`CRFastFloat(10,10,0);`): print(`CRFastFloat(10,1,0);`): elif nops([args])=1 and op(1,[args])=CutOffs then print(`CutOffs(N,m) the sequence of cutsoffs (h,t) `): print(`for each h+t=k, k<=m, (the smallest number of heads where `): print(`it is a GO with longevity N, and the first N1 where it is a GO.`): print(`For example, try: CutOffs(1000,10);`): elif nops([args])=1 and op(1,[args])=CutOffs2000 then print(`CutOffs2000(): The sequence of size 100 whose i-th entry`): print(`is the pair [[h,t],HowOld] where [h,t] is the position with`): print(`smallest h such that h+t=i and for N=20000 it is a GO position`): print(`(so it is definitely a GO position for N=infinity, but there`): print(`is a (very slight) chance that [h+1,i-h-1] is also a GO position`): print(`for N=infinity (but for N=2000, it is definitly a STOP) `): print(`HowOld is the first N such that for N=HowOld it is GO`): print(`but for N=g. For example, try`): print(`PrExc((1+t+t^2)/3,t,1);`): elif nops([args])=1 and op(1,[args])=Sd then print(`Sd(F,t): The standard deviation`): print(` of the prob. dist. given by the p.g.f. F(t).`): print(`For example try Sd((1+t)/2,t);`): elif nops([args])=1 and op(1,[args])=Sipur then print(`Sipur(N,m,r): All the info about expected gain`): print(`for positions with i+j<=m living up to N tosses`): print(`with resolution r for prob.`): print(`For example, try:`): print(`Sipur(200,3,.1);`): elif nops([args])=1 and op(1,[args])=SipurCG then print(`SipurCG(N,m,r): All the info about comparative gambling with`): print(`various goals`): print(`for positions with i+j<=m living up to N tosses`): print(`with resolution r for prob.`): print(`For example, try:`): print(`SipurCG(200,3,.1);`): elif nops([args])=1 and op(1,[args])=TurningPoint then print(`TurningPoint(i,j,N0): The first N<=N0 (if it exists)`): print(`such that i Heads and j Tails starts being GO rather`): print(`than Stop. For example, try:`): print(`TurningPoint(2,1,100);`): elif nops([args])=1 and op(1,[args])=W then print(`W(pt1,pt2,N,beta): The number of walks from pt1 to pt2`): print(`staying in the region i+jN then RETURN(FAIL): fi: if i+j=N then RETURN(max(1/2,i/N)): elif i+j>0 then RETURN(max( (CR(i+1,j,N)+CR(i,j+1,N))/2, i/(i+j) )): else RETURN(max( (CR(i+1,j,N)+CR(i,j+1,N))/2)): fi: end: #CRf(i,j,N): backwards induction for the coin-tossing game #when you have to quit after N steps CRf:=proc(i,j,N) option remember: if i+j>N then RETURN(FAIL): fi: if i+j=N then RETURN(max(.5,evalf(i/N))): elif i+j>0 then RETURN(evalf(max( (CR(i+1,j,N)+CR(i,j+1,N))/2, i/(i+j) ))): else RETURN(evalf(max( (CR(i+1,j,N)+CR(i,j+1,N))/2))): fi: end: #Tria(N): the triangle with N Tria:=proc(N) local j,i1: [seq([seq(CR(i1,j-i1,N),i1=0..j)],j=0..N)]: end: #TriaH(N): the triangle with N TriaH:=proc(N) local j,i1: [seq([seq(CRh(i1,j-i1,N),i1=0..j)],j=0..N)]: end: #CutOff1(L): the largest j such that CR(i,j,nops(L)-1) d CutOff1:=proc(L) local m,i: m:=nops(L)-1: if m=0 then RETURN(0): fi: for i from 1 while L[i]<>(i-1)/m do od: i-1: end: CutOff:=proc(N) local gu,i: gu:=Tria(N): [seq(CutOff1(gu[i]),i=1..nops(gu))]: end: #CutOffU(M,L1,L2): the first M terms of the ultimate cutoffs #Cutoff(infinity) CutOffU:=proc(M,L1,L2) local gu,i,j: for i from 2*M while nops({seq([op(1..M+1,CutOff(i+j))],j=0..L1)})<>1 do od: gu:=[op(1..M+1,CutOff(i+L1))]: if nops({seq([op(1..M+1,CutOff(i+j))],j=0..L2)})<>1 then RETURN(FAIL): else RETURN(gu): fi: end: #CRh(i,j,N): backwards induction for the honest #version of the coin-tossing game #when you have to quit after N steps with #H/N CRh:=proc(i,j,N) option remember: if i+j>N then RETURN(FAIL): fi: if i+j=N then RETURN(i/N): elif i+j>0 then RETURN(max( (CRh(i+1,j,N)+CRh(i,j+1,N))/2, i/(i+j) )): else RETURN(max( (CRh(i+1,j,N)+CRh(i,j+1,N))/2)): fi: end: #CRhFast(N,K1,K2) the table of CRh(i,j,N) only for i+j<=K CRhFast:=proc(N,K1,K2) local gu,k,i,mu: gu:=[seq(i/N,i=0..N)]: for k from N-1 by -1 to K1 do gu:=[seq(max( (gu[i]+gu[i+1])/2 ,(i-1)/k),i=1..nops(gu)-1)]: od: mu:=[gu]: for k from K1-1 by -1 to max(1,K2) do gu:=[seq(max( (gu[i]+gu[i+1])/2 ,(i-1)/k),i=1..nops(gu)-1)]: mu:=[op(mu),gu]: od: if K2=0 then gu:=[seq(max( (gu[i]+gu[i+1])/2),i=1..nops(gu)-1)]: mu:=[op(mu),gu]: fi: mu: end: #CRFast(N,K1,K2) the table of CR(i,j,N) only for i+j<=K CRFast:=proc(N,K1,K2) local gu,k,i,mu: option remember: gu:=[seq(max(1/2,i/N),i=0..N)]: for k from N-1 by -1 to K1 do gu:=[seq(max( (gu[i]+gu[i+1])/2 ,(i-1)/k),i=1..nops(gu)-1)]: od: mu:=[gu]: for k from K1-1 by -1 to max(1,K2) do gu:=[seq(max( (gu[i]+gu[i+1])/2 ,(i-1)/k),i=1..nops(gu)-1)]: mu:=[op(mu),gu]: od: if K2=0 then gu:=[seq(max( (gu[i]+gu[i+1])/2),i=1..nops(gu)-1)]: mu:=[op(mu),gu]: fi: mu: end: #CRFastFloat(N,K1,K2) the table of CR(i,j,N) only for i+j<=K #in Floating-point CRFastFloat:=proc(N,K1,K2) local gu,k,i,mu: option remember: gu:=evalf([seq(max(.5,i/N),i=0..N)]): for k from N-1 by -1 to K1 do gu:=evalf([seq(max( (gu[i]+gu[i+1])/2. ,(i-1)/k),i=1..nops(gu)-1)]): od: mu:=[gu]: for k from K1-1 by -1 to max(1,K2) do gu:=evalf([seq(max( (gu[i]+gu[i+1])/2 ,(i-1)/k),i=1..nops(gu)-1)]): mu:=[op(mu),gu]: od: if K2=0 then gu:=evalf([seq(max( (gu[i]+gu[i+1])/2),i=1..nops(gu)-1)]): mu:=[op(mu),gu]: fi: mu: end: #CutOffFast(N): Like CutOff(N): CutOffFast:=proc(N) local gu,k,i,mu: gu:=[seq(max(1/2,i/N),i=0..N)]: mu:=[CutOff1(gu)]: for k from N-1 by -1 to 1 do gu:=[seq(max( (gu[i]+gu[i+1])/2 ,(i-1)/k),i=1..nops(gu)-1)]: mu:=[op(mu),CutOff1(gu)]: od: gu:=[seq(max( (gu[i]+gu[i+1])/2),i=1..nops(gu)-1)]: mu:=[op(mu),CutOff1(gu)]: [seq(mu[nops(mu)-i+1],i=1..nops(mu))]: end: #Pd(i,j,N,t): the probability distribution (in terms of a g.f. in t) #if you quit after N throws, and right now you have i Heads and j Tails Pd:=proc(i,j,N,t) option remember: if i+j=N then RETURN(t^CR(i,j,N)): fi: if i+j=0 then RETURN( (Pd(i+1,j,N,t)+Pd(i,j+1,N,t))/2): fi: if CR(i,j,N)=i/(i+j) then RETURN(t^(i/(i+j))): else RETURN( (Pd(i+1,j,N,t)+Pd(i,j+1,N,t))/2): fi: end: #Moments(i,j,N,M): the expectation, variance, and #list of normalized moments,up to the Mth. #for coin-tossing if you have i Heads and j Tails Moments:=proc(i,j,N,M) local gu,f,t,av,va,i1: f:=Pd(i,j,N,t): av:=CR(i,j,N): gu:=[av]: f:=f/t^av: f:=t*diff(f,t): f:=t*diff(f,t): va:=subs(t=1,f): if va=0 then RETURN([av,0$(M-1)]): fi: gu:=[op(gu),va]: for i1 from 1 to M-2 do f:=t*diff(f,t): gu:=[op(gu),evalf(subs(t=1,f)/va^((i1+2)/2))]: od: gu: end: #Tran(i,j,N): the smallest number of coin-tosses such that #i Heads and j Tails starts to be a GO <=N. If with N it is a stop #it returns FAIL Tran:=proc(i,j,N) local M: for M from i+j to N while CRm(i,j,M)=i/(i+j) do od: if M=N+1 then RETURN(FAIL): else RETURN(M): fi: end: #PolToPd(P,t): Given a polynomial P(t) translates it to a discrete #prob. distibution. For example, try: PolToPd((t^(1/2)+t^(2/3))/2,t); PolToPd:=proc(P,t) local P1,i,mu,ev,po,c,T: P1:=expand(P): mu:=[]: for i from 1 to nops(P1) do ev:=op(i,P1): c:=subs(t=1,ev): po:=subs(t=1,normal(diff(ev,t)/ev)): mu:=[op(mu),po]: T[po]:=c: od: mu:=sort(mu): [seq([mu[i],T[mu[i]]],i=1..nops(mu))]: end: #PolToCd(P,t): Given a polynomial P(t) translates it to a #com. discrete #prob. distibution. For example, try: PolToPd((t^(1/2)+t^(2/3))/2,t); PolToCd:=proc(P,t) local gu,i,j: gu:=PolToPd(P,t): [seq([gu[i][1], add(gu[j][2],j=1..i)],i=1..nops(gu))]: end: #CRp(i,j,N,g): backwards induction for the coin-tossing game #when you have to quit after N steps and your criterion is #to maximize your chances of getting at least g CRp:=proc(i,j,N,g) local gu1,gu2: option remember: if g<=1/2 then print(`g must be bigger than 1/2 `): fi: if i+j>N then RETURN(FAIL): fi: if i+j=N then if i/N>=g then RETURN([1,i/N]): else RETURN([0,max(1/2,i/N)]): fi: elif i+j>0 then if i/(i+j)>=g then RETURN([1,i/(i+j)]): else gu1:=CRp(i+1,j,N,g): gu2:=CRp(i,j+1,N,g): RETURN([(gu1[1]+gu2[1])/2,(gu1[2]+gu2[2])/2] ): fi: elif i+j=0 then gu1:=CRp(i+1,j,N,g): gu2:=CRp(i,j+1,N,g): RETURN([(gu1[1]+gu2[1])/2,(gu1[2]+gu2[2])/2] ): else ERROR(`Something is wrong`): fi: end: #TranH(i,j,N): the smallest number of coin-tosses such that #i Heads and j Tails starts to be a GO <=N. If with N it is a stop #it returns FAIL TranH:=proc(i,j,N) local M: for M from i+j to N while CRh(i,j,M)=i/(i+j) do od: if M=N+1 then RETURN(FAIL): else RETURN(M): fi: end: CRm:=proc(i,j,N) option remember: if i+j>0 then CRFast(N,i+j,i+j)[1][i+1] else (CRm(0,1,N)+CRm(1,0,N))/2: fi: end: CRmFloat:=proc(i,j,N) option remember: CRFastFloat(N,i+j,i+j)[1][i+1] end: CRmH:=proc(i,j,N): CRhFast(N,i+j,i+j)[1][i+1] end: #IsStop(i,j,N): is (i,j) stop? IsStop:=proc(i,j,N) evalb(CRm(i,j,N)=i/(i+j)): end: #TriaS(N,S): the triangle with N TriaS:=proc(N,S) local j,i1,gu,gu1: gu:=[]: for j from 1 to N do gu1:=[]: for i1 from 0 to j do if IsStop(i1,j-i1,N) then gu1:=[op(gu1),S]: else gu1:=[op(gu1), CR(i1,j-i1,N)]: fi: od: gu:=[op(gu),gu1]: od: gu: end: #GuessRat1(gu,L,n,d): given a list gu #gueses a rational function R(n) of degree <=d , such that gu[i]=R(i) #for i>=L #For example, try: GuessRat1([seq(i/(i+1),i=1..20)],3,n,1); GuessRat1:=proc(gu,L,n,d) local eq,var,a,i,b,R: if nops(gu)-L<=2*d+2+5 then print(`make list bigger`): FAIL: fi: var:={seq(a[i],i=0..d-1), seq(b[i],i=0..d)}: R:=add(a[i]*n^i,i=0..d)/add(b[i]*n^i,i=0..d): R:=subs(a[d]=1,R): eq:={ seq(subs(n=i,R)-gu[i],i=L..nops(gu))}: var:=solve(eq,var): if var=NULL then RETURN(FAIL): fi: normal(subs(var,R)): end: #GuessRat(gu,L,n): given a list gu #gueses a rational function R(n) of degree <=d , such that gu[i]=R(i) #for i>=L #For example, try: GuessRat([seq(i/(i+1),i=1..20)],3,n); GuessRat:=proc(gu,L,n) local R,d: for d from 1 to (nops(gu)-L-7)/2 do R:=GuessRat1(gu,L,n,d): if R<>FAIL then RETURN(R): fi: od: FAIL: end: #GuessAB(N,A,B,K): guesses a rational function for CR(N-A,N-B,2*N) #for numeric A and B and symbolic N, (K is the size of thedata set) #nd the place where #it starts to apply #For example, try: #GuessAB(N,1,1,20); GuessAB:=proc(N,A,B,K) local gu,C,R,i,N1: C:=max(A,B): gu:=[seq(CRm(N1-A,N1-B,2*N1),N1=C+3..C+K)]: R:=GuessRat(gu,K/2,N): if R=FAIL then RETURN(FAIL): fi: R:=normal(subs(N=N-C-2,R)): for i from C+K/2 by -1 to C while subs(N=i,R)=CRm(i-A,i-B,2*i) do od: RETURN(R,i): end: #BetaSeq(N,m) the sequence of beta(N,n) the #for n=1...m of the #sequence such that you should stop as soon #as you reach an n such that # #Heads-#Tails is>=beta(N,n) #if you are allowed N coin-tosses. #For example, try: BetaSeq(1000,10); BetaSeq:=proc(N,m) local gu,k,i,j,T: if m>=N then ERROR(`Second argument must be strictly smaller than first argument`): fi: gu:=[seq(max(1/2,i/N),i=0..N)]: for k from N-1 by -1 to m+1 do gu:=[seq(max( (gu[i]+gu[i+1])/2 ,(i-1)/k),i=1..nops(gu)-1)]: od: for k from m by -1 to 1 do gu:=[seq(max( (gu[i]+gu[i+1])/2 ,(i-1)/k),i=1..nops(gu)-1)]: for j from 0 to nops(gu)-1 while gu[j+1]<>j/k do od: T[k]:=j: od: [seq(2*T[j]-j,j=1..m)]: end: #BetaSeqFloat(N,m) the sequence of beta(N,n) the #like BetaSeq(N,m) but using floating point #For example, try: BetaSeqFloat(1000,10); BetaSeqFloat:=proc(N,m) local gu,k,i,j,T: gu:=[seq(max(.5,evalf(i/N)),i=0..N)]: for k from N-1 by -1 to m+1 do gu:=[seq(max( (gu[i]+gu[i+1])/2. ,evalf((i-1)/k)),i=1..nops(gu)-1)]: od: for k from m by -1 to 1 do gu:=[seq(max( (gu[i]+gu[i+1])/2. ,evalf((i-1)/k)),i=1..nops(gu)-1)]: for j from 0 to nops(gu)-1 while abs(gu[j+1]-evalf(j/k))>10^(-Digits+4) do od: T[k]:=j: od: [seq(2*T[j]-j,j=1..m)]: end: #TurningPoint(i,j,N0): The first N<=N0 (if it exists) #such that i Heads and j Tails starts being GO rather #than Stop. For example, try: #TurningPoint(2,1,100); TurningPoint:=proc(i,j,N0) local N: for N from i+j+1 to N0 while CR(i,j,N)=i/(i+j) do od: N: end: #CutOffs(N,m) the sequence of cutsoffs (h,t) with h+t<=m #for each h+t=k (k<=m), and the first N1 where it is a GO #with life-span N #For example, try: CutOffs(1000,10); CutOffs:=proc(N,m) local gu,k,i,j,aluf,mu: gu:=[seq(max(1/2,i/N),i=0..N)]: mu:=[]: for k from N-1 by -1 to m+1 do gu:=[seq(max( (gu[i]+gu[i+1])/2 ,(i-1)/k),i=1..nops(gu)-1)]: od: for k from m by -1 to 1 do gu:=[seq(max( (gu[i]+gu[i+1])/2 ,(i-1)/k),i=1..nops(gu)-1)]: for j from 0 to nops(gu)-1 while gu[j+1]<>j/k do od: aluf:=[j-1,k-j+1]: mu:=[op(mu),[aluf,TurningPoint(j-1,k-j+1,N)]]: od: [seq(mu[nops(mu)-i+1],i=1..nops(mu))]: end: #TurningPointM(i,j,N0): The first N<=N0 (if it exists) #such that i Heads and j Tails starts being GO rather #than Stop. For example, try: #TurningPointM(2,1,100); TurningPointM:=proc(i,j,N0) local N: for N from i+j+1 to N0 while CRm(i,j,N)=i/(i+j) do od: N: end: #CutOffsM(N,m) the sequence of cutsoffs (h,t) with h+t<=m #for each h+t=k (k<=m), and the first N1 where it is a GO #with life-span N #For example, try: CutOffs(1000,10); CutOffsM:=proc(N,m) local gu,k,i,j,aluf,mu: gu:=[seq(max(1/2,i/N),i=0..N)]: mu:=[]: for k from N-1 by -1 to m+1 do gu:=[seq(max( (gu[i]+gu[i+1])/2 ,(i-1)/k),i=1..nops(gu)-1)]: od: for k from m by -1 to 1 do gu:=[seq(max( (gu[i]+gu[i+1])/2 ,(i-1)/k),i=1..nops(gu)-1)]: for j from 0 to nops(gu)-1 while gu[j+1]<>j/k do od: aluf:=[j-1,k-j+1]: mu:=[op(mu),[aluf,TurningPointM(j-1,k-j+1,N)]]: od: [seq(mu[nops(mu)-i+1],i=1..nops(mu))]: end: Beta10000:=proc(): [1, 2, 3, 2, 3, 2, 3, 2, 3, 4, 3, 4, 3, 4, 3, 4, 5, 4, 5, 4, 5, 4, 5, 4, 5, 4, 5, 4, 5, 6, 5, 6, 5, 6, 5, 6, 5, 6, 5, 6, 5, 6, 7, 6, 7, 6, 7, 6, 7, 6]: end: Beta50000:=proc(): [1, 2, 3, 2, 3, 2, 3, 2, 3, 4, 3, 4, 3, 4, 3, 4, 5, 4, 5, 4, 5, 4, 5, 4, 5, 4, 5, 4, 5, 6, 5, 6, 5, 6, 5, 6, 5, 6, 5, 6, 5, 6, 7, 6, 7, 6, 7, 6, 7, 6, 7, 6, 7, 6, 7, 6, 7, 6, 7, 8, 7, 8, 7, 8, 7, 8, 7, 8, 7, 8, 7, 8, 7, 8, 7, 8, 7, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 10, 9, 10, 9, 10, 9, 10, 9, 10, 9, 10, 9, 10, 9, 10, 9, 10, 9, 10, 9, 10, 9, 10, 9, 10, 9, 10, 11, 10, 11, 10, 11, 10, 11, 10, 11, 10, 11, 10, 11, 10, 11, 10, 11, 10, 11, 10, 11, 10, 11, 10, 11, 10, 11, 12, 11, 12, 11, 12, 11, 12, 11, 12, 11, 12, 11, 12, 11, 12, 11, 12, 11, 12, 11, 12, 11, 12, 11, 12, 11, 12, 11, 12, 11, 12]: end: #CutOffs2000(): The sequence of size 100 whose i-th entry #is the pair [[h,t],HowOld] where [h,t] is the position with #smallest h such that h+t=i and for N=20000 it is a GO position #(so it is definitely a GO position for N=infinity, but there #is a (very slight) chance that [h+1,i-h-1] is also a GO position #for N=infinity (but for N=2000, it is definitly a STOP) #HowOld is the first N such that for N=HowOld it is GO #but for N1 then ERROR(`Not prob. dist.`): fi: subs(t=1,diff(F,t)): end: #Sd(F,t): The standard deviation # of the prob. dist. given by the p.g.f. F(t) #For example try Sd((1+t)/2,t); Sd:=proc(F,t): if subs(t=1,F)<>1 then ERROR(`Not prob. dist.`): fi: sqrt(subs(t=1,diff(F,t$2))+Av(F,t)-Av(F,t)^2): end: #Mom(F,t,i): the i-th moment of the prob. dist. given by #the prob. gen. fun. F(t). #For example try Mom((1+t)/2,t,5); Mom:=proc(F,t,i) local gu,i1: if subs(t=1,F)<>1 then ERROR(`Not prob. dist.`): fi: gu:=F/t^Av(F,t): for i1 from 1 to i do gu:=expand(t*diff(gu,t)): od: subs(t=1,gu): end: #CRt(i,j,N,t): backwards induction for the coin-tossing game #when you have to quit after N steps, also gives the #prob. dist. CRt:=proc(i,j,N,t) option remember: if i+j>N then RETURN(FAIL): fi: if i+j=N then RETURN([max(1/2,i/N), t^max(1/2,i/N)]): elif i+j>0 then if (CRt(i+1,j,N,t)[1]+CRt(i,j+1,N,t)[1])/2 >i/(i+j) then RETURN([(CRt(i+1,j,N,t)[1]+CRt(i,j+1,N,t)[1])/2, expand((CRt(i+1,j,N,t)[2]+CRt(i,j+1,N,t)[2])/2)]): else RETURN([i/(i+j),t^(i/(i+j))]): fi: else RETURN( [(CRt(1,0,N,t)[1]+CRt(0,1,N,t)[1])/2, expand((CRt(1,0,N,t)[2]+CRt(0,1,N,t)[2])/2)] ): fi: end: #CRtFast(N,K1,K2,t) the table of CRt(i,j,N,t) only for i+j<=K CRtFast:=proc(N,K1,K2,t) local gu,k,i,mu,lu: option remember: gu:=[seq([max(1/2,i/N),t^max(1/2,i/N)],i=0..N)]: for k from N-1 by -1 to K1 do lu:=[]: for i from 1 to nops(gu)-1 do if (gu[i][1]+gu[i+1][1])/2>(i-1)/k then lu:=[op(lu),[(gu[i][1]+gu[i+1][1])/2,(gu[i][2]+gu[i+1][2])/2]]: else lu:=[op(lu),[(i-1)/k,t^((i-1)/k)] ]: fi od: gu:=lu: od: mu:=[gu]: for k from K1-1 by -1 to max(1,K2) do lu:=[]: for i from 1 to nops(gu)-1 do if (gu[i][1]+gu[i+1][1])/2>(i-1)/k then lu:=[op(lu),[(gu[i][1]+gu[i+1][1])/2,(gu[i][2]+gu[i+1][2])/2]]: else lu:=[op(lu),[(i-1)/k,t^((i-1)/k)] ]: fi: od: gu:=lu: mu:=[op(mu),gu]: od: if K2=0 then gu:=[seq( [(gu[i][1]+gu[i+1][1])/2,(gu[i][2]+gu[i+1][2])/2], i=1..nops(gu)-1 )]: mu:=[op(mu),gu]: fi: mu: end: CRtm:=proc(i,j,N,t) option remember: if i+j>0 then CRtFast(N,i+j,i+j,t)[1][i+1] else [(CRtm(0,1,N,t)[1]+CRtm(1,0,N,t)[1])/2,(CRtm(0,1,N,t)[2]+CRtm(1,0,N,t)[2])/2]: fi: end: #PrExc(F,t,g): Given a prob. gen. function F of t #finds the probability of getting >=g. For example, try #PrExc((1+t+t^2)/3,t,1); PrExc:=proc(F,t,g) local F1,gu,i,F11,c1,c2: F1:=expand(F): if type(F1,`^`) then F11:=op(2,F1): if F11>=g then RETURN(1): else RETURN(0): fi: fi: if not type(F1,`+`) then RETURN(FAIL): fi: gu:=0: for i from 1 to nops(F1) do F11:=op(i,F1): if not (type(F11,`*`) or type(F11,numeric)) then RETURN(FAIL): fi: if not type(F11,numeric) then c1:=op(1,F11): c2:=op(2,F11): if not type(c1,numeric) then RETURN(FAIL): fi: if type(c2,`^`) then if op(2,c2)>=g then gu:=gu+c1: fi: elif c2=t then gu:=gu+c1: else RETURN(FAIL): fi: fi: od: gu: end: ####End general prob. dist. ####Begin goal-oriented #CRg(i,j,N,g): backwards induction for the coin-tossing game #with maximizing your chances to exceed g #when you have to quit after N steps CRg:=proc(i,j,N,g) option remember: if g<=1/2 then print(`The last argument must be> 1/2 `): RETURN(FAIL): fi: if i=0 and j=0 then RETURN((CRg(i+1,j,N,g)+ CRg(i,j+1,N,g))/2): fi: if i+j>N then RETURN(FAIL): fi: if i+j=N then if i/N>=g then RETURN(1): else RETURN(0): fi: else if i/(i+j)>=g then RETURN(1): else RETURN((CRg(i+1,j,N,g)+ CRg(i,j+1,N,g))/2): fi: fi: end: ####Begin goal-oriented #CRgt(i,j,N,g,t): backwards induction for the coin-tossing game #with maximizing your chances to exceed g #also returns the prob. gen. fun. #when you have to quit after N steps CRgt:=proc(i,j,N,g,t) local gu1,gu2: option remember: if g<=1/2 then print(`The last argument must be> 1/2 `): RETURN(FAIL): fi: if i+j>N then RETURN(FAIL): fi: if i+j=0 then gu1:=CRgt(1,0,N,g,t): gu2:=CRgt(0,1,N,g,t): RETURN([(gu1[1]+gu2[1])/2,(gu1[2]+gu2[2])/2]): fi: if i+j=N then if i/N>=g then RETURN([1,t^(i/N)]): else RETURN([0,1]): fi: else if i/(i+j)>=g then RETURN([1,t^(i/(i+j))]): else gu1:=CRgt(i+1,j,N,g,t): gu2:=CRgt(i,j+1,N,g,t): RETURN([(gu1[1]+gu2[1])/2, (gu1[2]+gu2[2])/2]): fi: fi: end: #ComparativeGambling(h,t,N,g): compares #the the max. expectation and the Goal-oriented #approaches to gambling if you have h heads and #t tails, with longevity N and goal g #For example, try: #ComparativeGambling(2,1,200,3/4); ComparativeGambling:=proc(i,j,N,g) local t,gu1,gu2: if i>0 and j=0 then print(`Of course you should quit!`): print(`ExpectedGain (FirstWay):1`, `ExpectedGain (SecondWay):1`): print(`Prob.Exceeding Goal(MaxExp): 1`,`Prob.Exc.Goal(ExcGoal):1`): RETURN(): fi: if g<=1/2 then print(`Last argument must be>1/2 `): RETURN(FAIL): fi: gu1:=CRt(i,j,N,t): gu2:=CRgt(i,j,N,g,t): print (`ExpectedGain (FirstWay):`, evalf(gu1[1]), `ExpectedGain (SecondWay):`,evalf(Av(gu2[2],t))): print(`Prob.Exceeding Goal(FirstWay):`, evalf(PrExc(gu1[2],t,g)), `Prob.Exc.Goal(SecondWay):`, evalf(gu2[1]) ): end: ####End goal-oriented ### strart stories #Sipur(N,m,r): All the info about expected gain #for positions with i+j<=m living up to N tosses #with resolution r for prob. #For example, try: #Sipur(200,3,.1); Sipur:=proc(N,m,r) local t,i,k,S,gu,h,t0: t0:=time(): S:=BetaSeq(N,m): print(`This is the story of expected gain, and stat. information`): print(`for the Chow-Robbins coin-tossing game with life duration`, N): print(`for the first`, m, `tosses `): print(`with prob. of getting at least a certain amount with resolion`, r): gu:=CRtm(0,0,N,t): print(`The expected gain at the very beginning is`, evalf(gu[1])): print(`The standard deviation is`, evalf(Sd(gu[2],t))): print(`The prob. of getting at least`, .5+r*i, ` for i from 1 to`, trunc(.5/r)): print(`are: `): print( evalf([seq([.5+r*i, PrExc(gu[2],t,.5+r*i)],i=1..trunc(.5/r))])): for k from 1 to m do print(`If the total number of tosses is`, k, `then whenever the`): print(`number of heads minus the number of tails is >=`, S[k] ): print(`in other words, the number of heads is >=`, (S[k]+k)/2 ): print(`it is a stop, and you collect for sure h/(h+t) `): print(`for the remaining case we have`): for h from 0 to (S[k]+k)/2-1 do gu:=CRtm(h,k-h,N,t): print(`The expected gain with`,h, `heads and `, k-h, `tails is`, evalf(gu[1])): print(`The standard deviation is`, evalf(Sd(gu[2],t))): print(`The prob. of getting at least .5+r*i, for i from 1 to`, trunc(.5/r)): print(`are: `): print( evalf([seq([.5+r*i, PrExc(gu[2],t,.5+r*i)],i=1..trunc(.5/r))])): od: od: print(`The whole thing took`, time()-t0, `secs. of CPU time `): end: #SipurCG(N,m,r): All the info about comparative gambling with #various goals #for positions with i+j<=m living up to N tosses #with resolution r for prob. #For example, try: #SipurCG(200,3,.1); SipurCG:=proc(N,m,r) local k,h,t0,i1,g: t0:=time(): print(`This is a comparative study of two gambling methodologies`): print(`for playing the Chow-Robbins Coin-Tossing game,`): print(`where you toss a fair coin, and you are allowed to stop any time`): print(`collecting, as payoff, the average number of heads.`): print(``): print(`The first way is the usual one, maximizing the expected gain.`): print(`The second way is that you have to match or exceed a certain`): print(` goal, and wishes to maximize the prob. of making it.`): print(`(e.g. if you need a certain score to get admitted to your college`): print(`of choice, and you need your SAT score to be at least 1500,`): print(`or you want to buy something`): print(`that costs a certain amount, and if you get one penny less`): print(`, you can't.)`): print(``): print(`Below is the comparative study for the first`, m, `tosses `): print(`where we can only toss the coin up to`, N, `times `): print(`(if we make it so far, we collect 1/2 if the number of tails is `): print(`larger than the number of heads). `): print(`------------------------------------------`): print(`At the very beginning `): for i1 from 1 to trunc(.5/r) do g:=.5+r*i1: print(`if you want to exceed the goal of `, g): ComparativeGambling(0,0,N,g): od: print(`---------------`): for k from 1 to m do print(`If the total number of tosses so far is`, k, `then things are as follows.`): for h from 0 to k-1 do print(`----------------`): print(`If the number of heads is`, h, `and the number of tails is`, k-h): for i1 from 1 to trunc(.5/r) do g:=.5+r*i1: print(`if you want to exceed the goal of `, g): ComparativeGambling(h,k-h,N,g): od: od: od: print(`-------------------`): print(`-------------------`): print(`The whole thing took`, time()-t0, `secs. of CPU time `): end: #IsBoundaryPt(pt,N,beta): Is the point pt on #the boundary of the discrete region #(0<=i+j<=N, i-j<=beta[i+j]) #For example try: IsBoundaryPt([2,0],3,[1,2]); IsBoundaryPt:=proc(pt,N,beta) local i,j: i:=pt[1]: j:=pt[2]: if i+j=0 then RETURN(false): fi: if i+j=N then RETURN(true): fi: if i-j=beta[i+j] then RETURN(true): fi: false: end: #IsInteriorPt(pt,N,beta): Is the point pt in #the interior of the discrete region #(0<=i+j<=N, i-j<=beta[i+j]) #For example try: IsInteriorPt([2,0],3,[1,2]); IsInteriorPt:=proc(pt,N,beta) local i,j: i:=pt[1]: j:=pt[2]: if i+j=0 then RETURN(true): fi: if i<0 then RETURN(false): fi: if i+j=N then RETURN(false): fi: if i-j>=beta[i+j] then RETURN(false): fi: if i-jN-1 then ERROR(`Bad input`): fi: if not IsInteriorPt(pt1,N,beta) then ERROR(`Bad input`): fi: c:=pt2[1]:d:=pt2[2]: if pt2=pt1 then RETURN(1): fi: pt2a:=[c-1,d]:pt2b:=[c,d-1]: gu:=0: if IsInteriorPt(pt2a,N,beta) then gu:=gu+ W(pt1,pt2a,N,beta): fi: if IsInteriorPt(pt2b,N,beta) then gu:=gu+ W(pt1,pt2b,N,beta): fi: gu: end: #Bd(N,beta): the set of boundary points of the discrete region #{[i,j]; 0<=i,0<=j, i+j<=N, i-j<=beta[i+j]} . #For example, try: #Bd(4,[1,2,3]); Bd:=proc(N,beta) local gu,i,j,k,i1,j1: gu:=[]: for k from 1 to N-1 do i:=(k+beta[k])/2: j:=(k-beta[k])/2: if not ( type(i, integer) and type(j, integer) ) then ERROR(`Bad input `): fi: gu:=[op(gu),[i,j]]: od: i1:=gu[k-1][1]: [op(gu), seq([i1-j1,N-i1+j1],j1=0..i1)]: end: #PayOff(pt,N,beta): the pay-off, at point pt, with the boundary #given by N,beta. For example, try: #PayOff([0,0],5,[1,2,3,4]); PayOff:=proc(pt,N,beta) local gu,g: if nops(beta)<>N-1 then ERROR(`Bad input`): fi: gu:=Bd(N,beta): add(W(pt,g,N,beta)*max(1/2,g[1]/(g[1]+g[2]))/2^(g[1]+g[2]-pt[1]-pt[2]), g in gu): end: #CRpay(i,j,N): Same as CR(i,j,N) #using PayOff. #For example, try: #CRpay(0,0,10); CRpay:=proc(i,j,N) local b: b:=BetaSeq(N,N-1): if IsInteriorPt([i,j],N,b) then RETURN(PayOff([i,j],N,b)): else RETURN(max(1/2,i/(i+j))): fi: end: