Advertisement
0x13

Simple C genetic algorithm example

Oct 3rd, 2011
6,771
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 9.17 KB | None | 0 0
  1. /**
  2.  * description:
  3.  *  Simple genetic algorithm for finding equation that equals target number
  4.  *  example for number 27 has many results:
  5.  *      - 7+29-8-1
  6.  *      - 15+28-16
  7.  *  this code isn't really perfect ^_^ but shows some basics.
  8.  *  tested in linux fedora 14 with valgrind.
  9.  *
  10.  * author: ADRABI Abderrahim (adrabi[at]mail[dot]ru)
  11.  * date: 2011-10-03
  12.  */
  13. #include <stdio.h>
  14. #include <stdlib.h>
  15. #include <time.h>
  16. #include <string.h>
  17.  
  18. #define POPSIZE     1024
  19. #define ELITRATE    0.1f
  20. #define MUTATIONRATE    0.25f
  21. #define ELEMENTS    8
  22. #define MUTATION    RAND_MAX * MUTATIONRATE
  23. #define TARGET      27
  24.  
  25. /**
  26.  * Basic elements for construction an equation
  27.  */
  28. static const char *BIN_ELEMENTS[12] = {
  29.   "0000\0",         // 0
  30.   "0001\0",         // 1
  31.   "0010\0",         // 2
  32.   "0011\0",         // 3
  33.   "0100\0",         // 4
  34.   "0101\0",         // 5
  35.   "0110\0",         // 6
  36.   "0111\0",         // 7
  37.   "1000\0",         // 8
  38.   "1001\0",         // 9
  39.   "1010\0",         // +
  40.   "1011\0"          // -
  41. };
  42.  
  43. /**
  44.  * Structure base of genome
  45.  */
  46. typedef struct
  47. {
  48.   unsigned int fitness;
  49.   char *gen;
  50. } ga_struct;
  51.  
  52. /**
  53.  * Initialize new random population
  54.  */
  55. void
  56. init_population (ga_struct * population, ga_struct * beta_population)
  57. {
  58.   const int bin_size = (sizeof (char) * ELEMENTS * 4) + 1;
  59.   int index = 0;
  60.   for (; index < POPSIZE; index++)
  61.     {
  62.       // default initialization/ create empty genome
  63.       population[index].fitness = 0;
  64.       population[index].gen = malloc (bin_size);
  65.       *population[index].gen = '\0';
  66.  
  67.       // default initialization/ create empty genome
  68.       beta_population[index].fitness = 0;
  69.       beta_population[index].gen = malloc (bin_size);
  70.       *beta_population[index].gen = '\0';
  71.  
  72.       int e = 0;
  73.       for (; e < ELEMENTS; e++)
  74.     {
  75.       // put random element in population
  76.       // 12 is count of elements in BIN_ELEMENTS array
  77.       strcat (population[index].gen, BIN_ELEMENTS[(rand () % 12)]);
  78.     }
  79.     }
  80. }
  81.  
  82. /**
  83.  * Calculate each individual fitness in population
  84.  */
  85. void
  86. cal_fitness (ga_struct * population)
  87. {
  88.   int index = 0;
  89.   int unsigned fitness = 0;
  90.   for (; index < POPSIZE; index++)
  91.     {
  92.       char *gen_str = population[index].gen;
  93.       int gen_len = strlen (gen_str), sum = 0, current_value = 0, step = 0;
  94.       unsigned int last_operator_index = -1;
  95.       char last_operator = (char) 0;
  96.  
  97.       for (; step < ELEMENTS; step++)
  98.     {
  99.       char element[5] = "\0";
  100.       strncpy (element, gen_str, 4);
  101.       if (strcmp ("0000", element) == 0)
  102.         {
  103.           current_value *= 10;
  104.         }
  105.       else if (strcmp ("0001", element) == 0)
  106.         {
  107.           current_value = (current_value * 10) + 1;
  108.         }
  109.       else if (strcmp ("0010", element) == 0)
  110.         {
  111.           current_value = (current_value * 10) + 2;
  112.         }
  113.       else if (strcmp ("0011", element) == 0)
  114.         {
  115.           current_value = (current_value * 10) + 3;
  116.         }
  117.       else if (strcmp ("0100", element) == 0)
  118.         {
  119.           current_value = (current_value * 10) + 4;
  120.         }
  121.       else if (strcmp ("0101", element) == 0)
  122.         {
  123.           current_value = (current_value * 10) + 5;
  124.         }
  125.       else if (strcmp ("0110", element) == 0)
  126.         {
  127.           current_value = (current_value * 10) + 6;
  128.         }
  129.       else if (strcmp ("0111", element) == 0)
  130.         {
  131.           current_value = (current_value * 10) + 7;
  132.         }
  133.       else if (strcmp ("1000", element) == 0)
  134.         {
  135.           current_value = (current_value * 10) + 8;
  136.         }
  137.       else if (strcmp ("1001", element) == 0)
  138.         {
  139.           current_value = (current_value * 10) + 9;
  140.         }
  141.       // ignore elements that have two flowed operators or ends with operators like:
  142.       //         * 1+-1++-1
  143.       //         * 2333+55+
  144.       else if (strcmp ("1010", element) == 0
  145.            && step - last_operator_index > 1 && step + 1 < ELEMENTS)
  146.         {
  147.           if (last_operator == (char) 0)
  148.         {
  149.           sum = current_value;
  150.         }
  151.           else if (last_operator == '+')
  152.         {
  153.           sum += current_value;
  154.         }
  155.           else if (last_operator == '-')
  156.         {
  157.           sum -= current_value;
  158.         }
  159.  
  160.           current_value = 0;
  161.           last_operator_index = step;
  162.           last_operator = '+';
  163.         }
  164.       // ignore elements that have two flowed operators or ends with operators like:
  165.       //         * 1+-1++-1
  166.       //         * 2333+55+
  167.       else if (strcmp ("1011", element) == 0
  168.            && step - last_operator_index > 1 && step + 1 < ELEMENTS)
  169.         {
  170.           if (last_operator == (char) 0)
  171.         {
  172.           sum = current_value;
  173.         }
  174.           else if (last_operator == '+')
  175.         {
  176.           sum += current_value;
  177.         }
  178.           else if (last_operator == '-')
  179.         {
  180.           sum -= current_value;
  181.         }
  182.  
  183.           current_value = 0;
  184.           last_operator_index = step;
  185.           last_operator = '-';
  186.         }
  187.       else
  188.         {
  189.           /// error the binary string not found
  190.           sum = 999999;
  191.           break;
  192.         }
  193.       gen_str += 4;
  194.     }
  195.  
  196.       if (last_operator == '+')
  197.     {
  198.       sum += current_value;
  199.     }
  200.       else if (last_operator == '-')
  201.     {
  202.       sum -= current_value;
  203.     }
  204.  
  205.       // abs, because fitness is unsigned integer ^_^
  206.       population[index].fitness = abs (sum - TARGET);
  207.     }
  208. }
  209.  
  210. /**
  211.  * sort function needed by quick sort
  212.  */
  213. int
  214. sort_func (const void *e1, const void *e2)
  215. {
  216.   return ((ga_struct *) e1)->fitness - ((ga_struct *) e2)->fitness;
  217. }
  218.  
  219. /**
  220.  * sort population by fitness
  221.  */
  222. inline void
  223. sort_by_fitness (ga_struct * population)
  224. {
  225.   qsort (population, POPSIZE, sizeof (ga_struct), sort_func);
  226. }
  227.  
  228. /**
  229.  * select elit element in top array after sort
  230.  */
  231. void
  232. elitism (ga_struct * population, ga_struct * beta_population, int esize)
  233. {
  234.   const int gen_len = ELEMENTS * 4 + 1;
  235.   int index = 0;
  236.   for (; index < esize; index++)
  237.     {
  238.       int e = 0;
  239.       for (; e < gen_len; e++)
  240.     {
  241.       beta_population[index].gen[e] = population[index].gen[e];
  242.     }
  243.     }
  244. }
  245.  
  246. /**
  247.  * mutate an individual with random rate
  248.  */
  249. void
  250. mutate (ga_struct * member)
  251. {
  252.   int tsize = strlen (member->gen);
  253.   int number_of_mutations = rand () % 10;
  254.   int m = 0;
  255.   for (; m < number_of_mutations; m++)
  256.     {
  257.       int apos = rand () % tsize;
  258.  
  259.       if (member->gen[apos] == '0')
  260.     {
  261.       member->gen[apos] = '1';
  262.     }
  263.       else
  264.     {
  265.       member->gen[apos] = '0';
  266.     }
  267.     }
  268. }
  269.  
  270. /**
  271.  * mate randomly the rest of population after elitism
  272.  */
  273. void
  274. mate (ga_struct * population, ga_struct * beta_population)
  275. {
  276.   int esize = POPSIZE * ELITRATE;
  277.  
  278.   // elitism of top elements in array
  279.   elitism (population, beta_population, esize);
  280.  
  281.   // mate the rest of shitty population xD
  282.   int m = esize, i1 = -1, i2 = -1, pos = -1, tsize = ELEMENTS * 4 + 1;
  283.   for (; m < POPSIZE; m++)
  284.     {
  285.       pos = rand () % tsize;
  286.       i1 = rand () % POPSIZE;
  287.       i2 = rand () % POPSIZE;
  288.  
  289.       int i = 0;
  290.       for (; i < pos; i++)
  291.     {
  292.       beta_population[m].gen[i] = population[i1].gen[i];
  293.     }
  294.       for (i = pos; i < tsize; i++)
  295.     {
  296.       beta_population[m].gen[i] = population[i2].gen[i];
  297.     }
  298.  
  299.       if (rand () < MUTATION)
  300.     {
  301.       mutate (&beta_population[m]);
  302.     }
  303.     }
  304. }
  305.  
  306. /**
  307.  * decode binary string to readable format
  308.  */
  309. void
  310. decode_gen (ga_struct * member)
  311. {
  312.   char *gen_str = member->gen;
  313.   int step = 0;
  314.  
  315.   for (; step < ELEMENTS; step++)
  316.     {
  317.       char element[5] = "\0";
  318.       strncpy (element, gen_str, 4);
  319.       if (strcmp ("0000", element) == 0)
  320.     {
  321.       printf ("0");
  322.     }
  323.       else if (strcmp ("0001", element) == 0)
  324.     {
  325.       printf ("1");
  326.     }
  327.       else if (strcmp ("0010", element) == 0)
  328.     {
  329.       printf ("2");
  330.     }
  331.       else if (strcmp ("0011", element) == 0)
  332.     {
  333.       printf ("3");
  334.     }
  335.       else if (strcmp ("0100", element) == 0)
  336.     {
  337.       printf ("4");
  338.     }
  339.       else if (strcmp ("0101", element) == 0)
  340.     {
  341.       printf ("5");
  342.     }
  343.       else if (strcmp ("0110", element) == 0)
  344.     {
  345.       printf ("6");
  346.     }
  347.       else if (strcmp ("0111", element) == 0)
  348.     {
  349.       printf ("7");
  350.     }
  351.       else if (strcmp ("1000", element) == 0)
  352.     {
  353.       printf ("8");
  354.     }
  355.       else if (strcmp ("1001", element) == 0)
  356.     {
  357.       printf ("9");
  358.     }
  359.       else if (strcmp ("1010", element) == 0)
  360.     {
  361.       printf ("+");
  362.     }
  363.       else if (strcmp ("1011", element) == 0)
  364.     {
  365.       printf ("-");
  366.     }
  367.       gen_str += 4;
  368.     }
  369.  
  370.   printf ("\n");
  371. }
  372.  
  373. /**
  374.  * free memory before exit program
  375.  */
  376. void
  377. free_population (ga_struct * population)
  378. {
  379.   int index = 0;
  380.   for (; index < POPSIZE; index++)
  381.     {
  382.       free (population[index].gen);
  383.     }
  384.   free (population);
  385. }
  386.  
  387. /**
  388.  * swap arrays pointers
  389.  */
  390. void
  391. swap (ga_struct ** p1, ga_struct ** p2)
  392. {
  393.   ga_struct *tmp = *p1;
  394.   *p1 = *p2;
  395.   *p2 = tmp;
  396. }
  397.  
  398. /**
  399.  * main program
  400.  */
  401. int
  402. main (void)
  403. {
  404.   srand (time (NULL));
  405.  
  406.   ga_struct *population = malloc (sizeof (ga_struct) * POPSIZE);
  407.   ga_struct *beta_population = malloc (sizeof (ga_struct) * POPSIZE);
  408.  
  409.   init_population (population, beta_population);
  410.  
  411.   int index = 0;
  412.   for (; index < POPSIZE; index++)
  413.     {
  414.       cal_fitness (population);
  415.       sort_by_fitness (population);
  416.  
  417.       // print current best individual
  418.       printf ("binary string: %s - fitness: %d\n", population[0].gen,
  419.           population[0].fitness);
  420.  
  421.       if (population[0].fitness == 0)
  422.     {
  423.       //~ print equation
  424.       decode_gen (&population[0]);
  425.       break;
  426.     }
  427.  
  428.       mate (population, beta_population);
  429.       swap (&population, &beta_population);
  430.     }
  431.  
  432.   free_population (population);
  433.   free_population (beta_population);
  434.  
  435.   return 0;
  436. }
  437.  
  438.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement