bool Population::init(const IndividualContainer &origin, unsigned int popSize) { if (!origin.areEvaluated()) { std::cout << "Trying to initialize population of n best Robots from " "IndividualContainer which is not evaluated!" << std::endl; return false; } for (unsigned int i = 0; i < origin.size(); i++) { this->push_back(origin[i]); } this->sort(); // idea was to call this->resize(popSize);, but that requires a default // constructor to be present for RobotRepresentation, which is not the case // on purpose while (this->size() > popSize) { this->pop_back(); } this->evaluated_ = true; return true; }
namespace robogen { void init(unsigned int seed, std::string outputDirectory, std::string confFileName, bool overwrite, bool saveAll); void printUsage(char *argv[]) { std::cout << std::endl << "USAGE: " << std::endl << " " << std::string(argv[0]) << " <SEED, INTEGER> <OUTPUT_DIRECTORY, STRING> " << "<CONFIGURATION_FILE, STRING> [<OPTIONS>]" << std::endl << std::endl << "WHERE: " << std::endl << " <SEED> is a number to seed " << "the pseudorandom number generator." << std::endl << std::endl << " <OUTPUT_DIRECTORY> is the directory to write output " << "files to." << std::endl << std::endl << " <CONFIGURATION_FILE> is the evolution" << " configuration file to use." << std::endl << std::endl << "OPTIONS: " << std::endl << " --help" << std::endl << " Print all configuration options and exit." << std::endl << std::endl << " --overwrite" << std::endl << " Overwrite existing output file directory if it " << "exists." << std::endl << " (Default is to keep creating new output " << "directories with incrementing suffixes)." << std::endl << std::endl << " --save-all" << std::endl << " Save all individuals instead of just the generation" << "best." << std::endl << std::endl; } void printHelp() { boost::shared_ptr<EvolverConfiguration> conf = boost::shared_ptr< EvolverConfiguration>(new EvolverConfiguration()); conf->init("help"); std::cout << std::endl; boost::shared_ptr<RobogenConfig> robotConf = ConfigurationReader::parseConfigurationFile("help"); } boost::shared_ptr<Population> population; IndividualContainer children; boost::shared_ptr<NeatContainer> neatContainer; boost::shared_ptr<RobogenConfig> robotConf; boost::shared_ptr<EvolverConfiguration> conf; boost::shared_ptr<EvolverLog> log; bool neat; boost::shared_ptr<Selector> selector; boost::shared_ptr<Mutator> mutator; unsigned int generation; boost::random::mt19937 rng; std::vector<Socket*> sockets; void parseArgsThenInit(int argc, char* argv[]) { startRobogen(); // --------------------------------------- // verify usage and load configuration // --------------------------------------- if (argc > 1 && std::string(argv[1]) == "--help") { printUsage(argv); printHelp(); exitRobogen(EXIT_SUCCESS); } if ((argc < 4)) { printUsage(argv); std::cout << "RUN: " << std::endl << std::endl << " " << std::string(argv[0]) << " --help to see all configuration options." << std::endl << std::endl; exitRobogen(EXIT_FAILURE); } unsigned int seed = atoi(argv[1]); std::string outputDirectory = std::string(argv[2]); std::string confFileName = std::string(argv[3]); bool overwrite = false; bool saveAll = false; int currentArg = 4; for (; currentArg < argc; currentArg++) { if (std::string("--help").compare(argv[currentArg]) == 0) { printUsage(argv); printHelp(); exitRobogen(EXIT_SUCCESS); } else if (std::string("--overwrite").compare(argv[currentArg]) == 0) { overwrite = true; } else if (std::string("--save-all").compare(argv[currentArg]) == 0) { saveAll = true; } else { std::cerr << std::endl << "Invalid option: " << argv[currentArg] << std::endl << std::endl; printUsage(argv); exitRobogen(EXIT_FAILURE); } } init(seed, outputDirectory, confFileName, overwrite, saveAll); } void init(unsigned int seed, std::string outputDirectory, std::string confFileName, bool overwrite, bool saveAll) { // Seed random number generator rng.seed(seed); conf.reset(new EvolverConfiguration()); if (!conf->init(confFileName)) { std::cerr << "Problems parsing the evolution configuration file. Quit." << std::endl; exitRobogen(EXIT_FAILURE); } robotConf = ConfigurationReader::parseConfigurationFile( conf->simulatorConfFile); if (robotConf == NULL) { std::cerr << "Problems parsing the robot configuration file. Quit." << std::endl; exitRobogen(EXIT_FAILURE); } // --------------------------------------- // Set up evolution // --------------------------------------- if (conf->selection == conf->DETERMINISTIC_TOURNAMENT) { selector.reset(new DeterministicTournament(conf->tournamentSize, rng)); } else { std::cerr << "Selection type id " << conf->selection << " unknown." << std::endl; exitRobogen(EXIT_FAILURE); } mutator.reset(new Mutator(conf, rng)); log.reset(new EvolverLog()); try { if (!log->init(conf, robotConf, outputDirectory, overwrite, saveAll)) { std::cerr << "Error creating evolver log. Aborting." << std::endl; exitRobogen(EXIT_FAILURE); } } catch (std::exception& e) { std::cerr << e.what() << std::endl; exitRobogen(EXIT_FAILURE); } catch (...) { std::cerr << "non standard exception " << std::endl; exitRobogen(EXIT_FAILURE); } // --------------------------------------- // parse robot from file & initialize population // --------------------------------------- boost::shared_ptr<RobotRepresentation> referenceBot( new RobotRepresentation()); bool growBodies = false; if (conf->evolutionMode == EvolverConfiguration::BRAIN_EVOLVER && conf->referenceRobotFile.compare("") == 0) { std::cerr << "Trying to evolve brain, but no robot file provided." << std::endl; exitRobogen(EXIT_FAILURE); } else if (conf->referenceRobotFile.compare("") != 0) { if (!referenceBot->init(conf->referenceRobotFile)) { std::cerr << "Failed interpreting robot from text file" << std::endl; exitRobogen(EXIT_FAILURE); } } else { //doing body evolution and don't have a reference robot if (referenceBot->init()) { growBodies = true; } else { std::cerr << "Failed creating base robot for body evolution" << std::endl; exitRobogen(EXIT_FAILURE); } } neat = (conf->evolutionaryAlgorithm == EvolverConfiguration::HYPER_NEAT); population.reset(new Population()); if (!population->init(referenceBot, conf->mu, mutator, growBodies, (!(conf->useBrainSeed || neat)) ) ) { std::cerr << "Error when initializing population!" << std::endl; exitRobogen(EXIT_FAILURE); } if (neat) { neatContainer.reset(new NeatContainer(conf, population, seed, rng)); } // --------------------------------------- // open sockets for communication with simulator processes // --------------------------------------- #ifndef EMSCRIPTEN sockets.resize(conf->sockets.size()); for (unsigned int i = 0; i < conf->sockets.size(); i++) { sockets[i] = new TcpSocket; #ifndef FAKEROBOTREPRESENTATION_H // do not bother with sockets when using // benchmark if (!sockets[i]->open(conf->sockets[i].first, conf->sockets[i].second)) { std::cerr << "Could not open connection to simulator" << std::endl; exitRobogen(EXIT_FAILURE); } #endif } #endif // --------------------------------------- // run evolution TODO stopping criterion // --------------------------------------- if(neat) { if(!neatContainer->fillPopulationWeights(population)) { std::cerr << "Filling weights from NEAT failed." << std::endl; exitRobogen(EXIT_FAILURE); } } generation = 1; population->evaluate(robotConf, sockets); } void mainEvolutionLoop(); void postEvaluateNEAT() { population->sort(true); mainEvolutionLoop(); } void postEvaluateStd() { // comma or plus? if (conf->replacement == conf->PLUS_REPLACEMENT) { children += *population.get(); } // replace population.reset(new Population()); if (!population->init(children, conf->mu)) { std::cout << "Error when initializing population!" << std::endl; exitRobogen(EXIT_FAILURE); } mainEvolutionLoop(); } void triggerPostEvaluate() { if (generation == 1) { mainEvolutionLoop(); } else { if (neat) { postEvaluateNEAT(); } else { postEvaluateStd(); } } } void mainEvolutionLoop() { #ifdef EMSCRIPTEN std::stringstream ss; double best, average, stddev; population->getStat(best, average, stddev); ss << "{best : " << best << ", average : " << average << ", stddev : " << stddev << ", generation : " << generation << "}"; sendJSEvent("stats", ss.str()); #endif std::cout << "mainEvolutionLoop" << std::endl; if (!log->logGeneration(generation, *population.get())) { exitRobogen(EXIT_FAILURE); } generation++; if (generation <= conf->numGenerations) { std::cout << "Generation " << generation << std::endl; children.clear(); // create children if (neat) { //neatPopulation->Epoch(); if(!neatContainer->produceNextGeneration(population)) { std::cerr << "Producing next generation from NEAT failed." << std::endl; exitRobogen(EXIT_FAILURE); } population->evaluate(robotConf, sockets); } else { selector->initPopulation(population); unsigned int numOffspring = 0; while (numOffspring < conf->lambda) { std::pair<boost::shared_ptr<RobotRepresentation>, boost::shared_ptr<RobotRepresentation> > selection; if (!selector->select(selection.first)) { std::cerr << "Selector::select() failed." << std::endl; exitRobogen(EXIT_FAILURE); } unsigned int tries = 0; do { if (tries > 10000) { std::cerr << "Selecting second parent failed after " "10000 tries, giving up."; exitRobogen(EXIT_FAILURE); } if (!selector->select(selection.second)) { std::cerr << "Selector::select() failed." << std::endl; exitRobogen(EXIT_FAILURE); } tries++; } while (selection.first == selection.second); std::vector<boost::shared_ptr<RobotRepresentation> > offspring = mutator->createOffspring(selection.first, selection.second); // no crossover, or can fit both new individuals if ( (numOffspring + offspring.size()) <= conf->lambda ) { children.insert(children.end(), offspring.begin(), offspring.end() ); numOffspring += offspring.size(); } else { // crossover, but can only fit one children.push_back(offspring[0]); numOffspring++; } } children.evaluate(robotConf, sockets); } #ifndef EMSCRIPTEN triggerPostEvaluate(); #endif } else { #ifdef EMSCRIPTEN sendJSEvent("evolutionTerminated", "{}"); #endif } } #ifdef EMSCRIPTEN void EMSCRIPTEN_KEEPALIVE evaluationResultAvailable(int ptr, double fitness) { RobotRepresentation* robot = (RobotRepresentation*) ptr; robot->asyncEvaluateResult(fitness); } void EMSCRIPTEN_KEEPALIVE evaluationIsDone() { triggerPostEvaluate(); } #endif }
int main(int argc, char *argv[]) { startRobogen(); // --------------------------------------- // verify usage and load configuration // --------------------------------------- if (argc > 1 && std::string(argv[1]) == "--help") { printUsage(argv); printHelp(); exitRobogen(EXIT_SUCCESS); } if ((argc < 4)) { printUsage(argv); std::cout << "RUN: " << std::endl << std::endl << " " << std::string(argv[0]) << " --help to see all configuration options." << std::endl << std::endl; exitRobogen(EXIT_FAILURE); } unsigned int seed = atoi(argv[1]); std::string outputDirectory = std::string(argv[2]); std::string confFileName = std::string(argv[3]); bool overwrite = false; bool saveAll = false; int currentArg = 4; for (; currentArg<argc; currentArg++) { if (std::string("--help").compare(argv[currentArg]) == 0) { printUsage(argv); printHelp(); return EXIT_SUCCESS; } else if (std::string("--overwrite").compare(argv[currentArg]) == 0) { overwrite = true; } else if (std::string("--save-all").compare(argv[currentArg]) == 0) { saveAll = true; } else { std::cerr << std::endl << "Invalid option: " << argv[currentArg] << std::endl << std::endl; printUsage(argv); exitRobogen(EXIT_FAILURE); } } // Create random number generator boost::random::mt19937 rng; rng.seed(seed); boost::shared_ptr<EvolverConfiguration> conf = boost::shared_ptr<EvolverConfiguration>(new EvolverConfiguration()); if (!conf->init(confFileName)) { std::cerr << "Problems parsing the evolution configuration file. Quit." << std::endl; exitRobogen(EXIT_FAILURE); } boost::shared_ptr<RobogenConfig> robotConf = ConfigurationReader::parseConfigurationFile( conf->simulatorConfFile); if (robotConf == NULL) { std::cerr << "Problems parsing the robot configuration file. Quit." << std::endl; exitRobogen(EXIT_FAILURE); } // --------------------------------------- // Set up evolution // --------------------------------------- boost::shared_ptr<Selector> selector; if (conf->selection == conf->DETERMINISTIC_TOURNAMENT) { selector.reset(new DeterministicTournament(conf->tournamentSize, rng)); } else { std::cerr << "Selection type id " << conf->selection << " unknown." << std::endl; exitRobogen(EXIT_FAILURE); } boost::shared_ptr<Mutator> mutator = boost::shared_ptr<Mutator>( new Mutator(conf, rng)); boost::shared_ptr<EvolverLog> log(new EvolverLog()); if (!log->init(conf, robotConf, outputDirectory, overwrite, saveAll)) { std::cout << "Error creating evolver log. Aborting." << std::endl; return EXIT_FAILURE; } // --------------------------------------- // parse robot from file & initialize population // --------------------------------------- boost::shared_ptr<RobotRepresentation> referenceBot( new RobotRepresentation()); bool growBodies = false; if (conf->evolutionMode == EvolverConfiguration::BRAIN_EVOLVER && conf->referenceRobotFile.compare("") == 0) { std::cerr << "Trying to evolve brain, but no robot file provided." << std::endl; exitRobogen(EXIT_FAILURE); } else if (conf->referenceRobotFile.compare("") != 0) { if (!referenceBot->init(conf->referenceRobotFile)) { std::cerr << "Failed interpreting robot from text file" << std::endl; exitRobogen(EXIT_FAILURE); } } else { //doing body evolution and don't have a reference robot if (referenceBot->init()) { growBodies = true; } else { std::cerr << "Failed creating base robot for body evolution" << std::endl; exitRobogen(EXIT_FAILURE); } } boost::shared_ptr<Population> population(new Population()); boost::shared_ptr<NeatContainer> neatContainer; bool neat = (conf->evolutionaryAlgorithm == EvolverConfiguration::HYPER_NEAT); if (!population->init(referenceBot, conf->mu, mutator, growBodies, (!(conf->useBrainSeed || neat)) ) ) { std::cerr << "Error when initializing population!" << std::endl; exitRobogen(EXIT_FAILURE); } if (neat) { neatContainer.reset(new NeatContainer(conf, population, seed, rng)); } // --------------------------------------- // open sockets for communication with simulator processes // --------------------------------------- std::vector<TcpSocket*> sockets(conf->sockets.size()); for (unsigned int i = 0; i < conf->sockets.size(); i++) { sockets[i] = new TcpSocket; #ifndef FAKEROBOTREPRESENTATION_H // do not bother with sockets when using // benchmark if (!sockets[i]->open(conf->sockets[i].first, conf->sockets[i].second)) { std::cerr << "Could not open connection to simulator" << std::endl; exitRobogen(EXIT_FAILURE); } #endif } // --------------------------------------- // run evolution TODO stopping criterion // --------------------------------------- if(neat) { if(!neatContainer->fillPopulationWeights(population)) { std::cerr << "Filling weights from NEAT failed." << std::endl; exitRobogen(EXIT_FAILURE); } } population->evaluate(robotConf, sockets); if (!log->logGeneration(1, *population.get())) { exitRobogen(EXIT_FAILURE); } for (unsigned int generation = 2; generation <= conf->numGenerations; ++generation) { // create children IndividualContainer children; if (neat) { //neatPopulation->Epoch(); if(!neatContainer->produceNextGeneration(population)) { std::cerr << "Producing next generation from NEAT failed." << std::endl; exitRobogen(EXIT_FAILURE); } population->evaluate(robotConf, sockets); population->sort(true); } else { selector->initPopulation(population); for (unsigned int i = 0; i < conf->lambda; i++) { std::pair<boost::shared_ptr<RobotRepresentation>, boost::shared_ptr<RobotRepresentation> > selection; if (!selector->select(selection)) { std::cerr << "Selector::select() failed." << std::endl; exitRobogen(EXIT_FAILURE); } children.push_back( mutator->mutate(selection.first, selection.second)); } // evaluate children children.evaluate(robotConf, sockets); // comma or plus? if (conf->replacement == conf->PLUS_REPLACEMENT) { children += *population.get(); } // replace population.reset(new Population()); if (!population->init(children, conf->mu)) { std::cerr << "Error when initializing population!" << std::endl; exitRobogen(EXIT_FAILURE); } } if (!log->logGeneration(generation, *population.get())) { exitRobogen(EXIT_FAILURE); } } // Clean up sockets for (unsigned int i = 0; i < conf->sockets.size(); i++) { delete sockets[i]; } exitRobogen(EXIT_SUCCESS); }
void mainEvolutionLoop() { #ifdef EMSCRIPTEN std::stringstream ss; double best, average, stddev; population->getStat(best, average, stddev); ss << "{best : " << best << ", average : " << average << ", stddev : " << stddev << ", generation : " << generation << "}"; sendJSEvent("stats", ss.str()); #endif std::cout << "mainEvolutionLoop" << std::endl; if (!log->logGeneration(generation, *population.get())) { exitRobogen(EXIT_FAILURE); } generation++; if (generation <= conf->numGenerations) { std::cout << "Generation " << generation << std::endl; children.clear(); // create children if (neat) { //neatPopulation->Epoch(); if(!neatContainer->produceNextGeneration(population)) { std::cerr << "Producing next generation from NEAT failed." << std::endl; exitRobogen(EXIT_FAILURE); } population->evaluate(robotConf, sockets); } else { selector->initPopulation(population); unsigned int numOffspring = 0; while (numOffspring < conf->lambda) { std::pair<boost::shared_ptr<RobotRepresentation>, boost::shared_ptr<RobotRepresentation> > selection; if (!selector->select(selection.first)) { std::cerr << "Selector::select() failed." << std::endl; exitRobogen(EXIT_FAILURE); } unsigned int tries = 0; do { if (tries > 10000) { std::cerr << "Selecting second parent failed after " "10000 tries, giving up."; exitRobogen(EXIT_FAILURE); } if (!selector->select(selection.second)) { std::cerr << "Selector::select() failed." << std::endl; exitRobogen(EXIT_FAILURE); } tries++; } while (selection.first == selection.second); std::vector<boost::shared_ptr<RobotRepresentation> > offspring = mutator->createOffspring(selection.first, selection.second); // no crossover, or can fit both new individuals if ( (numOffspring + offspring.size()) <= conf->lambda ) { children.insert(children.end(), offspring.begin(), offspring.end() ); numOffspring += offspring.size(); } else { // crossover, but can only fit one children.push_back(offspring[0]); numOffspring++; } } children.evaluate(robotConf, sockets); } #ifndef EMSCRIPTEN triggerPostEvaluate(); #endif } else { #ifdef EMSCRIPTEN sendJSEvent("evolutionTerminated", "{}"); #endif } }