|
@@ -1,11 +1,237 @@
|
|
|
#include "OptimizerEvolutionary.h"
|
|
|
+#include <iostream>
|
|
|
|
|
|
namespace mdd {
|
|
|
- OptimizerEvolutionary::OptimizerEvolutionary(std::shared_ptr<IModule> module)
|
|
|
+ void OptimizerEvolutionary::evaluate(size_t ignore_len)
|
|
|
{
|
|
|
+ //calculate fitness
|
|
|
+ for (auto& it = _children.begin() + ignore_len; it != _children.end(); ++it)
|
|
|
+ {
|
|
|
+ for (size_t j = 0; j < _inputs.size(); j++)
|
|
|
+ {
|
|
|
+ std::cout << "set: " << j << ": " << it->dna[j] << std::endl;
|
|
|
+ _inputs[j]->setDefaultValue() = it->dna[j];
|
|
|
+ }
|
|
|
+ auto opt = updateReader();
|
|
|
+ if (opt.module_state == state::STATE_ERROR) {
|
|
|
+ _children.erase(it);
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ it->fitness = opt.opt_value;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ //find fitest
|
|
|
+ double max = _children[0].fitness;
|
|
|
+ for (size_t i = 1; i < _children.size(); i++)
|
|
|
+ {
|
|
|
+ if (max < _children[i].fitness) {
|
|
|
+ max = _children[i].fitness;
|
|
|
+ _best = _children[i];
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
- state OptimizerEvolutionary::update()
|
|
|
+ OptimizerEvolutionary::OptimizerEvolutionary(std::shared_ptr<IModule> module, size_t grow_generation, double max_fitness, int min_generations)
|
|
|
{
|
|
|
- return state();
|
|
|
+ _module = module;
|
|
|
+ _grow_generation = grow_generation;
|
|
|
+ _min_generations = min_generations;
|
|
|
+ _max_fitness = max_fitness;
|
|
|
+ }
|
|
|
+ json OptimizerEvolutionary::update()
|
|
|
+ {
|
|
|
+ size_t gen = -1;
|
|
|
+ do
|
|
|
+ {
|
|
|
+ if (_children.empty())
|
|
|
+ {
|
|
|
+ for (size_t i = 0; i < _grow_generation*2; i++)
|
|
|
+ {
|
|
|
+ _children.push_back(generateIndividual());
|
|
|
+ }
|
|
|
+ evaluate();
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ evolve(_children);
|
|
|
+ }
|
|
|
+ ++gen;
|
|
|
+ } while (gen < _min_generations || _best.fitness > _max_fitness);
|
|
|
+
|
|
|
+ return _best.dna;
|
|
|
+ }
|
|
|
+ json OptimizerEvolutionary::mutateGene(json limit, json seed)
|
|
|
+ {
|
|
|
+ /*
|
|
|
+ limit{
|
|
|
+ (("min": []
|
|
|
+ or
|
|
|
+ "max" : [])
|
|
|
+ ("step": []
|
|
|
+ or
|
|
|
+ "rule" : string))
|
|
|
+ nor
|
|
|
+ "elements": [[],[],[]]
|
|
|
+ }
|
|
|
+ */
|
|
|
+ json ret = seed;
|
|
|
+
|
|
|
+
|
|
|
+ if (limit.contains("elements"))
|
|
|
+ {
|
|
|
+ if (limit["elements"].is_array()) {
|
|
|
+ int i = (int)random_num(0, limit["elements"].size()-1);
|
|
|
+ ret["value"] = limit["elements"][i].is_array();
|
|
|
+ }
|
|
|
+ std::cout << "ERROR in GENE elements!" << std::endl;
|
|
|
+ return ret;
|
|
|
+ }
|
|
|
+ if (limit.contains("min") && limit.contains("max")) {
|
|
|
+
|
|
|
+ bool check = true;
|
|
|
+ do {
|
|
|
+ if (!ret.empty())
|
|
|
+ {
|
|
|
+ int i = (int)random_num(0, limit["min"].size() - 1);
|
|
|
+ if (limit.contains("step")) {
|
|
|
+ //randomly generate step dx in [min, max]
|
|
|
+ /*std::cout << limit["min"][i].get<double>() << " | ";
|
|
|
+ std::cout << limit["max"][i].dump() << " | ";
|
|
|
+ std::cout << limit["step"][i].dump() << " | ";*/
|
|
|
+ ret["value"][i] = random_num(limit["min"][i].get<double>(), limit["max"][i].get<double>(), limit["step"][i].get<double>());
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ int m = (int)random_num(0, 1);
|
|
|
+ if (m == 0)
|
|
|
+ {
|
|
|
+ ret["value"][i] = limit["min"][i];
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ ret["value"][i] = limit["max"][i];
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ for (size_t i = 0; i < limit["min"].size(); i++)
|
|
|
+ {
|
|
|
+ if (limit.contains("step")) {
|
|
|
+ //randomly generate step dx in [min, max]
|
|
|
+ ret["value"].push_back(random_num(limit["min"][i].get<double>(), limit["max"][i].get<double>(), limit["step"][i].get<double>()));
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ int m = (int)random_num(0, 1);
|
|
|
+ if (m == 0)
|
|
|
+ {
|
|
|
+ ret["value"].push_back(limit["min"][i]);
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ ret["value"].push_back(limit["max"][i]);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (limit.contains("rule")) {
|
|
|
+ //use rule to check
|
|
|
+ std::cout << "ERROR in GENE elements! (rule not implemented)" << std::endl;
|
|
|
+ check = false;
|
|
|
+ }
|
|
|
+ } while (!check);
|
|
|
+ return ret;
|
|
|
+
|
|
|
+ }
|
|
|
+ std::cout << "ERROR in GENE elements! (END)" << std::endl;
|
|
|
+ return json();//ERROR
|
|
|
+ }
|
|
|
+
|
|
|
+ void OptimizerEvolutionary::evolve(std::vector<Individual> parents)
|
|
|
+ {
|
|
|
+ ////fittest should breed more
|
|
|
+ //detect lower border
|
|
|
+ double max = parents[0].fitness;
|
|
|
+ for (size_t i = 1; i < parents.size(); i++)
|
|
|
+ {
|
|
|
+ if (max < parents[i].fitness) {
|
|
|
+ max = parents[i].fitness;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ //detect lower border
|
|
|
+ double sum = 0;
|
|
|
+ for (size_t i = 0; i < parents.size(); i++)
|
|
|
+ {
|
|
|
+ sum += max - parents[i].fitness;
|
|
|
+ }
|
|
|
+ //multiply fitter parents
|
|
|
+ std::vector<Individual> gen_pool = parents;
|
|
|
+ for (size_t i = 0; i < parents.size(); i++)
|
|
|
+ {
|
|
|
+ for (size_t j = 1; j < std::round((max - parents[i].fitness)/sum*20); i++)
|
|
|
+ {
|
|
|
+ gen_pool.push_back(parents[i]);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ //fittest parents will also be new childrens
|
|
|
+ _children.clear();
|
|
|
+ double min = parents[0].fitness;
|
|
|
+ for (size_t i = 1; i < parents.size(); i++)
|
|
|
+ {
|
|
|
+ if (max > parents[i].fitness) {
|
|
|
+ min = parents[i].fitness;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ for (size_t i = 0; i < parents.size(); i++)
|
|
|
+ {
|
|
|
+ if (max == parents[i].fitness) {
|
|
|
+ bool exist = false;
|
|
|
+ for (size_t j = 0; j < _children.size(); j++)
|
|
|
+ {
|
|
|
+ if (_children[j].dna == parents[i].dna) {
|
|
|
+ exist = true;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (!exist) {
|
|
|
+ _children.push_back(parents[i]);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ //breed
|
|
|
+ size_t init_len = _children.size();
|
|
|
+ for (size_t i = 0; i < _grow_generation; i++)
|
|
|
+ {
|
|
|
+ int p1 = (int)random_num(0, gen_pool.size() - 1);
|
|
|
+ int p2 = (int)random_num(0, gen_pool.size() - 1);
|
|
|
+ _children.push_back(combine(gen_pool[p1], gen_pool[p2]));
|
|
|
+ }
|
|
|
+ evaluate(init_len);
|
|
|
+ }
|
|
|
+ OptimizerEvolutionary::Individual OptimizerEvolutionary::combine(Individual par1, Individual par2)
|
|
|
+ {
|
|
|
+ size_t len = par1.dna.size();
|
|
|
+ Individual child;
|
|
|
+ for (size_t i = 0; i < len; i++)
|
|
|
+ {
|
|
|
+ double p = random_num(0.0, 100.0, 1.0);
|
|
|
+ if (p<45.0)
|
|
|
+ {
|
|
|
+ child.dna.push_back(par1.dna[i]);
|
|
|
+ }
|
|
|
+ else if(p<90.0){
|
|
|
+ child.dna.push_back(par2.dna[i]);
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ child.dna.push_back(mutateGene(_input_limits[i]));
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return child;
|
|
|
+ }
|
|
|
+ OptimizerEvolutionary::Individual OptimizerEvolutionary::generateIndividual()
|
|
|
+ {
|
|
|
+ Individual ret;
|
|
|
+ for (size_t i = 0; i < _inputs.size(); i++)
|
|
|
+ {
|
|
|
+ ret.dna.push_back(mutateGene(_input_limits[i]));
|
|
|
+ }
|
|
|
+ return ret;
|
|
|
}
|
|
|
}
|