From 18f0d6eb9420312d1ec587cdefa4c1716cb47b6d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Thu, 27 Feb 2020 00:40:57 +0100 Subject: [PATCH] [yul-phaser] AlgorithmRunner: Duplicate chromosome randomisation --- test/yulPhaser/AlgorithmRunner.cpp | 49 +++++++++++++++++++++++++++++ tools/yulPhaser/AlgorithmRunner.cpp | 39 +++++++++++++++++++++++ tools/yulPhaser/AlgorithmRunner.h | 9 ++++++ tools/yulPhaser/Phaser.cpp | 3 ++ 4 files changed, 100 insertions(+) diff --git a/test/yulPhaser/AlgorithmRunner.cpp b/test/yulPhaser/AlgorithmRunner.cpp index 7b20d8db4..0b54ad38f 100644 --- a/test/yulPhaser/AlgorithmRunner.cpp +++ b/test/yulPhaser/AlgorithmRunner.cpp @@ -188,6 +188,55 @@ BOOST_FIXTURE_TEST_CASE(run_should_not_save_population_to_file_if_autosave_file_ BOOST_TEST(!fs::exists(m_autosavePath)); } +BOOST_FIXTURE_TEST_CASE(run_should_randomise_duplicate_chromosomes_if_requested, AlgorithmRunnerFixture) +{ + Chromosome duplicate("afc"); + Population population(m_fitnessMetric, {duplicate, duplicate, duplicate}); + CountingAlgorithm algorithm; + + m_options.maxRounds = 1; + m_options.randomiseDuplicates = true; + m_options.minChromosomeLength = 50; + m_options.maxChromosomeLength = 50; + AlgorithmRunner runner(population, m_options, m_output); + + runner.run(algorithm); + + auto const& newIndividuals = runner.population().individuals(); + + BOOST_TEST(newIndividuals.size() == 3); + BOOST_TEST(( + newIndividuals[0].chromosome == duplicate || + newIndividuals[1].chromosome == duplicate || + newIndividuals[2].chromosome == duplicate + )); + BOOST_TEST(newIndividuals[0] != newIndividuals[1]); + BOOST_TEST(newIndividuals[0] != newIndividuals[2]); + BOOST_TEST(newIndividuals[1] != newIndividuals[2]); + + BOOST_TEST((newIndividuals[0].chromosome.length() == 50 || newIndividuals[0].chromosome == duplicate)); + BOOST_TEST((newIndividuals[1].chromosome.length() == 50 || newIndividuals[1].chromosome == duplicate)); + BOOST_TEST((newIndividuals[2].chromosome.length() == 50 || newIndividuals[2].chromosome == duplicate)); +} + +BOOST_FIXTURE_TEST_CASE(run_should_not_randomise_duplicate_chromosomes_if_not_requested, AlgorithmRunnerFixture) +{ + Chromosome duplicate("afc"); + Population population(m_fitnessMetric, {duplicate, duplicate, duplicate}); + CountingAlgorithm algorithm; + + m_options.maxRounds = 1; + m_options.randomiseDuplicates = false; + AlgorithmRunner runner(population, m_options, m_output); + + runner.run(algorithm); + + BOOST_TEST(runner.population().individuals().size() == 3); + BOOST_TEST(runner.population().individuals()[0].chromosome == duplicate); + BOOST_TEST(runner.population().individuals()[1].chromosome == duplicate); + BOOST_TEST(runner.population().individuals()[2].chromosome == duplicate); +} + BOOST_AUTO_TEST_SUITE_END() BOOST_AUTO_TEST_SUITE_END() diff --git a/tools/yulPhaser/AlgorithmRunner.cpp b/tools/yulPhaser/AlgorithmRunner.cpp index a075fa785..b9f22171b 100644 --- a/tools/yulPhaser/AlgorithmRunner.cpp +++ b/tools/yulPhaser/AlgorithmRunner.cpp @@ -35,6 +35,7 @@ void AlgorithmRunner::run(GeneticAlgorithm& _algorithm) for (size_t round = 0; !m_options.maxRounds.has_value() || round < m_options.maxRounds.value(); ++round) { m_population = _algorithm.runNextRound(m_population); + randomiseDuplicates(); m_outputStream << "---------- ROUND " << round + 1 << " ----------" << endl; m_outputStream << m_population; @@ -64,3 +65,41 @@ void AlgorithmRunner::populationAutosave() const "Error while writing to file '" + m_options.populationAutosaveFile.value() + "': " + strerror(errno) ); } + +void AlgorithmRunner::randomiseDuplicates() +{ + if (m_options.randomiseDuplicates) + { + assert(m_options.minChromosomeLength.has_value()); + assert(m_options.maxChromosomeLength.has_value()); + + m_population = randomiseDuplicates( + m_population, + m_options.minChromosomeLength.value(), + m_options.maxChromosomeLength.value() + ); + } +} + +Population AlgorithmRunner::randomiseDuplicates( + Population _population, + size_t _minChromosomeLength, + size_t _maxChromosomeLength +) +{ + if (_population.individuals().size() == 0) + return _population; + + vector chromosomes{_population.individuals()[0].chromosome}; + size_t duplicateCount = 0; + for (size_t i = 1; i < _population.individuals().size(); ++i) + if (_population.individuals()[i].chromosome == _population.individuals()[i - 1].chromosome) + ++duplicateCount; + else + chromosomes.push_back(_population.individuals()[i].chromosome); + + return ( + Population(_population.fitnessMetric(), chromosomes) + + Population::makeRandom(_population.fitnessMetric(), duplicateCount, _minChromosomeLength, _maxChromosomeLength) + ); +} diff --git a/tools/yulPhaser/AlgorithmRunner.h b/tools/yulPhaser/AlgorithmRunner.h index 93c8348d5..ff0d0e3c3 100644 --- a/tools/yulPhaser/AlgorithmRunner.h +++ b/tools/yulPhaser/AlgorithmRunner.h @@ -43,6 +43,9 @@ public: { std::optional maxRounds = std::nullopt; std::optional populationAutosaveFile = std::nullopt; + bool randomiseDuplicates = false; + std::optional minChromosomeLength = std::nullopt; + std::optional maxChromosomeLength = std::nullopt; }; AlgorithmRunner( @@ -61,6 +64,12 @@ public: private: void populationAutosave() const; + void randomiseDuplicates(); + static Population randomiseDuplicates( + Population _population, + size_t _minChromosomeLength, + size_t _maxChromosomeLength + ); Population m_population; Options m_options; diff --git a/tools/yulPhaser/Phaser.cpp b/tools/yulPhaser/Phaser.cpp index b1ee03f56..e8902a1bc 100644 --- a/tools/yulPhaser/Phaser.cpp +++ b/tools/yulPhaser/Phaser.cpp @@ -438,6 +438,9 @@ AlgorithmRunner::Options Phaser::buildAlgorithmRunnerOptions(po::variables_map c return { _arguments.count("rounds") > 0 ? static_cast>(_arguments["rounds"].as()) : nullopt, _arguments.count("population-autosave") > 0 ? static_cast>(_arguments["population-autosave"].as()) : nullopt, + false, + nullopt, + nullopt, }; }