Evolve 2012.01.28 Mark Spahn markspahn@verizon.net This program crudely simulates evolution by taking a target-string of characters, then producing successive generations of a string whose characters randomly vary until the character in a given position becomes the same as the corresponding character in the target-string, after which that character remains the same. How many generations does it take for the random string to “evolve” to become the target-string? Here we imagine an N-character string (such as the Gettysburg Address, for which N=1456) and N monkeys, each before a keyboard offering a selection of M characters. Each monkey repeatedly hits a key at random, and if he hits “his” target character, his choice of character is henceforth locked in. The monkeys keep going until, in K random guesses, the target string has been zeroed in on. Program:AMonkeys If 0:0rand ; if desired, use fixed sequence of random numbers FnOff ; turn off the graphing functions Yn “ABCDEFGHIJKLMNOPQRSTUVWXYZ .’:,-”Str0; A to Z, space, period, apostrophe, colon, hyphen length(Str0)M ; how many characters to randomly choose from AxesOff:ClrDraw “FOUR SCORE AND”Str1 ; set Str1 to the default target string If 0:Then Disp “INPUT TARGET STR” Disp “HIT 2ND ALPHA” Disp “END W/ <ENTER>” Input Str1 For(I,1,length(Str1)) If inString(Str0,sub(Str1,I,1))=0 Then Disp “BAD CHAR”,I,Str1 Stop End End End ; If desired, ; tell user how to input his own string, length(Str1)N For(I,1,N) Text(0,4(I-1),sub(Str1,I,1)) End 1D prgmRun ; length of the string (target string, evolving string) ; Show target string ; at top, each char in its 4-pixel-wide space ; and input a user-defined string: ; make sure that each char is in the alphabet in Str0 ; if not, start over ; End of If inString( ; End of For(I ; End of If 0/1:Then ; turn on the “Display” mode Given a random N-char target-string Str1, guess at it till you guess it all (in K guesses). A run is a guess-till-success sequence of string-guesses in which each character is guessed at randomly from an alphabet of M characters and any correctly guessed character is retained in all subsequent guesses. That is, in each string-guess, only the still-unguessed characters are guessed at. Program:Run “<theta>”Str2 ; set guess-string to N <theta>s (all wrong characters) For(I,2,N):Str2+“<theta>”Str2:End NU ; how many unmatched (unguessed) chars are left 0K ; how many string-guesses made Repeat U=0 1+KK For(I,1,N) If sub(Str2,I,1).ne.sub(Str1,I,1) ; if corresponding letters are different, Then sub(Str0,randInt(1,M),1)Str3 ; pick a random character Str3 If Str3=sub(Str1,I,1):U-1U ; if char was guessed right, decrement Unguessed count If I=1:Then ; put character Str3 into position I of string Str2 Str3+sub(Str2,2,N-1) Str2:Else If I=N:Then sub(Str2,1,N-1)+Str3Str2:Else sub(Str2,1,I-1)+Str3+sub(Str2,I+1,N-I) Str2 End ; End of If I=N:Then:..:Else End ; End of If I=1:Then:..:Else End ; End of If sub(Str2,I,1).ne.sub(Str1,I,1) End ; End of For(I If D:Then ; if “display” mode is turned on, K-1T ; K-th string should appear on line T = ((K-1) mod 9)+1 T-9int(T/9)+1T T+1I:If I>9:1I ; Erase the following line I (for easy-to-read spacing) 6TT:6II ; (each line is 6 pixels tall) For(J,0,4(N+5),4) ; erase N+5 chars (each 4 pixels wide) Text(I,J, “ ”) ; 4 spaces End For(I,1,N) ; show each char of Str2 on line T of screen Text(T,4(I-1),sub(Str2,I,1)) ; positioned in its 4-pixel-wide space End Text(T,4N,“ ”,K,“ ”,U, “ ”) ; 3 spaces, generation number K, 2 spaces, how many ; U unmatched chars left, 4 spaces to overwrite previous getKeyT:If T=103:Pause ; Pause if decimal-point key has been pressed End ; End of If D End ; End of Repeat U=0 Graphs the probability density function Y1(x) = (1 – q^x)^n – (1 – q^(x-1))^n for a specified m, n Program:BPrbCurv Prompt M,N ; hm chars in alphabet, length of target-string 1/MP ; prb that a random guess at a char will be correct 1-PQ ; prb of guessing a given char wrongly “(1-Q^X)^N-(1-Q^(X-1))^N”Y1 ; prb of guessing an N-char string in exactly X guesses 2Xres ; faster than Xres=1 (8 sec vs 27 sec), little degradation 0Ymin ; Y1(x) reaches its max at L. Find L, Ymax: If N=1:Then ; For N=1, a hand analysis say max Y1(x) is at 1L:P/QYmax ; x=0, where Y1(0)=P/Q Else Q^(1/(N-1))T ; Y1 reaches its maximum at this L; that’s where Y1’(x)=0, (log(1-T)-log(1-QT))/log(Q)+1L ; says a calculus analysis by hand Y1(L)Ymax End prgmSetAB ; Determine a suitable A=Xmin, B=Xmax for graphing AXmin:BXmax Xmax-XminV:prgmTickSize:TXscl ; set size of tick-marks on X- and Y-axes Ymax-YminV:prgmTickSize:TYscl FnOff ; turn functions off (don’t graph just yet) AxesOff:ClrDraw:AxesOn 4dim(L1) ; store values for .25, .50, .75, .99 temporarily in L1 Fill(0,L1) ; ensures real number is L1, even if held complex numbers .25S:prgmSplitAtS:CL1(1) .50S:prgmSplitAtS:CL1(2) .75S:prgmSplitAtS:CL1(3) .99S:prgmSplitAtS:CL1(4) 95-max(4+1+int(log(max({B,M,N})))),2+4(5+int(log(L1(dim(L1)))))) C ; set margin 0I Text(I,C,“A=”,A):6+II ; Display list of values Text(I,C,“.25:”,L1(1)):6+II Text(I,C,“ MX:”,L):6+II Text(I,C “.50:”,L1(2)):6+II Text(I,C “.75:”,L1(3)):6+II Text(I,C “.99:”,L1(4)):6+II Text(I,C, “B=”,B):6+II 95-4(3+int(log(max(M,N))))C ; set margin Text(I,C, “M=”,M):6+II Text(I,C, “N=”,N) FnOn 1:DispGraph ; turn on function Y1 and graph it For graphing assuming Xmin=Ymin=0, select a proper tick-mark size T for the X- or Y-axis, given maximum positive value V. Program:TickSize 10^(int(log(V)))T ; find correct power of 10 If V/T<2:T/5T ; if too few ticks, use smaller tick size If V/T<3:T/2T Given probability s, show a dotted line on the graph at k, where P{success within k guesses} = s. Program:SplitAtS log(1-N xsqrt S)/log(Q)C int(94(C-Xmin)/(Xmax-Xmin))J ; how far across the screen int(62-62(Y1(C)-Ymin)/(Ymax-Ymin))+1I ; show the dividing line as a dotted line If I>50:Return ; if too narrow to show dotted line, don’t 59T:Repeat T.le.I ; show dotted line in pixel column J Pxl-On(T,J) T-2T:End In drawing the curve Y1(x) from x=A to x=B, determine what A and B should be. The function’s maximum value is at x=L. Program:SetAB Ymax/100T ; target value T, 1/100 the maximum value 1A ; take A=1 if Y1(1).ge.T If Y1(1)<T:Then 1I:int(L)K ; Y1 increases from Y1(I)<T to Y1(K)>T Repeat K-I.le.1 ; move I and K together, bracketing target T int(I+K)/2) J ; set J to midpoint integer between I and K If Y1(J)>T:Then:JK:Else:JI:End End IA ; Y1(A) is near target value T End int(L)+1I:1E6K ; Y1 decreases from L to infinity Repeat K-I.le.1 ; squeeze I and K together around target value T int(I+K)/2)J If Y1(J)<T:Then:JK:Else:JI:End End KB ; Y1(B) is near the target value T End If 1:Return ; Done. But to ensure that the pixel distance between 1I:While A+47I<B:1+II:End ; successive integers is constant, adjust B so that A+47IB ; (B-A) is a multiple of 47 (half the pixels 0-94 on screen). Assuming that the routine GuessCrv has just been run, this routine makes multiple runs of guesses at an Ncharacter target-string randomly chosen from an alphabet of M characters, and makes a bar graph for K from A to B, of how many times the target-string was fully guessed in K characters. This bar graph (histogram) is superimposed on the curve giving the theoretical probability for each value K in the range. This routine is practical only for small M and N. For a good demonstration, run GuessCrv with M=2, N=3, and do R=200 runs. The histogram will be similar to the curve. Or try M=4, N=3, R=500, which will take about 17 minutes. Program:CBarGraf ; was: GetStats sub(“ABCDEFGHIJKLMNOPQRSTUVWXYZ .’:,-”,1,M)Str0 ; get M-character alphabet B-A+1dim(L1):Fill(0,L1) ; keep count in list L1, for K from A to B Input “HM RUNS=”,R ; how many runs to do in guessing at a target string DispGraph ; display the graph of the curve, then overwrite it Text(12,40,“R=”,R) ; how many runs will be made Text(18,40,“W=”,W) ; which-number run this is Text(24,40,“K=”,K) ; how many guesses it took to guess the target-string startTmrO ; Time how many seconds the R runs take 0D ; turn off “Display” mode (for the routine Run) For(W,1,R) “<theta>”Str1 ; set Str1 to an N-char random string of the first M letters For(I,1,N) sub(Str0,randInd(1,M),1)+Str1Str1 End sub(Str1,1,N) Str1 ; drop the <theta> from Str1 Text(0,C-4N-4,Str1) ; show the target string Str1 prgmRun Text(24,48,K,“ ”) ; show how many guesses this run took If K<A:AK ; increment the proper item in list L1 If K>B:BK K-A+1T 1+L1(T)L1(T) 61-L1(T)I ; turn on the proper pixel of the bar graph If I.ge.0:Pxl-On(I,int(94(K-A)/(B-A))) Text(18,48,W) ; how many runs have been completed so far If 0:Text(06,40,startTmr-O) ; if desired, how many seconds these W runs have taken End startTmr-OO ; how many seconds the R runs took For(J,40,63) ; erase 6 4-pixel-wide characters Text(00,J,“ ”) ; erase test string Text(18,J,“ ”) ; erase W line Text(24,J,“ ”) ; erase K line If 0:StorePic 1 ; if desired, store a picture of the resulting screen Given alphabet size M and target-string length N, for a given degree of certainty (probability S), compute how many string-guesses K are needed so that (1-q^k)^n = P{completely guessing the target-string in k or fewer guesses} = s. Solving for k, we get k = log(1 – n-th root of s)/log q, where q = 1-1/M. Program:HmSure ; how many guesses needed to be S sure of success Prompt M,N 1/MP:1-PQ While 1 Prompt S ln(1-N xSqrt S)/ln(Q)X ; real x for which f(x) = s, where f(x) := (1-q^x)^n Disp X int(X)K:Disp K+(1-Q^K)^N ; integer k.P{guessing the string in k guesses} 1+KK:Disp K+(1-Q^K)^N ; next integer (k+1).P{guessing the string in (k+1) guesses} End Example: For M=27, N=15, S=?.5 82.07610326 means f(82.0761032) = .5 82.49898073 means f(82) = .49898073, just under .5 83.51229367 means f(83) = .51229367, just over .5 S=?.95 150.5009374 means this is the real number x where f(x) = .95 (95% sure of success) 150.9490688 means that with 150 guesses, you are 94.90688% sure of success 151.9509112 means that with 151 guesses, you are 95.09112% sure of success Uses the algorithm given on page 320 of the Chemical Rubber Company (CRC) Handbook of Chemistry and Physics, 44th Edition, 1962-63, and explained at http://www.sosmath.com/algebra/factor/fac11/fac11.html . SSolve the cubic equation y^3 + py^2 + qy + r = 0 by reducing it to the equation x^3 + ax + b = 0 (where there is no x^2 term) by setting y = x – p/3 and taking a = (1/3)(3q – p^2), b = (1/27)(2p^3 – 9pq + 27r), then finding the three roots for x, and converting these roots back to y by y = x – p/3. Program:ACubic a+bi ; set to “complex number” mode (hit MODE, scroll) Prompt P,Q,R (3Q-P^2)/3A 2P^3/27+PQ/3+RB A^3/27+B^2/4D -B/2T 3Sqrt(T+Sqrt(D))F ; cube root of [–b/2 + sqrt(a^3/27+b^2/4)] 3Sqrt(T-Sqrt(D))G ; (for “cube root” 3Sqrt, hit MATH, 4) 3dim(L1) F+GL1(1) ; first root -.5(F+G)+.5sqrt(3)(F-G)iL1(2) ; second root -.5(F+G)-.5sqrt(3)(F-G)iL1(3) ; third root L1-P/3L1 ; convert x roots back into y roots If D.le.0:real(L1)L1 ; if all-real roots, convert complex numbers to reals Real ; restore Real mode; F, G, L1 might contain complex numbers