diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt
index 3b2fef6f0..70d547a0b 100644
--- a/test/CMakeLists.txt
+++ b/test/CMakeLists.txt
@@ -144,6 +144,7 @@ set(yul_phaser_sources
yulPhaser/CommonTest.cpp
yulPhaser/Chromosome.cpp
yulPhaser/FitnessMetrics.cpp
+ yulPhaser/GeneticAlgorithms.cpp
yulPhaser/Population.cpp
yulPhaser/Program.cpp
yulPhaser/SimulationRNG.cpp
@@ -153,6 +154,7 @@ set(yul_phaser_sources
# unnecessary duplication. Create a library or find a way to reuse the list in both places.
../tools/yulPhaser/Chromosome.cpp
../tools/yulPhaser/FitnessMetrics.cpp
+ ../tools/yulPhaser/GeneticAlgorithms.cpp
../tools/yulPhaser/Population.cpp
../tools/yulPhaser/Program.cpp
../tools/yulPhaser/SimulationRNG.cpp
diff --git a/test/yulPhaser/GeneticAlgorithms.cpp b/test/yulPhaser/GeneticAlgorithms.cpp
new file mode 100644
index 000000000..3528f2be0
--- /dev/null
+++ b/test/yulPhaser/GeneticAlgorithms.cpp
@@ -0,0 +1,96 @@
+/*
+ This file is part of solidity.
+
+ solidity is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ solidity is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with solidity. If not, see .
+*/
+
+#include
+
+#include
+#include
+#include
+#include
+
+#include
+
+#include
+
+#include
+#include
+
+#include
+
+using namespace std;
+using namespace boost::unit_test::framework;
+using namespace boost::test_tools;
+using namespace solidity::langutil;
+using namespace solidity::util;
+
+namespace solidity::phaser::test
+{
+
+class DummyAlgorithm: public GeneticAlgorithm
+{
+public:
+ using GeneticAlgorithm::GeneticAlgorithm;
+ void runNextRound() override { ++m_currentRound; }
+
+ size_t m_currentRound = 0;
+};
+
+class GeneticAlgorithmFixture
+{
+protected:
+ shared_ptr m_fitnessMetric = make_shared();
+ output_test_stream m_output;
+};
+
+BOOST_AUTO_TEST_SUITE(Phaser)
+BOOST_AUTO_TEST_SUITE(GeneticAlgorithmsTest)
+BOOST_AUTO_TEST_SUITE(GeneticAlgorithmTest)
+
+BOOST_FIXTURE_TEST_CASE(run_should_call_runNextRound_once_per_round, GeneticAlgorithmFixture)
+{
+ DummyAlgorithm algorithm(Population(m_fitnessMetric), m_output);
+
+ BOOST_TEST(algorithm.m_currentRound == 0);
+ algorithm.run(10);
+ BOOST_TEST(algorithm.m_currentRound == 10);
+ algorithm.run(3);
+ BOOST_TEST(algorithm.m_currentRound == 13);
+}
+
+BOOST_FIXTURE_TEST_CASE(run_should_print_the_top_chromosome, GeneticAlgorithmFixture)
+{
+ // run() is allowed to print more but should at least print the first one
+
+ DummyAlgorithm algorithm(
+ // NOTE: Chromosomes chosen so that they're not substrings of each other and are not
+ // words likely to appear in the output in normal circumstances.
+ Population(m_fitnessMetric, {Chromosome("fcCUnDve"), Chromosome("jsxIOo"), Chromosome("ighTLM")}),
+ m_output
+ );
+
+ BOOST_TEST(m_output.is_empty());
+ algorithm.run(1);
+ BOOST_TEST(countSubstringOccurrences(m_output.str(), toString(algorithm.population().individuals()[0].chromosome)) == 1);
+ algorithm.run(3);
+ BOOST_TEST(countSubstringOccurrences(m_output.str(), toString(algorithm.population().individuals()[0].chromosome)) == 4);
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+BOOST_AUTO_TEST_SUITE_END()
+BOOST_AUTO_TEST_SUITE_END()
+
+}
diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt
index d3101ad7b..601b249e6 100644
--- a/tools/CMakeLists.txt
+++ b/tools/CMakeLists.txt
@@ -15,6 +15,8 @@ install(TARGETS solidity-upgrade DESTINATION "${CMAKE_INSTALL_BINDIR}")
add_executable(yul-phaser
yulPhaser/main.cpp
+ yulPhaser/GeneticAlgorithms.h
+ yulPhaser/GeneticAlgorithms.cpp
yulPhaser/Population.h
yulPhaser/Population.cpp
yulPhaser/FitnessMetrics.h
diff --git a/tools/yulPhaser/GeneticAlgorithms.cpp b/tools/yulPhaser/GeneticAlgorithms.cpp
new file mode 100644
index 000000000..6e69565f4
--- /dev/null
+++ b/tools/yulPhaser/GeneticAlgorithms.cpp
@@ -0,0 +1,32 @@
+/*
+ This file is part of solidity.
+
+ solidity is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ solidity is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with solidity. If not, see .
+*/
+
+#include
+
+using namespace std;
+using namespace solidity::phaser;
+
+void GeneticAlgorithm::run(optional _numRounds)
+{
+ for (size_t round = 0; !_numRounds.has_value() || round < _numRounds.value(); ++round)
+ {
+ runNextRound();
+
+ m_outputStream << "---------- ROUND " << round << " ----------" << endl;
+ m_outputStream << m_population;
+ }
+}
diff --git a/tools/yulPhaser/GeneticAlgorithms.h b/tools/yulPhaser/GeneticAlgorithms.h
new file mode 100644
index 000000000..c2700416b
--- /dev/null
+++ b/tools/yulPhaser/GeneticAlgorithms.h
@@ -0,0 +1,66 @@
+/*
+ This file is part of solidity.
+
+ solidity is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ solidity is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with solidity. If not, see .
+*/
+/**
+ * Contains an abstract base class representing a genetic algorithm and its concrete implementations.
+ */
+
+#pragma once
+
+#include
+
+#include
+#include
+
+namespace solidity::phaser
+{
+
+/**
+ * Abstract base class for genetic algorithms.
+ *
+ * The main feature is the @a run() method that executes the algorithm, updating the internal
+ * population during each round and printing the results to the stream provided to the constructor.
+ *
+ * Derived classes can provide specific methods for updating the population by implementing
+ * the @a runNextRound() method.
+ */
+class GeneticAlgorithm
+{
+public:
+ GeneticAlgorithm(Population _initialPopulation, std::ostream& _outputStream):
+ m_population(std::move(_initialPopulation)),
+ m_outputStream(_outputStream) {}
+
+ GeneticAlgorithm(GeneticAlgorithm const&) = delete;
+ GeneticAlgorithm& operator=(GeneticAlgorithm const&) = delete;
+ virtual ~GeneticAlgorithm() = default;
+
+ Population const& population() const { return m_population; }
+
+ void run(std::optional _numRounds = std::nullopt);
+
+ /// The method that actually implements the algorithm. Should use @a m_population as input and
+ /// replace it with the updated state after the round.
+ virtual void runNextRound() = 0;
+
+protected:
+ Population m_population;
+
+private:
+ std::ostream& m_outputStream;
+};
+
+}