Sample in action: terminal output readability problems on windows
Hi again!
I'm considering using this to evolve/optimize behaviors in mobile robots.
Would it be possible to add small practical examples (optimizing a function or something like that) that are illustrative and also allow the library to be tested?
Thanks!
DJuego
Hi, Yes, I agree this would be very useful. I have a few examples I can comment and put in an "examples/" folder. I'll do that asap.
I have added a simple onemax example (with custom DNA, single objective and sqlite export). I will try to add more soon. Is there any specific example you had in mind that you think could benefit a new user?
Hi! First: thank you for your effort! :-)
Before proposing anything I wanted to verify the example codes. I use Microsoft Visual Studio 2017 in Windows 10 x64 (Spanish)
I see two cpp main files in folder onemax:
simple_onemax.cpp mainevo.cpp (?)
When i try mainevo.cpp i get:

When i try onemax.cpp i get:

In https://github.com/jdisset/gaga/issues/7 I suggest possible (?) solution for _mkdir problem in Visual Studio 2017. But there are more problems. Could you consider them? Thanks in advance!
Anyways i get this output for onemax.cpp (release mode):

Sadly, there are readability problems... :-(
DJuego
For the readability problems, I'm not very familiar with Visual Studio. Judging from your screenshot it seems the terminal doesn't recognize utf-8 symbols, nor does it seem recognize any ANSI escape sequence (at least for color).
To "fix" that, I've added 2 preprocessor symbols:
GAGA_COLOR_DISABLED -> if defined before including gaga.hpp, disables color output
GAGA_UTF8_DEBUG_PRINT_DISABLED -> disables UTF-8 symbols in terminal output
Can you maybe try these and let me know if the readability issues are fixed?
The presentation improves significantly with GAGA_UTF8_DEBUG_PRINT_DISABLED, although it is not perfect.
The code:
#include <array>
#include <cassert>
#include <random>
#include <sstream>
#define GAGA_COLOR_DISABLED
#define GAGA_UTF8_DEBUG_PRINT_DISABLED
#include <gaga/gaga.hpp>
static std::default_random_engine globalRand;
struct MyDNA {
// MyDNA is a simple example of a DNA class
// it contains an array of N integers,
// implements a simple mutation
// and a simple uniform crossover
// Through initialization & mutation, we ensure that the dna will only contain 0 or 1
static const constexpr size_t N = 40;
std::array<int, N> numbers;
MyDNA() {}
// deserialization : we just read a line of numbers separated by a space
MyDNA(const std::string& s) {
std::stringstream ss(s);
std::string item;
int i = 0;
while (std::getline(ss, item, ' ')) numbers[i++] = stoi(item);
assert(i == N);
}
// serialization : write every numbers on a line, separated by a space
std::string serialize() const {
std::stringstream ss;
for (const auto& n : numbers) ss << n << " ";
ss.seekp(-1, std::ios_base::end);
return ss.str();
}
// mutation consists in replacing one of the numbers by a random number
void mutate() {
std::uniform_int_distribution<int> d5050(0, 1);
std::uniform_int_distribution<int> dInt(0, N - 1);
numbers[dInt(globalRand)] = d5050(globalRand) ? 1 : 0;
}
// this is a uniform crossover :
// we randomly decide for each number if we take its value from parent 1 or parent 2
MyDNA crossover(const MyDNA& other) {
MyDNA res;
std::uniform_int_distribution<int> d5050(0, 1);
for (size_t i = 0; i < N; ++i)
res.numbers[i] = d5050(globalRand) ? numbers[i] : other.numbers[i];
return res;
}
// this is just a static method that will generate a new random dna
// we will use it to initialize the population
static MyDNA random() {
MyDNA res;
std::uniform_int_distribution<int> d5050(0, 1);
for (size_t i = 0; i < N; ++i) res.numbers[i] = d5050(globalRand);
return res;
}
};
int main(int, char**) {
globalRand = std::default_random_engine(0);
GAGA::GA<MyDNA> ga; // declaration of the GAGA instance, with dna type MyDNA
ga.setEvaluator(
[](auto& individu, int) { // second argument of the evaluator funciton is the cpuId
int n = 0;
for (int a : individu.dna.numbers) n += a;
std::this_thread::sleep_for(std::chrono::milliseconds(1)); // we simulate load
individu.fitnesses["number of ones"] = n; // only one objective
},
"sum"); // name of the evaluator, just used for saving purposes
#ifdef SQLITE_SAVE
// OPTIONAL: we set up an sqlite saver
std::string sqlFilename = "onemax.sql";
SQLiteSaver sql(sqlFilename, ""); // second argument is any configuration detail for
// the run you want to save in the database export
#endif
// setting a few basic parameters.
// see documentation for comprehensive list
ga.setPopSize(200);
ga.setMutationRate(0.8);
ga.setCrossoverRate(0.2);
ga.setVerbosity(1);
ga.setNbThreads(8);
// we initialize the population with random DNA. The function passed to
// initPopulation is called enough time to fill the population vector
ga.initPopulation([]() { return MyDNA::random(); });
for (size_t i = 0; i < 10; ++i) { // we run the ga for 10 generations
ga.step(); // next generation
#ifdef SQLITE_SAVE
sql.newGen(ga); // saving the generation to sql
#endif
}
return 0;
}
Without flags https://imgur.com/ksxXi6R
With flags https://imgur.com/VUGs2H1
DJuego