home *** CD-ROM | disk | FTP | other *** search
/ NetNews Usenet Archive 1992 #19 / NN_1992_19.iso / spool / comp / ai / 3269 < prev    next >
Encoding:
Text File  |  1992-08-30  |  10.0 KB  |  535 lines

  1. Newsgroups: comp.ai
  2. Path: sparky!uunet!van-bc!ubc-cs!news.UVic.CA!sol.UVic.CA!schumach
  3. From: schumach@sol.UVic.CA (Ian Schumacher)
  4. Subject: genetic algorithm example in c++
  5. Message-ID: <schumach.715219339@sol.UVic.CA>
  6. Sender: news@sol.UVic.CA
  7. Nntp-Posting-Host: sol.uvic.ca
  8. Organization: University of Victoria
  9. Distribution: all
  10. Date: 31 Aug 92 00:02:19 GMT
  11. Lines: 522
  12.  
  13.  
  14. I have seen a lot of interest in Gene algorithms these days.  I was
  15. pretty interested myself, so I threw together a Gene and Gene_Pool
  16. Class in C++.  Figured I'd send it out, so that anyone that was interested
  17. could have a example to work with, improve upon, whatever.
  18. Bugs?  You tell me.  It hasn't been very thoroughly tested, but there's
  19. not that much that could go wrong.  It's in three parts gene.h gene.m and
  20. imp.m.  Enjoy.
  21.  
  22. --------------------------------------------------------------------
  23.  
  24. // class gene.h: gene structure
  25. // Programmer : Ian Schumacher
  26. // Comments welcome
  27. // email: schumach@sol.UVic.CA
  28. // Genie : I.SCHUMACHER
  29.  
  30. class Gene
  31. {
  32.     unsigned short *gene;
  33.  
  34. protected:
  35.  
  36.     int length;
  37.     double mutate_rate;
  38.     double value;
  39.  
  40. public:
  41.     Gene(int);
  42.     Gene();
  43.     ~Gene();
  44.     Gene& operator+(Gene &);
  45.     unsigned short& operator[](int);
  46.     Gene& operator=(const Gene &);
  47.     Gene& operator=(const double);
  48.     Gene& mutate(void);
  49.     void set_rate(double);
  50.     int get_length(void);
  51.     double get_value(void) {return value;}
  52. };
  53.  
  54. class Gene_Pool
  55. {
  56.     int size;
  57.     int plength;
  58.     Gene *gene;
  59.     int *index;
  60.     
  61. public:
  62.     Gene_Pool(int number=1,int a=1);
  63.     ~Gene_Pool() {delete gene;delete index;}
  64.     Gene_Pool& operator+(Gene_Pool &);
  65.     Gene& operator[](int);
  66.     Gene_Pool& operator=(const Gene_Pool &);
  67.     Gene_Pool& mutate(void);
  68.     int get_size(void) { return size;}
  69.     int get_length(void) {return plength;}
  70.     Gene_Pool& evolve(void);
  71.     Gene_Pool& sort(void);
  72.     Gene_Pool& kill(int);
  73.     Gene_Pool& set_rate(double);
  74. };
  75.  
  76. ---------------------------------------------------------------------------
  77.  
  78. // gene.m : Definition of Gene and Gene_Pool functions
  79. // Programmer : Ian Schumacher
  80. // Comments welcome
  81. // email: schumach@sol.UVic.CA
  82. // Genie : I.SCHUMACHER
  83.  
  84. #include "gene.h"
  85. #include <stdio.h>
  86. #include <stdlib.h>
  87. #include <math.h>
  88.  
  89. #define RATE 0.01            // default mutation rate
  90. #define RAND_MATE 1        // mate randomly or in order switch
  91.  
  92. void indexx(int ,double *,int *);
  93. int irbit2(void);
  94.  
  95. int pop_length=1;        // gene population value set by Gene_Pool, used by Gene
  96. int iseed=-666;               // random generator seed
  97.  
  98. Gene::Gene(int n)
  99. {
  100.     int i;
  101.     
  102.     if(n>0)
  103.     {
  104.         gene=new unsigned short[n];
  105.         mutate_rate=RATE;
  106.         length=n;
  107.     }
  108.     else
  109.     {
  110.         gene=new unsigned short[1];
  111.         mutate_rate=RATE;
  112.         length=1;
  113.     }
  114.     
  115. // insert random values into gene
  116.     for(i=0;i<length;i++)
  117.         gene[i]=(unsigned short) irbit2();  // don't trust rand() that much, use "NR in C" function
  118. }
  119.  
  120. Gene::Gene()
  121. {
  122. // uses global variable pop_length set by Gene_Pool to determine gene size
  123.     int i;
  124.     
  125.     if(pop_length<1)
  126.         pop_length=1;
  127.     length=pop_length;
  128.     mutate_rate=0.01;
  129.     gene=new unsigned short[pop_length];
  130. // insert random values into gene
  131.     for(i=0;i<pop_length;i++)
  132.         gene[i]=(unsigned short) (irbit2());
  133. }
  134.  
  135. Gene::~Gene()
  136. {
  137.     delete gene;
  138. }
  139.  
  140. Gene& Gene::operator+(Gene &a)
  141. {
  142.     int cp,i;
  143.     int tmp;
  144.  
  145.     static Gene b(length);    //static because its adress is returned
  146.  
  147.     if(this==&a)
  148.         return *this;
  149.     if(length!=a.length)
  150.     {
  151.         printf("Currently cannot mate genes of different lengths. Genes unchanged\n");
  152.         return *this;
  153.     }
  154.     // mating routine
  155.     cp=int(rand()%length);   // Random cross point. I thought this would produce better result
  156.                         // constant half way cross point.
  157.     for(i=0;i<cp;i++)
  158.         b.gene[i]=this->gene[i];
  159.     for(i=cp;i<length;i++)
  160.         b.gene[i]=a.gene[i];
  161.     return b;
  162. }
  163.  
  164. unsigned short& Gene::operator[](int elem)
  165. // Returning address allows gene[j] to be on either side of equals sign
  166. {
  167.     static unsigned short tmp=0;
  168.     
  169.     if(elem>=0&&elem<length)
  170.         return gene[elem];
  171.     else
  172.     {
  173.         printf("Gene access error\n");
  174.         return tmp;
  175.     }
  176. }
  177.  
  178. Gene& Gene::operator=(const Gene& a)
  179. // set one gene equal to another
  180. {
  181.     int i;
  182.  
  183.     if(this==&a)
  184.         return *this;
  185.     length=a.length;
  186.     mutate_rate=a.mutate_rate;
  187.     value=a.value;
  188.     delete gene;
  189.     gene=new unsigned short[length];
  190.     for(i=0;i<length;i++)
  191.         gene[i]=a.gene[i];
  192.     return *this;
  193. }
  194.  
  195. Gene& Gene::operator=(const double x)
  196. // set gene value
  197. {
  198.     value=x;
  199.     return *this;
  200. }
  201.  
  202. Gene& Gene::mutate(void)
  203. {
  204.     int i;
  205.     
  206.     for(i=0;i<length;i++)
  207.     {
  208.         if(rand()/(RAND_MAX+1.0)<mutate_rate)
  209.         {
  210.             gene[i]=gene[i]<1 ? 1:0;
  211.         }
  212.     }
  213.     return *this;
  214. }
  215.  
  216. void Gene::set_rate(double r)
  217. {
  218.     if(r>0.0)
  219.         mutate_rate=r;
  220.     return;
  221. }
  222.  
  223. int Gene::get_length(void)
  224. {
  225.     return length;
  226. }
  227.  
  228. // Gene_Pool definitions
  229.  
  230. Gene_Pool::Gene_Pool(int number,int a)
  231. // uses global variable pop_length to set gene size
  232. {
  233.     int i;
  234.     
  235.     pop_length=a;
  236.     plength=a;
  237.     size=number;
  238.     index=new int[size];
  239.     for(i=0;i<size;i++)
  240.         index[i]=i;
  241.     gene=new Gene[size];
  242. }
  243.  
  244. Gene_Pool& Gene_Pool::operator+(Gene_Pool &a)
  245. {
  246.     int i;
  247.     
  248.     static Gene_Pool b(size+a.size,plength);
  249.     
  250.     if(this==&a)
  251.     {
  252.         delete &b;
  253.         return *this;
  254.     }
  255.     if(plength!=a.plength)
  256.     {
  257.         printf("incompatible genes\n");
  258.         delete &b;
  259.         return *this;
  260.     }
  261.     for(i=0;i<a.size;i++)
  262.         b.gene[i]=gene[i];
  263.     for(i=size;i<b.size;i++)
  264.         b.gene[i]=a.gene[i-size];
  265.     return b;
  266. }
  267.  
  268. Gene& Gene_Pool::operator[](int elem)
  269. {
  270.     if(elem>=0&&elem<size)
  271.         return gene[index[size-elem-1]];
  272.     else
  273.     {
  274.         printf("Gene access error\n");
  275.         return gene[0];
  276.     }
  277. }
  278.  
  279. Gene_Pool& Gene_Pool::operator=(const Gene_Pool& a)
  280. {
  281.     int i;
  282.  
  283.     if(this==&a)
  284.         return *this;
  285.     size=a.size;
  286.     pop_length=a.plength;
  287.     plength=a.plength;
  288.     delete gene;
  289.     delete index;
  290.     gene=new Gene[size];
  291.     index=new int[size];
  292.     for(i=0;i<pop_length;i++)
  293.     {
  294.         gene[i]=a.gene[i];
  295.         index[i]=a.index[i];
  296.     }
  297.     return *this;
  298. }
  299.  
  300. Gene_Pool& Gene_Pool::mutate(void)
  301. {
  302.     int i;
  303.  
  304.     for(i=0;i<size;i++)
  305.         gene[i].mutate();
  306.     return *this;
  307. }
  308.  
  309. Gene_Pool& Gene_Pool::set_rate(double r)
  310. {
  311.     int i;
  312.  
  313.     for(i=0;i<size;i++)
  314.         gene[i].set_rate(r);
  315.     return *this;
  316. }
  317.  
  318. Gene_Pool& Gene_Pool::sort(void)
  319. {
  320.     int i,j;
  321.     double *values;
  322.  
  323.     values=new double[size];
  324.  
  325.     for(i=0;i<size;i++)
  326.         values[i]=gene[i].get_value();
  327.     indexx(size,values,index);    // "NR in C" heap sort function.  Sorts lowest to highest
  328.     delete values;
  329.     return *this;
  330. }
  331.  
  332. Gene_Pool& Gene_Pool::evolve(void)
  333. // allows for random mating of top half or ordered mating (you decide which is better)
  334. {
  335.     int i;
  336.  
  337.     this->sort();
  338.     if(RAND_MATE)
  339.     {
  340.         // randomly mate top half of population and store in bottom half
  341.         for(i=0;i<size/2;i++)
  342.         {
  343.             gene[index[i]]=gene[index[size-rand()%size-1]]+gene[index[size-rand()%size-1]];
  344.         }
  345.         this->mutate();
  346.     }
  347.     else
  348.     {
  349.         // or mate top half of population together in order
  350.         for(i=0;i<size/2;i++)
  351.         {
  352.             gene[index[i]]=gene[index[size-i-1]]+gene[index[size-i-2]];
  353.         }
  354.     }
  355.     return *this;
  356. }
  357.  
  358. Gene_Pool& Gene_Pool::kill(int n)
  359. // if after evolve for a while you want to kill off the weak to speed things up
  360. {
  361.     int i;
  362.     Gene *tmp;
  363.  
  364.     tmp=new Gene[size-n];
  365.     if(n>=size)
  366.         n=size-1;
  367.     size=size-n;
  368.     for(i=0;i<size;i++)
  369.         tmp[i]=gene[index[size+n-i]-1];
  370.     delete gene;
  371.     delete index;
  372.     gene=new Gene[size];
  373.     index=new int[size];
  374.     for(i=0;i<size;i++)
  375.         gene[i]=tmp[i];
  376.     this->sort();
  377.     delete tmp;
  378.     return *this;
  379. }
  380.  
  381. // "Numerical Recipes is C" heapsort of arrin with corresponding reordering of indx
  382. void indexx(int n,double *arrin,int *indx)
  383. {
  384.     int l,j,ir,indxt,i;
  385.     float q;
  386.  
  387.     indx--;
  388.     for (j=1;j<=n;j++) indx[j]=j-1;
  389.     l=(n >> 1) + 1;
  390.     ir=n;
  391.     for (;;)
  392.     {
  393.         if (l > 1)
  394.             q=arrin[(indxt=indx[--l])];
  395.         else
  396.         {
  397.             q=arrin[(indxt=indx[ir])];
  398.             indx[ir]=indx[1];
  399.             if (--ir == 1)
  400.             {
  401.                 indx[1]=indxt;
  402.                 indx++;
  403.                 return;
  404.             }
  405.         }
  406.         i=l;
  407.         j=l << 1;
  408.         while (j <= ir)
  409.         {
  410.             if (j < ir && arrin[indx[j]] < arrin[indx[j+1]]) j++;
  411.             if (q < arrin[indx[j]])
  412.             {
  413.                 indx[i]=indx[j];
  414.                 j += (i=j);
  415.             }
  416.             else j=ir+1;
  417.         }
  418.         indx[i]=indxt;
  419.     }
  420. }
  421.  
  422. #define IB1 1
  423. #define IB2 2
  424. #define IB5 16
  425. #define IB18 131072
  426. #define MASK IB1+IB2+IB5
  427.  
  428. // "Numerical Recipes in C" random bit function (uses periodic maximal length sequences)
  429. int irbit2(void)
  430. {
  431.     if (
  432.     iseed & IB18) {
  433.         iseed=((iseed ^ MASK) << 1) | IB1;
  434.         return 1;
  435.     } else {
  436.         iseed <<= 1;
  437.         return 0;
  438.     }
  439. }
  440.  
  441. #undef MASK
  442. #undef IB18
  443. #undef IB5
  444. #undef IB2
  445. #undef IB1
  446.  
  447. --------------------------------------------------------------------------
  448.  
  449. // imp.m : Example implementation of Gene_Pool class
  450. // Programmer : Ian Schumacher
  451. // Comments welcome 
  452. // email : schumach@sol.UVic.CA
  453. // Genie : I.SCHUMACHER
  454.  
  455. // Pathetically unrealistic problem to be solved by using gene algorithms,
  456. // but illustrates principles.
  457.  
  458. #include "gene.h"
  459. #include <stdio.h>
  460. #include <stdlib.h>
  461. #include <math.h>
  462.  
  463. #define size 500        // Gene_Pool population size
  464. #define length 30        // Gene length
  465. #define steps 100        // maximum number of evolution steps
  466. #define sqr(x) x*x        // simple squaring function
  467.  
  468. int main()
  469. {
  470.     int i,j,k,t;
  471.     Gene_Pool a(size,length);
  472.     double value1,value2,value3;
  473.     double tmp1,tmp2;
  474.     int tmp;
  475.  
  476.     a.set_rate(0.05/length);        // set mutation rate, (in this case to 5% of population)
  477.  
  478.     for(i=0;i<steps;i++)        // number of evolution steps
  479.     {
  480.         for(j=0;j<a.get_size();j++)
  481.         {
  482.             // this is where the value of gene is determined
  483.             value1=0;
  484.             value2=0;
  485.             value3=0;
  486.             tmp=a[j].get_length()/3;
  487.             for(t=0;t<tmp;t++)
  488.             {
  489.                 // interperate gene as three long integers
  490.                 value1+=(1L<<t)*a[j][t];
  491.                 value2+=(1L<<t)*a[j][t+tmp];
  492.                 value3+=(1L<<t)*a[j][t+2*tmp];
  493.             }
  494.             // normalize values to 1
  495.             value1/=1L<<tmp;
  496.             value2/=1L<<tmp;
  497.             value3/=1L<<tmp;
  498.             // maximize simple nonlinear equation
  499.             a[j]=exp(-sqr((value1-0.33))-sqr((value2-0.5))-sqr((value3-0.7)));  // set gene[j] value
  500.         }
  501. // break out of evolution early if genes starting to look the same
  502.         if((a[0].get_value()==a[1].get_value())&&a[1].get_value()==a[2].get_value()&&tmp1==tmp2)
  503.             break;
  504.         tmp1=a[0].get_value();
  505.         tmp2=a[1].get_value();
  506.         a.evolve();
  507.         // display sample of every fifth generation
  508.         if(!(i%5))
  509.         {
  510.             for(j=0;j<5;j++)
  511.             {
  512.                 for(k=0;k<length;k++)
  513.                 {
  514.                     printf("%d ",a[j][k]);
  515.                 }
  516.                 printf("%f\n",a[j].get_value());
  517.             }
  518.             printf("\n");
  519.         }
  520.     }
  521.     // display final result
  522.     for(t=0;t<tmp;t++)
  523.     {
  524.         value1+=(1L<<t)*a[0][t];
  525.         value2+=(1L<<t)*a[0][t+tmp];
  526.         value3+=(1L<<t)*a[0][t+2*tmp];
  527.     }
  528.     value1/=1L<<tmp;
  529.     value2/=1L<<tmp;
  530.     value3/=1L<<tmp;
  531.     printf("value1 = %f value2= %f value3= %f\n",value1,value2,value3);
  532.     return 1;
  533. }
  534.  
  535.