home *** CD-ROM | disk | FTP | other *** search
/ ProfitPress Mega CDROM2 …eeware (MSDOS)(1992)(Eng) / ProfitPress-MegaCDROM2.B6I / PROG / MISC / GENALG.ZIP / GENALG3.PAS < prev    next >
Encoding:
Pascal/Delphi Source File  |  1990-06-30  |  16.6 KB  |  691 lines

  1. {$R-}
  2. PROGRAM genetic_algorithm_demo_one_dimensional (input, output);
  3. {program to demonstrate the operation of a genetic algorithm.
  4. from randomly generated population of real numbers, attempts to find
  5. a number arbitrarily close to a goal real number.
  6.  
  7. Calling convention:
  8.  
  9. gademo <k> <g> <e> <m> <c> <t> <i>
  10.  
  11. OR
  12.  
  13. gademo
  14.  
  15. Calling without parameters, user will be prompted for values.
  16. k = carrying capacity, integer such that 1 <= k <= 1000
  17. g = goal value, and arbitrary real number
  18. e = error level, integer value, the larger the number, the less error is
  19.      tolerated
  20. m,c,t = real values between 0 and 1 which give the probability of the
  21.          normal operation occurring, where
  22.            m is the probability that mutation will not occur
  23.            c is the probability that crossover will occur and not inversion
  24.            t is the probability that transcription will not occur
  25. i is an integer iteration factor
  26.  
  27. }
  28.  
  29. {
  30.  
  31. Copyright 1990 by Wesley R. Elsberry.  All rights reserved.
  32.  
  33. Commercial use of this software is prohibited without written consent of
  34. the author.
  35.  
  36. For information, bug reports, and updates contact
  37.  
  38. Wesley R. Elsberry
  39. 528 Chambers Creek Drive South
  40. Everman, Texas 76140
  41. Telephone: (817) 551-7018 (Voice)
  42.  
  43. Another point of contact is:
  44.  
  45.   Central Neural System BBS
  46.   RBBS-Net 8:930/303
  47.   (817) 551-9363
  48.   9600 HST, 2400, 1200, and 300 Baud connects
  49.   8 data bits, no parity, 1 stop bit
  50.   C.N.S. features neural network discussion and simulation related file
  51.   downloads.  C.N.S. is the home of the Neural_Net Echo.  There are no
  52.   access fees charged for use of the C.N.S. BBS.
  53.  
  54. }
  55.  
  56.  
  57. USES DOS, CRT;
  58.  
  59. const
  60.   cr = ^M;
  61.   lf = ^J;
  62.  
  63. type
  64.   command_string_ = string[127];
  65.   param_array_ = array[1..9] of command_string_;
  66.   param_rec_ = record
  67.     k : integer;
  68.     g : real;
  69.     e : integer;
  70.     m : real;
  71.     c : real;
  72.     t : real;
  73.     i : integer;
  74.     end;
  75.  
  76. var
  77.   trr, tss : real;    {variables used in testing of the code}
  78.   tii, tjj : integer; {ditto}
  79.   tinch : char;
  80.   toutf : text;
  81.   paramstrings : param_array_;
  82.   params : param_rec_;
  83.  
  84. procedure wait;
  85. begin
  86.   tinch := readkey;
  87. end;
  88.  
  89. procedure demo;
  90. const
  91.   max_k = 999;
  92.   mach_inf = 1E37;
  93. (*  k = 49;                {carrying capacity - 1}
  94.   {smaller carrying capacity = faster generations}
  95.   goal = 3.141592653589793;       {the value to strive for}
  96.     {goal is arbitrary, change to whatever you like}
  97.   error_level = 4096;  {inverse of amount of error allowed in goal completion}
  98.   mutation_threshold = 0.7; {probability that chromosome will not undergo
  99.                               mutation}
  100.   cross2invers = 0.7;   {probability that reproduction method will be crossover
  101.                           as opposed to inversion}
  102.   transcribe = 0.7; {1 - probability that transcription occurs} *)
  103.   debug : boolean = FALSE;
  104.  
  105. type
  106.   byte_map_ = array[0..5] of byte;    {structure to allow bit manipulation of real}
  107.   population_ = array[0..max_k] of real;  {structure to hold the candidates}
  108.   out_rec_ = record
  109.     s : string[80];
  110.     end;
  111.  
  112. var
  113.   k : integer;
  114.   goal : real;
  115.   error_level : integer;
  116.   mutation_threshold : real;
  117.   cross2invers : real;
  118.   transcribe : real;
  119.   generation_number : integer; {count of generations}
  120.   max_generations : real; {frustration capacity}
  121.   pop : population_;           {current candidates}
  122.   sel_dist : array[0..max_k] of real;  {probability of each candidate to reproduce one time}
  123.   how_far : array[0..max_k] of real;   {distance of candidate from goal}
  124.   success, finish : boolean;
  125.   close_enough : real; {range about goal that fulfills the requirements}
  126.   ii, jj : integer;
  127.   how_close : real;
  128.   outf : text;
  129.   inch : char;
  130.   raoutf : file of out_rec_;
  131.   tstr1, tstr2 : out_rec_;
  132.   str1 : string[80];
  133.   fom : real;  {Figure Of Merit: Improvement over average random search}
  134.  
  135. procedure initialize;
  136. var ii, jj : integer;
  137.   rr, ss : real;
  138. begin
  139.   k := params.k - 1; {adjust for base zero}
  140.   goal := params.g;
  141.   error_level := params.e;
  142.   mutation_threshold := params.m;
  143.   cross2invers := params.c;
  144.   transcribe := params.t;
  145.  
  146.   generation_number := 1;
  147.   success := false;
  148.   close_enough := goal / error_level;
  149.   rr := error_level;
  150.   for jj := 1 to 9 do
  151.     rr := rr * 2;
  152.     {have to match sign and exponent bits as well}
  153.   max_generations := rr / (k+1) / 2.0;
  154.   writeln('Maximum # of generations = ',max_generations:8:3);
  155.   {k is base zero; average random search will find in n/2 experiments}
  156.   randomize;
  157. end;
  158.  
  159. procedure generate_starting_population; {got to start somewhere}
  160. var ii, jj, kk, ll : integer;
  161.   rr, ss : real;
  162. begin
  163.   for jj := 0 to k do {for each candidate}
  164.     begin  {value of candidate to be spread over several orders of magnitude}
  165.       kk := random(37);
  166.       rr := 1;
  167.       for ii := 1 to kk do
  168.         rr := rr * 10;
  169.       ll :=  random(2);
  170.       if ll = 0 then
  171.         ss := -1.0
  172.       else
  173.         ss := 1.0;
  174.       pop[jj] := random * rr * ss;
  175.     end;
  176. end;
  177.  
  178. function distance (spot : integer): real;
  179. var  ii : integer;
  180.   rr : real;
  181. begin
  182.   distance := abs(goal - pop[spot]);
  183. end;
  184.  
  185. function min_distance : real;
  186. var
  187.   ii : integer;
  188.   rr : real;
  189. begin
  190.   rr := mach_inf;
  191.   for ii := 0 to k do
  192.     begin
  193.       if how_far[ii] < rr then
  194.         rr := how_far[ii];
  195.     end;
  196.   min_distance := rr;
  197. end;
  198.  
  199. function done: boolean;
  200. begin
  201.   success := false;
  202.   done := false;
  203.   how_close := min_distance;
  204.   if how_close <= close_enough then
  205.     success := true;  {success!}
  206.   if (generation_number >= max_generations) then
  207.     done := true; {failure  :(  }
  208.   if success then done := true;
  209. end;
  210.  
  211. procedure generate_selectionist_distribution;
  212. var
  213.   sum_distance : real;
  214.   ii, jj : integer;
  215.   dist : real;
  216. begin
  217.   sum_distance := 0.0;
  218.   for ii := 0 to k do
  219.     begin
  220.       dist := ln(distance(ii));
  221.       sel_dist[ii] := 1- (1 /(1+exp(- dist)));
  222.       sum_distance := sum_distance +  sel_dist[ii];
  223.     end;
  224.   if debug then
  225.     writeln('Population:      Selectionist Distribution: ');
  226.   for ii := 0 to k do
  227.     begin
  228.       sel_dist[ii] := sel_dist[ii] / sum_distance;
  229.       if debug then
  230.         writeln(pop[ii]:12:6,'     ',sel_dist[ii]:12:6);
  231.     end;
  232.       if debug then
  233.         writeln;
  234. end;
  235.  
  236. procedure evaluate_population;
  237. var
  238.   ii : integer;
  239.   rr : real;
  240. begin
  241.   for ii := 0 to k do
  242.     begin
  243.       how_far[ii] := distance(ii);
  244.     end;
  245. end;
  246.  
  247. procedure generate_new_population;
  248. var
  249.   new_pop : population_;
  250.   ogive1, ogive2 : real;
  251.   ii, jj : integer;
  252.   p1, p2 : integer;
  253.   pr1, pr2 : real;
  254.   finished : boolean;
  255.  
  256. function find_parent(prob : real) : integer;
  257. var
  258.   ii : integer;
  259.   parent : integer;
  260.   so_far : real;
  261.   found : boolean;
  262. begin
  263.   so_far := 0.0;
  264.   found := false;
  265.   ii := 0;
  266.   while not found do
  267.     begin
  268.       so_far := so_far + sel_dist[ii];
  269.       if (prob <= so_far) then
  270.         begin
  271.           found := true;
  272.           parent := ii;
  273.         end;
  274.       ii := ii + 1;
  275.     end;
  276.   find_parent := parent;
  277. end;
  278.  
  279. function generate_offspring(par1, par2 : real): real;
  280. const
  281.   bits : array[0..7] of byte = (1,2,4,8,16,32,64,128);
  282.   bit7 = 128;
  283.   bit6 = 64;
  284.   bit5 = 32;
  285.   bit4 = 16;
  286.   bit3 = 8;
  287.   bit2 = 4;
  288.   bit1 = 2;
  289.   bit0 = 1;
  290. type
  291.   allele_ = 0..1;                       {will have binary values}
  292.   chromosome_ = array[0..47] of allele_;  {48 bit positions total}
  293. var
  294.   c1, c2, c3, cz : chromosome_;
  295.   rr : real;
  296.  
  297. procedure print_genotype(gene : chromosome_);
  298. var ii, jj : integer;
  299. begin
  300.  if FALSE then
  301.    begin
  302.   for ii := 0 to 47 do
  303.     begin
  304.       write(gene[ii]:1);
  305.     end;
  306.   writeln;
  307.    end;
  308. end;
  309.  
  310. procedure phenotype_to_genotype(parent : real; var gene : chromosome_);
  311. var
  312.   ii, gptr : integer;
  313.   b1 : byte_map_ absolute parent;
  314. begin
  315.   gptr := 0;
  316.   for ii := 0 to 5 do
  317.     begin
  318.  
  319.       if ((b1[ii] and bit7) >= 1) then
  320.         gene[gptr] := 1
  321.       else
  322.         gene[gptr] := 0;
  323.  
  324.       if ((b1[ii] and bit6) >= 1) then
  325.         gene[gptr+1] := 1
  326.       else
  327.         gene[gptr+1] := 0;
  328.  
  329.       if ((b1[ii] and bit5) >= 1) then
  330.         gene[gptr+2] := 1
  331.       else
  332.         gene[gptr+2] := 0;
  333.  
  334.       if ((b1[ii] and bit4) >= 1) then
  335.         gene[gptr+3] := 1
  336.       else
  337.         gene[gptr+3] := 0;
  338.  
  339.       if ((b1[ii] and bit3) >= 1) then
  340.         gene[gptr+4] := 1
  341.       else
  342.         gene[gptr+4] := 0;
  343.  
  344.       if ((b1[ii] and bit2) >= 1) then
  345.         gene[gptr+5] := 1
  346.       else
  347.         gene[gptr+5] := 0;
  348.  
  349.       if ((b1[ii] and bit1) >= 1) then
  350.         gene[gptr+6] := 1
  351.       else
  352.         gene[gptr+6] := 0;
  353.  
  354.       if ((b1[ii] and bit0) >= 1) then
  355.         gene[gptr+7] := 1
  356.       else
  357.         gene[gptr+7] := 0;
  358.  
  359.       gptr := gptr + 8;
  360.     end;
  361. end;
  362.  
  363. procedure genotype_to_phenotype(var parent : real; gene : chromosome_);
  364. var
  365.   bptr, gptr : integer;
  366.   br : real;
  367.   b1 : byte_map_ absolute br;
  368. begin
  369.   gptr := 0;
  370.   for bptr := 0 to 5 do
  371.     begin
  372.       b1[bptr] :=  (gene[gptr] * bit7) + (gene[gptr+1] * bit6) +
  373.                    (gene[gptr+2] * bit5) + (gene[gptr+3] * bit4) +
  374.                    (gene[gptr+4] * bit3) + (gene[gptr+5] * bit2) +
  375.                    (gene[gptr+6] * bit1) + (gene[gptr+7] * bit0);
  376.       gptr := gptr + 8;
  377.     end;
  378.   parent := br;
  379. end;
  380.  
  381. procedure crossover(gene1, gene2 : chromosome_; var zygote : chromosome_;
  382.                     start, length : integer);
  383. var
  384.   ii, split, jj : integer;
  385. begin
  386.   zygote := gene1;
  387.   for ii := start to (start + length) do
  388.     begin
  389.       jj := ii mod 48;
  390.       zygote [jj] := gene2 [jj];
  391.     end;
  392. end;
  393.  
  394. procedure inversion (gene1, gene2 : chromosome_; var zygote : chromosome_;
  395.                      start, length : integer);
  396. var
  397.   ii, split, jj, kk : integer;
  398. begin
  399.   zygote := gene1;
  400.   jj := length + 48;
  401.   for ii := start to (start + length) do
  402.     begin
  403.       zygote [jj mod 48] := gene2 [ii mod 48];
  404.       jj := jj - 1;
  405.     end;
  406. end;
  407.  
  408. procedure mutation (var gene1 : chromosome_; position : integer);
  409. var
  410.   ii : integer;
  411. begin
  412.   if gene1[position] > 0 then
  413.     gene1[position] := 0
  414.   else
  415.     gene1[position] := 1;
  416. end;
  417.  
  418. procedure transcription (gene1, gene2 : chromosome_; var zygote : chromosome_;
  419.                          start, length : integer);
  420. var
  421.   ii, jj : integer;
  422.   ctmp : chromosome_;
  423. begin
  424.   ii := random(48);
  425.   for jj := start to (start + length) do
  426.     begin
  427.       ctmp[jj mod 48] := gene2[ii mod 48];
  428.       ii := ii + 1;
  429.     end;
  430.   if random <= cross2invers then
  431.     crossover(gene1,ctmp,zygote,start,length)
  432.   else
  433.     inversion(gene1,ctmp,zygote,start,length);
  434. end;
  435.  
  436.  
  437. begin  {generate_offspring}
  438. {have not yet included transcription}
  439.   phenotype_to_genotype(par1,c1);
  440.   phenotype_to_genotype(par2,c2);
  441.   rr := random;
  442.   if (rr > mutation_threshold) then
  443.     mutation(c1,random(48));
  444.   rr := random;
  445.   if (rr > mutation_threshold) then
  446.     mutation(c2,random(48));
  447.   rr := random;
  448.   if (rr > transcribe) then
  449.     begin
  450.       phenotype_to_genotype(pop[random(k+1)],c3);
  451.       rr := random(2);
  452.       if (rr = 0) then
  453.         transcription(c1,c3,c1,random(48),random(24))
  454.       else
  455.         transcription(c2,c3,c2,random(48),random(24));
  456.     end;
  457.  
  458.   rr := random;
  459.   if (rr > cross2invers) then
  460.     begin
  461.       inversion(c1, c2, cz, (random(48)), (random(48)));
  462.     end
  463.   else
  464.     begin
  465.       crossover(c1, c2, cz, random(48), random(48));
  466.     end;
  467.  
  468.   print_genotype(c1);
  469.   print_genotype(c2);
  470.   print_genotype(cz);
  471.   genotype_to_phenotype(rr, cz);
  472.   generate_offspring := rr;
  473. end;
  474.  
  475.  
  476. begin  {generate_new_population}
  477. {  writeln('New population made by: ');}
  478.   for ii := 0 to k do
  479.     begin
  480.       finished := false;
  481.       jj := 0;
  482.       p1 := find_parent(random);
  483.       p2 := find_parent(random);
  484.       pr1 := pop[p1];
  485.       pr2 := pop[p2];
  486.       if debug then
  487.         write(pr1:8:5,' x ',pr2:8:5);
  488.       new_pop[ii] := generate_offspring(pr1,pr2);
  489.       if debug then
  490.         writeln(' = ',new_pop[ii]:8:5);
  491.     end;
  492.       if debug then
  493.         writeln;
  494.   pop := new_pop;
  495. end;
  496.  
  497. procedure report;
  498. {give out lines that indicate population distribution}
  499. var
  500.   ii, jj : integer;
  501.   ss : real;
  502.   fdist : array[-38..38] of integer;
  503.  
  504. function order_of_magnitude(rr : real): integer;
  505. const
  506.   ln2log = 0.4342944819;
  507. var ii : integer;
  508. begin
  509.   if (rr <= 0.0) then
  510.     ii := 0
  511.   else
  512.     ii := round(ln2log * ln(rr));
  513.   if ii < -38 then
  514.     ii := -38;
  515.   if ii > 38 then
  516.     ii := 38;
  517.   order_of_magnitude := ii;
  518. end;
  519.  
  520. function signum(rr : real): integer;
  521. begin
  522.   if (rr >= 0) then
  523.     signum := 1
  524.   else
  525.     signum := -1;
  526. end;
  527.  
  528.  
  529. begin {report}
  530.   fillchar(fdist,sizeof(fdist),0);
  531. (*  for ii := 0 to k do
  532.     begin
  533.       jj := signum(pop[ii])*order_of_magnitude(abs(pop[ii]));
  534.       writeln(jj);
  535.       fdist[jj] := fdist[jj] + 1;
  536.     end;  *)
  537.                              {
  538.   if  ((generation_number mod 10) = 0) then
  539.     writeln('Generation ',generation_number);}
  540.   for ii := -38 to 38 do
  541.     begin
  542.       if debug then
  543.         begin
  544.       if fdist[ii] < 1 then
  545.         write('_')
  546.       else
  547.       if fdist[ii] > 9 then
  548.         write('^')
  549.       else
  550.         write(fdist[ii]:1);
  551.         end;
  552.     end;
  553.       if debug then
  554.         begin
  555.   writeln;
  556.   writeln('0                                      E1                                  E38');
  557.   writeln;
  558.         end;
  559. end;
  560.  
  561. begin  {demo}
  562.   initialize;
  563.   generate_starting_population;
  564.   repeat
  565.       evaluate_population;
  566.       generate_selectionist_distribution;
  567.       finish := done;
  568.       if not finish then
  569.         begin
  570.           generate_new_population;
  571.           report;
  572.           writeln('Within ',(how_close/goal*100):8:5,
  573.                   '% of goal condition in generation ',generation_number);
  574.           generation_number := generation_number + 1;
  575.  
  576.         end;
  577.   until (finish);
  578.  
  579. {$I-}
  580.     assign(raoutf,'garesult.dat');
  581.     reset(raoutf);
  582.     CASE IORESULT OF
  583.       $02 :  BEGIN
  584.                ASSIGN(RAOUTF,'GARESULT.DAT');
  585.                REWRITE(RAOUTF);
  586.              END;
  587.     END;
  588. {$I+}
  589.     seek(raoutf,filesize(raoutf)); {go to end of file}
  590.     fillchar(tstr1,sizeof(tstr1),' ');
  591.  
  592.     fom := max_generations / generation_number;
  593.  
  594.     str((k+1),str1);
  595.     tstr1.s := 'K:' + str1;
  596.     str(goal:12:8,str1);
  597.     tstr1.s := tstr1.s + ' G:' + str1;
  598.     str(error_level,str1);
  599.     tstr1.s := tstr1.s + ' E:' + str1;
  600.     str(mutation_threshold:5:3,str1);
  601.     tstr1.s := tstr1.s + ' M:' + str1;
  602.     str(cross2invers:5:3,str1);
  603.     tstr1.s := tstr1.s + ' CI:' + str1;
  604.     str(transcribe:5:3,str1);
  605.     tstr1.s := tstr1.s + ' T:' + str1;
  606.     str(fom:8:3,str1);
  607.     tstr1.s := tstr1.s + ' FOM:' + str1;
  608.  
  609.     tstr1.s[79] := CR;
  610.     tstr1.s[80] := LF;
  611.  
  612.     write(raoutf,tstr1);
  613.     writeln(tstr1.s);
  614.     fillchar(tstr1,sizeof(tstr1),' ');
  615.  
  616.   if success then
  617.    begin
  618.     tstr1.s := 'Achieved goal in generation ';
  619.     str(generation_number:6,str1);
  620.     tstr1.s := tstr1.s + str1;
  621.     tstr1.s[79] := CR;
  622.     tstr1.s[80] := LF;
  623.     write(raoutf,tstr1);
  624.     writeln(tstr1.s);
  625.    end
  626.   else
  627.    begin
  628.     tstr1.s := 'No better than ave. random search ';
  629.     str(max_generations:16:0,str1);
  630.     tstr1.s := tstr1.s + str1;
  631.     write(raoutf,tstr1);
  632.     writeln(tstr1.s);
  633.    end;
  634.   close(raoutf);
  635. end;
  636.  
  637. begin {main}
  638.   if paramcount > 0 then
  639.     begin
  640.       with params do
  641.         begin
  642.           val(paramstr(1),k,tii);
  643.           val(paramstr(2),g,tii);
  644.           val(paramstr(3),e,tii);
  645.           val(paramstr(4),m,tii);
  646.           val(paramstr(5),c,tii);
  647.           val(paramstr(6),t,tii);
  648.           val(paramstr(7),i,tii);
  649.         end;
  650.     end
  651.   else
  652.     begin
  653.       with params do
  654.         begin
  655.           writeln;
  656.           repeat
  657.             write('Enter carrying capacity (1 <= k <= 1000) : ');
  658.             readln(k);
  659.           until (k >= 1) and (k <= 1000);
  660.           repeat
  661.             write('Enter goal value (real number) : ');
  662.             readln(g);
  663.           until true;
  664.           repeat
  665.             write('Enter error level (larger = less error) : ');
  666.             readln(e);
  667.           until (e > 0) and (e <= 32501);
  668.           repeat
  669.             write('Enter mutation threshold : ');
  670.             readln(m);
  671.           until (m > 0.0) and (m <= 1.0);
  672.           repeat
  673.             write('Enter crossover/inversion ratio : ');
  674.             readln(c);
  675.           until (c > 0.0) and (c <= 1.0);
  676.           repeat
  677.             write('Enter transcription threshold : ');
  678.             readln(t);
  679.           until (t > 0.0) and (t <= 1.0);
  680.           repeat
  681.             write('Enter number of experiments : ');
  682.             readln(i);
  683.           until (i > 0) and (i < 101);
  684.         end;
  685.     end;
  686.  
  687.    for tjj := 1 to params.i do
  688.      begin
  689.        demo;
  690.      end;
  691. end.