From e4a360947b6b77e7a2844af0db97048bc282c403 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Tue, 25 Feb 2020 20:16:47 +0100 Subject: [PATCH] [yul-phaser] Add FitnessMetricCombination and derived classes for average, sum, min and max --- test/yulPhaser/FitnessMetrics.cpp | 54 ++++++++++++++++++++++++++++ tools/yulPhaser/FitnessMetrics.cpp | 44 +++++++++++++++++++++++ tools/yulPhaser/FitnessMetrics.h | 56 ++++++++++++++++++++++++++++++ 3 files changed, 154 insertions(+) diff --git a/test/yulPhaser/FitnessMetrics.cpp b/test/yulPhaser/FitnessMetrics.cpp index 27997c791..8b62b03b7 100644 --- a/test/yulPhaser/FitnessMetrics.cpp +++ b/test/yulPhaser/FitnessMetrics.cpp @@ -78,6 +78,21 @@ protected: Program m_optimisedProgram = optimisedProgram(m_program); }; +class FitnessMetricCombinationFixture: public ProgramBasedMetricFixture +{ +protected: + vector> m_simpleMetrics = { + make_shared(m_program, 1), + make_shared(m_program, 2), + make_shared(m_program, 3), + }; + vector m_fitness = { + m_simpleMetrics[0]->evaluate(m_chromosome), + m_simpleMetrics[1]->evaluate(m_chromosome), + m_simpleMetrics[2]->evaluate(m_chromosome), + }; +}; + BOOST_AUTO_TEST_SUITE(Phaser) BOOST_AUTO_TEST_SUITE(FitnessMetricsTest) BOOST_AUTO_TEST_SUITE(ProgramBasedMetricTest) @@ -173,6 +188,45 @@ BOOST_FIXTURE_TEST_CASE(evaluate_should_multiply_the_result_by_scaling_factor, P BOOST_TEST(RelativeProgramSize(m_program, 4).evaluate(m_chromosome) == round(10000.0 * sizeRatio)); } +BOOST_AUTO_TEST_SUITE_END() +BOOST_AUTO_TEST_SUITE(FitnessMetricCombinationTest) + +BOOST_FIXTURE_TEST_CASE(FitnessMetricAverage_evaluate_should_compute_average_of_values_returned_by_metrics_passed_to_it, FitnessMetricCombinationFixture) +{ + FitnessMetricAverage metric(m_simpleMetrics); + + assert(m_simpleMetrics.size() == 3); + BOOST_TEST(metric.evaluate(m_chromosome) == (m_fitness[0] + m_fitness[1] + m_fitness[2]) / 3); + BOOST_TEST(metric.metrics() == m_simpleMetrics); +} + +BOOST_FIXTURE_TEST_CASE(FitnessMetricSum_evaluate_should_compute_sum_of_values_returned_by_metrics_passed_to_it, FitnessMetricCombinationFixture) +{ + FitnessMetricSum metric(m_simpleMetrics); + + assert(m_simpleMetrics.size() == 3); + BOOST_TEST(metric.evaluate(m_chromosome) == m_fitness[0] + m_fitness[1] + m_fitness[2]); + BOOST_TEST(metric.metrics() == m_simpleMetrics); +} + +BOOST_FIXTURE_TEST_CASE(FitnessMetricMaximum_evaluate_should_compute_maximum_of_values_returned_by_metrics_passed_to_it, FitnessMetricCombinationFixture) +{ + FitnessMetricMaximum metric(m_simpleMetrics); + + assert(m_simpleMetrics.size() == 3); + BOOST_TEST(metric.evaluate(m_chromosome) == max(m_fitness[0], max(m_fitness[1], m_fitness[2]))); + BOOST_TEST(metric.metrics() == m_simpleMetrics); +} + +BOOST_FIXTURE_TEST_CASE(FitnessMetricMinimum_evaluate_should_compute_minimum_of_values_returned_by_metrics_passed_to_it, FitnessMetricCombinationFixture) +{ + FitnessMetricMinimum metric(m_simpleMetrics); + + assert(m_simpleMetrics.size() == 3); + BOOST_TEST(metric.evaluate(m_chromosome) == min(m_fitness[0], min(m_fitness[1], m_fitness[2]))); + BOOST_TEST(metric.metrics() == m_simpleMetrics); +} + BOOST_AUTO_TEST_SUITE_END() BOOST_AUTO_TEST_SUITE_END() BOOST_AUTO_TEST_SUITE_END() diff --git a/tools/yulPhaser/FitnessMetrics.cpp b/tools/yulPhaser/FitnessMetrics.cpp index 02c3b457f..49482d0af 100644 --- a/tools/yulPhaser/FitnessMetrics.cpp +++ b/tools/yulPhaser/FitnessMetrics.cpp @@ -50,3 +50,47 @@ size_t RelativeProgramSize::evaluate(Chromosome const& _chromosome) static_cast(optimisedSize) / unoptimisedSize * scalingFactor )); } + +size_t FitnessMetricAverage::evaluate(Chromosome const& _chromosome) +{ + assert(m_metrics.size() > 0); + + size_t total = m_metrics[0]->evaluate(_chromosome); + for (size_t i = 1; i < m_metrics.size(); ++i) + total += m_metrics[i]->evaluate(_chromosome); + + return total / m_metrics.size(); +} + +size_t FitnessMetricSum::evaluate(Chromosome const& _chromosome) +{ + assert(m_metrics.size() > 0); + + size_t total = m_metrics[0]->evaluate(_chromosome); + for (size_t i = 1; i < m_metrics.size(); ++i) + total += m_metrics[i]->evaluate(_chromosome); + + return total; +} + +size_t FitnessMetricMaximum::evaluate(Chromosome const& _chromosome) +{ + assert(m_metrics.size() > 0); + + size_t maximum = m_metrics[0]->evaluate(_chromosome); + for (size_t i = 1; i < m_metrics.size(); ++i) + maximum = max(maximum, m_metrics[i]->evaluate(_chromosome)); + + return maximum; +} + +size_t FitnessMetricMinimum::evaluate(Chromosome const& _chromosome) +{ + assert(m_metrics.size() > 0); + + size_t minimum = m_metrics[0]->evaluate(_chromosome); + for (size_t i = 1; i < m_metrics.size(); ++i) + minimum = min(minimum, m_metrics[i]->evaluate(_chromosome)); + + return minimum; +} diff --git a/tools/yulPhaser/FitnessMetrics.h b/tools/yulPhaser/FitnessMetrics.h index 3544dba75..e79d99ff4 100644 --- a/tools/yulPhaser/FitnessMetrics.h +++ b/tools/yulPhaser/FitnessMetrics.h @@ -113,4 +113,60 @@ private: size_t m_fixedPointPrecision; }; +/** + * Abstract base class for fitness metrics that compute their value based on values of multiple + * other, nested metrics. + */ +class FitnessMetricCombination: public FitnessMetric +{ +public: + explicit FitnessMetricCombination(std::vector> _metrics): + m_metrics(std::move(_metrics)) {} + + std::vector> const& metrics() const { return m_metrics; } + +protected: + std::vector> m_metrics; +}; + +/** + * Fitness metric that returns the average of values of its nested metrics. + */ +class FitnessMetricAverage: public FitnessMetricCombination +{ +public: + using FitnessMetricCombination::FitnessMetricCombination; + size_t evaluate(Chromosome const& _chromosome) override; +}; + +/** + * Fitness metric that returns the sum of values of its nested metrics. + */ +class FitnessMetricSum: public FitnessMetricCombination +{ +public: + using FitnessMetricCombination::FitnessMetricCombination; + size_t evaluate(Chromosome const& _chromosome) override; +}; + +/** + * Fitness metric that returns the highest of values of its nested metrics. + */ +class FitnessMetricMaximum: public FitnessMetricCombination +{ +public: + using FitnessMetricCombination::FitnessMetricCombination; + size_t evaluate(Chromosome const& _chromosome) override; +}; + +/** + * Fitness metric that returns the lowest of values of its nested metrics. + */ +class FitnessMetricMinimum: public FitnessMetricCombination +{ +public: + using FitnessMetricCombination::FitnessMetricCombination; + size_t evaluate(Chromosome const& _chromosome) override; +}; + }