mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
[yul-phaser] AlgorithmRunner: Population autosave
This commit is contained in:
parent
04c7c56d84
commit
1b5960111d
@ -18,9 +18,11 @@
|
|||||||
#include <test/yulPhaser/TestHelpers.h>
|
#include <test/yulPhaser/TestHelpers.h>
|
||||||
|
|
||||||
#include <tools/yulPhaser/AlgorithmRunner.h>
|
#include <tools/yulPhaser/AlgorithmRunner.h>
|
||||||
|
#include <tools/yulPhaser/Common.h>
|
||||||
|
|
||||||
#include <libsolutil/CommonIO.h>
|
#include <libsolutil/CommonIO.h>
|
||||||
|
|
||||||
|
#include <boost/filesystem.hpp>
|
||||||
#include <boost/test/unit_test.hpp>
|
#include <boost/test/unit_test.hpp>
|
||||||
#include <boost/test/tools/output_test_stream.hpp>
|
#include <boost/test/tools/output_test_stream.hpp>
|
||||||
|
|
||||||
@ -29,10 +31,12 @@ using namespace boost::unit_test::framework;
|
|||||||
using namespace boost::test_tools;
|
using namespace boost::test_tools;
|
||||||
using namespace solidity::util;
|
using namespace solidity::util;
|
||||||
|
|
||||||
|
namespace fs = boost::filesystem;
|
||||||
|
|
||||||
namespace solidity::phaser::test
|
namespace solidity::phaser::test
|
||||||
{
|
{
|
||||||
|
|
||||||
class DummyAlgorithm: public GeneticAlgorithm
|
class CountingAlgorithm: public GeneticAlgorithm
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
using GeneticAlgorithm::GeneticAlgorithm;
|
using GeneticAlgorithm::GeneticAlgorithm;
|
||||||
@ -45,6 +49,16 @@ public:
|
|||||||
size_t m_currentRound = 0;
|
size_t m_currentRound = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class RandomisingAlgorithm: public GeneticAlgorithm
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
using GeneticAlgorithm::GeneticAlgorithm;
|
||||||
|
Population runNextRound(Population _population) override
|
||||||
|
{
|
||||||
|
return Population::makeRandom(_population.fitnessMetric(), _population.individuals().size(), 10, 20);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
class AlgorithmRunnerFixture
|
class AlgorithmRunnerFixture
|
||||||
{
|
{
|
||||||
protected:
|
protected:
|
||||||
@ -53,6 +67,25 @@ protected:
|
|||||||
AlgorithmRunner::Options m_options;
|
AlgorithmRunner::Options m_options;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class AlgorithmRunnerAutosaveFixture: public AlgorithmRunnerFixture
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static vector<string> chromosomeStrings(Population const& _population)
|
||||||
|
{
|
||||||
|
vector<string> lines;
|
||||||
|
for (auto const& individual: _population.individuals())
|
||||||
|
lines.push_back(toString(individual.chromosome));
|
||||||
|
|
||||||
|
return lines;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
TemporaryDirectory m_tempDir;
|
||||||
|
string const m_autosavePath = m_tempDir.memberPath("population-autosave.txt");
|
||||||
|
Population const m_population = Population::makeRandom(m_fitnessMetric, 5, 0, 20);
|
||||||
|
RandomisingAlgorithm m_algorithm;
|
||||||
|
};
|
||||||
|
|
||||||
BOOST_AUTO_TEST_SUITE(Phaser)
|
BOOST_AUTO_TEST_SUITE(Phaser)
|
||||||
BOOST_AUTO_TEST_SUITE(AlgorithmRunnerTest)
|
BOOST_AUTO_TEST_SUITE(AlgorithmRunnerTest)
|
||||||
|
|
||||||
@ -60,7 +93,8 @@ BOOST_FIXTURE_TEST_CASE(run_should_call_runNextRound_once_per_round, AlgorithmRu
|
|||||||
{
|
{
|
||||||
m_options.maxRounds = 5;
|
m_options.maxRounds = 5;
|
||||||
AlgorithmRunner runner(Population(m_fitnessMetric), m_options, m_output);
|
AlgorithmRunner runner(Population(m_fitnessMetric), m_options, m_output);
|
||||||
DummyAlgorithm algorithm;
|
|
||||||
|
CountingAlgorithm algorithm;
|
||||||
|
|
||||||
BOOST_TEST(algorithm.m_currentRound == 0);
|
BOOST_TEST(algorithm.m_currentRound == 0);
|
||||||
runner.run(algorithm);
|
runner.run(algorithm);
|
||||||
@ -82,7 +116,7 @@ BOOST_FIXTURE_TEST_CASE(run_should_print_the_top_chromosome, AlgorithmRunnerFixt
|
|||||||
m_output
|
m_output
|
||||||
);
|
);
|
||||||
|
|
||||||
DummyAlgorithm algorithm;
|
CountingAlgorithm algorithm;
|
||||||
|
|
||||||
BOOST_TEST(m_output.is_empty());
|
BOOST_TEST(m_output.is_empty());
|
||||||
runner.run(algorithm);
|
runner.run(algorithm);
|
||||||
@ -93,6 +127,67 @@ BOOST_FIXTURE_TEST_CASE(run_should_print_the_top_chromosome, AlgorithmRunnerFixt
|
|||||||
BOOST_TEST(countSubstringOccurrences(m_output.str(), toString(runner.population().individuals()[0].chromosome)) == 4);
|
BOOST_TEST(countSubstringOccurrences(m_output.str(), toString(runner.population().individuals()[0].chromosome)) == 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BOOST_FIXTURE_TEST_CASE(run_should_save_initial_population_to_file_if_autosave_file_specified, AlgorithmRunnerAutosaveFixture)
|
||||||
|
{
|
||||||
|
m_options.maxRounds = 0;
|
||||||
|
m_options.populationAutosaveFile = m_autosavePath;
|
||||||
|
AlgorithmRunner runner(m_population, m_options, m_output);
|
||||||
|
assert(!fs::exists(m_autosavePath));
|
||||||
|
|
||||||
|
runner.run(m_algorithm);
|
||||||
|
assert(runner.population() == m_population);
|
||||||
|
|
||||||
|
BOOST_TEST(fs::is_regular_file(m_autosavePath));
|
||||||
|
BOOST_TEST(readLinesFromFile(m_autosavePath) == chromosomeStrings(runner.population()));
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_FIXTURE_TEST_CASE(run_should_save_population_to_file_if_autosave_file_specified, AlgorithmRunnerAutosaveFixture)
|
||||||
|
{
|
||||||
|
m_options.maxRounds = 1;
|
||||||
|
m_options.populationAutosaveFile = m_autosavePath;
|
||||||
|
AlgorithmRunner runner(m_population, m_options, m_output);
|
||||||
|
assert(!fs::exists(m_autosavePath));
|
||||||
|
|
||||||
|
runner.run(m_algorithm);
|
||||||
|
assert(runner.population() != m_population);
|
||||||
|
|
||||||
|
BOOST_TEST(fs::is_regular_file(m_autosavePath));
|
||||||
|
BOOST_TEST(readLinesFromFile(m_autosavePath) == chromosomeStrings(runner.population()));
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_FIXTURE_TEST_CASE(run_should_overwrite_existing_file_if_autosave_file_specified, AlgorithmRunnerAutosaveFixture)
|
||||||
|
{
|
||||||
|
m_options.maxRounds = 5;
|
||||||
|
m_options.populationAutosaveFile = m_autosavePath;
|
||||||
|
AlgorithmRunner runner(m_population, m_options, m_output);
|
||||||
|
assert(!fs::exists(m_autosavePath));
|
||||||
|
|
||||||
|
vector<string> originalContent = {"Original content"};
|
||||||
|
{
|
||||||
|
ofstream tmpFile(m_autosavePath);
|
||||||
|
tmpFile << originalContent[0] << endl;
|
||||||
|
}
|
||||||
|
assert(fs::exists(m_autosavePath));
|
||||||
|
assert(readLinesFromFile(m_autosavePath) == originalContent);
|
||||||
|
|
||||||
|
runner.run(m_algorithm);
|
||||||
|
|
||||||
|
BOOST_TEST(fs::is_regular_file(m_autosavePath));
|
||||||
|
BOOST_TEST(readLinesFromFile(m_autosavePath) != originalContent);
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_FIXTURE_TEST_CASE(run_should_not_save_population_to_file_if_autosave_file_not_specified, AlgorithmRunnerAutosaveFixture)
|
||||||
|
{
|
||||||
|
m_options.maxRounds = 5;
|
||||||
|
m_options.populationAutosaveFile = nullopt;
|
||||||
|
AlgorithmRunner runner(m_population, m_options, m_output);
|
||||||
|
assert(!fs::exists(m_autosavePath));
|
||||||
|
|
||||||
|
runner.run(m_algorithm);
|
||||||
|
|
||||||
|
BOOST_TEST(!fs::exists(m_autosavePath));
|
||||||
|
}
|
||||||
|
|
||||||
BOOST_AUTO_TEST_SUITE_END()
|
BOOST_AUTO_TEST_SUITE_END()
|
||||||
BOOST_AUTO_TEST_SUITE_END()
|
BOOST_AUTO_TEST_SUITE_END()
|
||||||
|
|
||||||
|
@ -17,16 +17,50 @@
|
|||||||
|
|
||||||
#include <tools/yulPhaser/AlgorithmRunner.h>
|
#include <tools/yulPhaser/AlgorithmRunner.h>
|
||||||
|
|
||||||
|
#include <tools/yulPhaser/Exceptions.h>
|
||||||
|
|
||||||
|
#include <libsolutil/Assertions.h>
|
||||||
|
|
||||||
|
#include <cerrno>
|
||||||
|
#include <cstring>
|
||||||
|
#include <fstream>
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
using namespace solidity::phaser;
|
using namespace solidity::phaser;
|
||||||
|
|
||||||
void AlgorithmRunner::run(GeneticAlgorithm& _algorithm)
|
void AlgorithmRunner::run(GeneticAlgorithm& _algorithm)
|
||||||
{
|
{
|
||||||
|
populationAutosave();
|
||||||
|
|
||||||
for (size_t round = 0; !m_options.maxRounds.has_value() || round < m_options.maxRounds.value(); ++round)
|
for (size_t round = 0; !m_options.maxRounds.has_value() || round < m_options.maxRounds.value(); ++round)
|
||||||
{
|
{
|
||||||
m_population = _algorithm.runNextRound(m_population);
|
m_population = _algorithm.runNextRound(m_population);
|
||||||
|
|
||||||
m_outputStream << "---------- ROUND " << round + 1 << " ----------" << endl;
|
m_outputStream << "---------- ROUND " << round + 1 << " ----------" << endl;
|
||||||
m_outputStream << m_population;
|
m_outputStream << m_population;
|
||||||
|
|
||||||
|
populationAutosave();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AlgorithmRunner::populationAutosave() const
|
||||||
|
{
|
||||||
|
if (!m_options.populationAutosaveFile.has_value())
|
||||||
|
return;
|
||||||
|
|
||||||
|
ofstream outputStream(m_options.populationAutosaveFile.value(), ios::out | ios::trunc);
|
||||||
|
assertThrow(
|
||||||
|
outputStream.is_open(),
|
||||||
|
FileOpenError,
|
||||||
|
"Could not open file '" + m_options.populationAutosaveFile.value() + "': " + strerror(errno)
|
||||||
|
);
|
||||||
|
|
||||||
|
for (auto& individual: m_population.individuals())
|
||||||
|
outputStream << individual.chromosome << endl;
|
||||||
|
|
||||||
|
assertThrow(
|
||||||
|
!outputStream.bad(),
|
||||||
|
FileWriteError,
|
||||||
|
"Error while writing to file '" + m_options.populationAutosaveFile.value() + "': " + strerror(errno)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
@ -42,6 +42,7 @@ public:
|
|||||||
struct Options
|
struct Options
|
||||||
{
|
{
|
||||||
std::optional<size_t> maxRounds = std::nullopt;
|
std::optional<size_t> maxRounds = std::nullopt;
|
||||||
|
std::optional<std::string> populationAutosaveFile = std::nullopt;
|
||||||
};
|
};
|
||||||
|
|
||||||
AlgorithmRunner(
|
AlgorithmRunner(
|
||||||
@ -59,6 +60,8 @@ public:
|
|||||||
Population const& population() const { return m_population; }
|
Population const& population() const { return m_population; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
void populationAutosave() const;
|
||||||
|
|
||||||
Population m_population;
|
Population m_population;
|
||||||
Options m_options;
|
Options m_options;
|
||||||
std::ostream& m_outputStream;
|
std::ostream& m_outputStream;
|
||||||
|
@ -29,5 +29,6 @@ struct MissingFile: virtual BadInput {};
|
|||||||
|
|
||||||
struct FileOpenError: virtual util::Exception {};
|
struct FileOpenError: virtual util::Exception {};
|
||||||
struct FileReadError: virtual util::Exception {};
|
struct FileReadError: virtual util::Exception {};
|
||||||
|
struct FileWriteError: virtual util::Exception {};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user