Back to TILs

C++ GAlib

Date: 2023-04-03Last modified: 2023-04-05

Table of contents

#include <fmt/core.h>
#include <ga/GARealGenome.h>
#include <ga/ga.h>

#include <cmath>
#include <fstream>
#include <ga/GARealGenome.C>

FILE* genomeFile;

// Define the fitness function
float myObjective(GAGenome& g) {
  GARealGenome genome = (GARealGenome&)g;
  float x1 = genome.gene(0) - 33.0;
  float x2 = genome.gene(1) - 22.0;

  return (x1 * x1) + (x2 * x2);
  // The minimum value is (33;22)
}

int main([[maybe_unused]] int argc, [[maybe_unused]] char** argv) {
  constexpr auto minValue1 = -1.0;
  constexpr auto maxValue1 = 50.0;
  constexpr auto increment1 = 0.001;

  constexpr auto minValue2 = -2.0;
  constexpr auto maxValue2 = 40.0;
  constexpr auto increment2 = 0.005;

  genomeFile = fopen("output/galib_01.dat", "w");

  GARandomSeed(123456);
  
  // One allele for each dimension
  GARealAlleleSetArray alleles;
  alleles.add(minValue1, maxValue1, increment1, GAAllele::EXCLUSIVE,
              GAAllele::EXCLUSIVE);
  alleles.add(minValue2, maxValue2, increment2, GAAllele::EXCLUSIVE,
              GAAllele::EXCLUSIVE);

  GARealGenome genome(alleles, myObjective);

  GASimpleGA ga(genome);
  ga.minimize();          // by default we want to minimize the objective
  ga.populationSize(10);  // how many individuals in the population
  ga.nGenerations(500);   // number of generations to evolve

  // Dumping data (optional)
  ga.scoreFrequency(20);  // keep the scores of every n generations
  ga.flushFrequency(20);  // specify how often to write the score to disk
  ga.scoreFilename("output/galib_01_score.txt");

  ga.initialize();
  // ----------------------------------------------------------------------
  // ga.evolve();
  // ----------------------------------------------------------------------
  // Or step by step
  size_t step{};
  while (!ga.done()) {
    ga.step();
    // Debugging
    if (step++ % 20 == 0) {
      GARealGenome& best = (GARealGenome&)ga.statistics().bestIndividual();
      fmt::print(genomeFile, "{:3} {:.7f} {:.7f} {:.7f}\n", step, best.gene(0),
                 best.gene(1), best.score());
    }
  }
  // ----------------------------------------------------------------------

  // Print the best solution found
  GARealGenome& best = (GARealGenome&)ga.statistics().bestIndividual();
  fmt::print("Best X1: {:+.7f} X2: {:+.7f}\n", best.gene(0), best.gene(1));

  fmt::print(genomeFile, "{:3} {:.7f} {:.7f} {:.7f}\n", step, best.gene(0),
             best.gene(1), best.score());
  fclose(genomeFile);

  // Plot
  FILE* gnuplotPipe = popen("gnuplot -persistent", "w");
  fprintf(gnuplotPipe, "set term svg enhanced size 1200 800\n");
  fprintf(gnuplotPipe, "set output 'images/galib_01.svg'\n");
  fprintf(gnuplotPipe, "set title 'Optimization progress' tc rgb 'white'\n");
  fprintf(gnuplotPipe, "set xlabel 'Best of generation' tc rgb 'white'\n");
  fprintf(gnuplotPipe, "set ylabel 'Input values and Score' tc rgb 'white'\n");
  fprintf(gnuplotPipe, "set border lc rgb 'white'\n");
  fprintf(gnuplotPipe, "set key tc rgb 'white'\n");
  fprintf(gnuplotPipe, "set logscale y\n");
  fprintf(gnuplotPipe, "set grid\n");
  fprintf(gnuplotPipe, "set linetype 1 lc rgb 'orange' lw 2\n");
  fprintf(gnuplotPipe, "set linetype 2 lc rgb 'cyan' lw 2\n");
  fprintf(gnuplotPipe, "set linetype 3 lc rgb 'green' lw 2\n");
  fprintf(gnuplotPipe, "set linetype 99 lc rgb 'white'\n");
  fprintf(gnuplotPipe, "set xzeroaxis linetype 99\n");
  fprintf(gnuplotPipe, "set yzeroaxis linetype 99\n");
  fprintf(gnuplotPipe,
          "plot "
          "'output/galib_01.dat' using 1:4 w l title 'Score', "
          "'output/galib_01.dat' using 1:2 w l title 'X_1', "
          "'output/galib_01.dat' using 1:3 w l title 'X_2'\n");
  fflush(gnuplotPipe);
  pclose(gnuplotPipe);

  return 0;
}
Plot
Fig. 1 - Plot

Possible output

Best X1: +32.7250023 X2: +22.2899990

Debugging evolution data:

  1 30.8700008 17.3349991 26.2991295
 21 30.8700008 21.1099987 5.3289986
 41 30.8700008 21.1099987 5.3289986
 61 30.8700008 21.1099987 5.3289986
 81 30.8700008 21.1099987 5.3289986
101 30.8700008 21.1099987 5.3289986
121 30.8700008 21.1099987 5.3289986
141 34.7660027 21.1099987 3.9108677
161 34.7660027 21.1099987 3.9108677
181 34.7660027 21.1099987 3.9108677
201 34.7660027 21.1099987 3.9108677
221 34.7660027 21.1099987 3.9108677
241 34.7660027 21.1099987 3.9108677
261 32.7250023 22.2899990 0.1597232
281 32.7250023 22.2899990 0.1597232
301 32.7250023 22.2899990 0.1597232
321 32.7250023 22.2899990 0.1597232
341 32.7250023 22.2899990 0.1597232
361 32.7250023 22.2899990 0.1597232
381 32.7250023 22.2899990 0.1597232
401 32.7250023 22.2899990 0.1597232
421 32.7250023 22.2899990 0.1597232
441 32.7250023 22.2899990 0.1597232
461 32.7250023 22.2899990 0.1597232
481 32.7250023 22.2899990 0.1597232
500 32.7250023 22.2899990 0.1597232

Score file generated by galib.

0	1223.13
20	271.691
40	554.674
60	75.4333
80	5.329
100	5.329
120	5.329
140	3.91087
160	3.91087
180	11.2698
200	97.5
220	723.864
240	3.91087
260	377.376
280	0.159723
300	384.785
320	572.807
340	0.159723
360	0.159723
380	0.159723
400	0.159723

References