int main()
{
    //setup the optimisation
    //define your boundaries
    OptBoundaries<double> optBoundaries;
    optBoundaries.add_boundary(-5.0, 5.0, "X");

    //instansiate your calculator
    MySolver<double> mySolver;

    //number of calculations
    unsigned int maxCalculations = 300;

    //we want to find the minimum
    OptTarget optTarget = MINIMIZE;

    //how fast the great deluge algorithm slows down
    //http://en.wikipedia.org/wiki/Great_Deluge_algorithm
    double coolingFactor = 0.95;

    //the initial water level
    //http://en.wikipedia.org/wiki/Great_Deluge_algorithm
    double waterLevel = 25.0;

    //how much rain is added to the water level per iteration
    //with x^2 from -5 to +5 the max value is 25, while the min and wanted value is 0
    //with 300 calculations, the water level should be pretty close to the optimum of 0
    //25/300 => 0.083333 [rain should AT LEAST be that much] => make it 0.15
    //http://en.wikipedia.org/wiki/Great_Deluge_algorithm
    double rain = 0.15;

    //create your optimiser
    //using great deluge
    OptGreatDeluge<double> opt(optBoundaries,
                               maxCalculations,
                               &mySolver,
                               optTarget,
                               0.0, //only required if approaching / diverging
                               coolingFactor,
                               waterLevel,
                               rain);

    //enable logging
    //boundaries object required to know the parameters names for the header
    OptBase<double>::enable_logging("example_great_deluge_x_square.log", optBoundaries);

    //let's go
    OptBase<double>::run_optimisations();

    //print result
    OptCalculation<double> best = opt.get_best_calculation();
    cout << best.to_string_header() << endl;
    cout << best.to_string_values() << endl;

    return 0;
}
int main() {
    //setup the optimisation
    //define your boundaries
    OptBoundaries<double> optBoundaries;
    optBoundaries.add_boundary({-5.0, 5.0, "X"});

    //number of calculations
    unsigned int maxCalculations = 300;

    //we want to find the minimum
    OptTarget optTarget = OptTarget::MINIMIZE;

    //how fast the great deluge algorithm slows down
    //http://en.wikipedia.org/wiki/Great_Deluge_algorithm
    double coolingFactor = 0.95;

    //the initial water level
    //http://en.wikipedia.org/wiki/Great_Deluge_algorithm
    double waterLevel = 25.0;

    //how much rain is added to the water level per iteration
    //with x^2 from -5 to +5 the max value is 25, while the min and wanted value is 0
    //with 300 calculations, the water level should be pretty close to the optimum of 0
    //25/300 => 0.083333 [rain should AT LEAST be that much] => make it 0.15
    //http://en.wikipedia.org/wiki/Great_Deluge_algorithm
    double rain = 0.15;

    //define your coordinator
    OptCoordinator<double, false> coordinator(
        maxCalculations,
        toOptimize,
        optTarget,
        0);

    //add great deluge as child
    coordinator.add_child(make_unique<OptGreatDeluge<double>>(
        optBoundaries,
        optTarget,
        0,
        coolingFactor,
        waterLevel,
        rain));

    //let's go
    coordinator.run_optimisation();

    //print result
    OptCalculation<double> best = coordinator.get_best_calculation();
    cout << best.to_string_header() << endl;
    cout << best.to_string_values() << endl;

    return 0;
}
int main()
{
    //setup the optimisation
    //define your boundaries
    OptBoundaries<double> optBoundaries;
    optBoundaries.add_boundary(-5.0, 5.0, "X");

    //instansiate your calculator
    MySolver<double> mySolver;

    //number of calculations
    unsigned int maxCalculations = 300;

    //we want to find the minimum
    OptTarget optTarget = MINIMIZE;

    //how fast the simulated annealing algorithm slows down
    //http://en.wikipedia.org/wiki/Simulated_annealing
    double coolingFactor = 0.95;

    //the chance in the beginning to follow bad solutions
    double startChance = 0.25;

    //create your optimiser
    //using simulated annealing
    OptSimulatedAnnealing<double> opt(optBoundaries,
                                  maxCalculations,
                                  &mySolver,
                                  optTarget,
                                  0.0, //only required if approaching / diverging
                                  coolingFactor,
                                  startChance);

    //enable logging
    //boundaries object required to know the parameters names for the header
    OptBase<double>::enable_logging("example_simulated_annealing_x_square.log", optBoundaries);

    //let's go
    OptBase<double>::run_optimisations();

    //print result
    OptCalculation<double> best = opt.get_best_calculation();
    cout << best.to_string_header() << endl;
    cout << best.to_string_values() << endl;

    return 0;
}
int main() {
    //setup the optimisation
    //define your boundaries
    OptBoundaries<double> optBoundaries;
    optBoundaries.add_boundary({-5.0, 5.0, "X"});

    //number of calculations
    unsigned int maxCalculations = 300;

    //we want to find the minimum
    OptTarget optTarget = OptTarget::MINIMIZE;

    //how fast the evolutionary algorithm slows down
    //https://en.wikipedia.org/wiki/Evolutionary_algorithm
    double coolingFactor = 0.95;

    //how many individuals should be spawned in the beginning
    //use an even, positiv number
    //https://en.wikipedia.org/wiki/Evolutionary_algorithm
    unsigned int nIndividualsStart = 50;

    //how many individuals shall be selected each generation
    //this should also be an even number
    //https://en.wikipedia.org/wiki/Evolutionary_algorithm
    unsigned int nIndividualsSelection = 10;

    //how many children each parent pair should spawn
    //use a number > 2
    ////https://en.wikipedia.org/wiki/Evolutionary_algorithm
    unsigned int nIndividualsOffspring = 3;

    //how much the offspring should be mutated
    //or moved from the center of the parents
    //https://en.wikipedia.org/wiki/Evolutionary_algorithm
    double mutation = 0.1;

    //define your coordinator
    OptCoordinator<double, false> coordinator(
        maxCalculations,
        toOptimize,
        optTarget,
        0);

    //add evolutionary as child
    coordinator.add_child(make_unique<OptEvolutionary<double>>(
        optBoundaries,
        optTarget,
        0,
        coolingFactor,
        nIndividualsStart,
        nIndividualsSelection,
        nIndividualsOffspring,
        mutation));

    //let's go
    coordinator.run_optimisation();

    //print result
    OptCalculation<double> best = coordinator.get_best_calculation();
    cout << best.to_string_header() << endl;
    cout << best.to_string_values() << endl;

    return 0;
}