mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
[yul-phaser] Phaser: Accepting multiple input programs
- Use average of metric values for individual programs as the overall metric.
This commit is contained in:
parent
01050940fd
commit
bc46323bed
@ -58,8 +58,16 @@ protected:
|
|||||||
class FitnessMetricFactoryFixture
|
class FitnessMetricFactoryFixture
|
||||||
{
|
{
|
||||||
protected:
|
protected:
|
||||||
CharStream m_sourceStream = CharStream("{}", "");
|
vector<CharStream> m_sourceStreams = {
|
||||||
Program m_program = get<Program>(Program::load(m_sourceStream));
|
CharStream("{}", ""),
|
||||||
|
CharStream("{{}}", ""),
|
||||||
|
CharStream("{{{}}}", ""),
|
||||||
|
};
|
||||||
|
vector<Program> m_programs = {
|
||||||
|
get<Program>(Program::load(m_sourceStreams[0])),
|
||||||
|
get<Program>(Program::load(m_sourceStreams[1])),
|
||||||
|
get<Program>(Program::load(m_sourceStreams[2])),
|
||||||
|
};
|
||||||
FitnessMetricFactory::Options m_options = {
|
FitnessMetricFactory::Options m_options = {
|
||||||
/* metric = */ MetricChoice::CodeSize,
|
/* metric = */ MetricChoice::CodeSize,
|
||||||
/* relativeMetricScale = */ 5,
|
/* relativeMetricScale = */ 5,
|
||||||
@ -144,22 +152,32 @@ BOOST_AUTO_TEST_SUITE(FitnessMetricFactoryTest)
|
|||||||
BOOST_FIXTURE_TEST_CASE(build_should_create_metric_of_the_right_type, FitnessMetricFactoryFixture)
|
BOOST_FIXTURE_TEST_CASE(build_should_create_metric_of_the_right_type, FitnessMetricFactoryFixture)
|
||||||
{
|
{
|
||||||
m_options.metric = MetricChoice::RelativeCodeSize;
|
m_options.metric = MetricChoice::RelativeCodeSize;
|
||||||
unique_ptr<FitnessMetric> metric = FitnessMetricFactory::build(m_options, m_program);
|
unique_ptr<FitnessMetric> metric = FitnessMetricFactory::build(m_options, {m_programs[0]});
|
||||||
BOOST_REQUIRE(metric != nullptr);
|
BOOST_REQUIRE(metric != nullptr);
|
||||||
|
|
||||||
auto relativeProgramSizeMetric = dynamic_cast<RelativeProgramSize*>(metric.get());
|
auto averageMetric = dynamic_cast<FitnessMetricAverage*>(metric.get());
|
||||||
|
BOOST_REQUIRE(averageMetric != nullptr);
|
||||||
|
BOOST_REQUIRE(averageMetric->metrics().size() == 1);
|
||||||
|
BOOST_REQUIRE(averageMetric->metrics()[0] != nullptr);
|
||||||
|
|
||||||
|
auto relativeProgramSizeMetric = dynamic_cast<RelativeProgramSize*>(averageMetric->metrics()[0].get());
|
||||||
BOOST_REQUIRE(relativeProgramSizeMetric != nullptr);
|
BOOST_REQUIRE(relativeProgramSizeMetric != nullptr);
|
||||||
BOOST_TEST(toString(relativeProgramSizeMetric->program()) == toString(m_program));
|
BOOST_TEST(toString(relativeProgramSizeMetric->program()) == toString(m_programs[0]));
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOST_FIXTURE_TEST_CASE(build_should_respect_chromosome_repetitions_option, FitnessMetricFactoryFixture)
|
BOOST_FIXTURE_TEST_CASE(build_should_respect_chromosome_repetitions_option, FitnessMetricFactoryFixture)
|
||||||
{
|
{
|
||||||
m_options.metric = MetricChoice::CodeSize;
|
m_options.metric = MetricChoice::CodeSize;
|
||||||
m_options.chromosomeRepetitions = 5;
|
m_options.chromosomeRepetitions = 5;
|
||||||
unique_ptr<FitnessMetric> metric = FitnessMetricFactory::build(m_options, m_program);
|
unique_ptr<FitnessMetric> metric = FitnessMetricFactory::build(m_options, {m_programs[0]});
|
||||||
BOOST_REQUIRE(metric != nullptr);
|
BOOST_REQUIRE(metric != nullptr);
|
||||||
|
|
||||||
auto programSizeMetric = dynamic_cast<ProgramSize*>(metric.get());
|
auto averageMetric = dynamic_cast<FitnessMetricAverage*>(metric.get());
|
||||||
|
BOOST_REQUIRE(averageMetric != nullptr);
|
||||||
|
BOOST_REQUIRE(averageMetric->metrics().size() == 1);
|
||||||
|
BOOST_REQUIRE(averageMetric->metrics()[0] != nullptr);
|
||||||
|
|
||||||
|
auto programSizeMetric = dynamic_cast<ProgramSize*>(averageMetric->metrics()[0].get());
|
||||||
BOOST_REQUIRE(programSizeMetric != nullptr);
|
BOOST_REQUIRE(programSizeMetric != nullptr);
|
||||||
BOOST_TEST(programSizeMetric->repetitionCount() == m_options.chromosomeRepetitions);
|
BOOST_TEST(programSizeMetric->repetitionCount() == m_options.chromosomeRepetitions);
|
||||||
}
|
}
|
||||||
@ -168,14 +186,29 @@ BOOST_FIXTURE_TEST_CASE(build_should_set_relative_metric_scale, FitnessMetricFac
|
|||||||
{
|
{
|
||||||
m_options.metric = MetricChoice::RelativeCodeSize;
|
m_options.metric = MetricChoice::RelativeCodeSize;
|
||||||
m_options.relativeMetricScale = 10;
|
m_options.relativeMetricScale = 10;
|
||||||
unique_ptr<FitnessMetric> metric = FitnessMetricFactory::build(m_options, m_program);
|
unique_ptr<FitnessMetric> metric = FitnessMetricFactory::build(m_options, {m_programs[0]});
|
||||||
BOOST_REQUIRE(metric != nullptr);
|
BOOST_REQUIRE(metric != nullptr);
|
||||||
|
|
||||||
auto relativeProgramSizeMetric = dynamic_cast<RelativeProgramSize*>(metric.get());
|
auto averageMetric = dynamic_cast<FitnessMetricAverage*>(metric.get());
|
||||||
|
BOOST_REQUIRE(averageMetric != nullptr);
|
||||||
|
BOOST_REQUIRE(averageMetric->metrics().size() == 1);
|
||||||
|
BOOST_REQUIRE(averageMetric->metrics()[0] != nullptr);
|
||||||
|
|
||||||
|
auto relativeProgramSizeMetric = dynamic_cast<RelativeProgramSize*>(averageMetric->metrics()[0].get());
|
||||||
BOOST_REQUIRE(relativeProgramSizeMetric != nullptr);
|
BOOST_REQUIRE(relativeProgramSizeMetric != nullptr);
|
||||||
BOOST_TEST(relativeProgramSizeMetric->fixedPointPrecision() == m_options.relativeMetricScale);
|
BOOST_TEST(relativeProgramSizeMetric->fixedPointPrecision() == m_options.relativeMetricScale);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BOOST_FIXTURE_TEST_CASE(build_should_create_metric_for_each_input_program, FitnessMetricFactoryFixture)
|
||||||
|
{
|
||||||
|
unique_ptr<FitnessMetric> metric = FitnessMetricFactory::build(m_options, m_programs);
|
||||||
|
BOOST_REQUIRE(metric != nullptr);
|
||||||
|
|
||||||
|
auto combinedMetric = dynamic_cast<FitnessMetricCombination*>(metric.get());
|
||||||
|
BOOST_REQUIRE(combinedMetric != nullptr);
|
||||||
|
BOOST_REQUIRE(combinedMetric->metrics().size() == m_programs.size());
|
||||||
|
}
|
||||||
|
|
||||||
BOOST_AUTO_TEST_SUITE_END()
|
BOOST_AUTO_TEST_SUITE_END()
|
||||||
BOOST_AUTO_TEST_SUITE(PopulationFactoryTest)
|
BOOST_AUTO_TEST_SUITE(PopulationFactoryTest)
|
||||||
|
|
||||||
@ -283,20 +316,30 @@ BOOST_FIXTURE_TEST_CASE(build_should_combine_populations_from_all_sources, Poula
|
|||||||
BOOST_AUTO_TEST_SUITE_END()
|
BOOST_AUTO_TEST_SUITE_END()
|
||||||
BOOST_AUTO_TEST_SUITE(ProgramFactoryTest)
|
BOOST_AUTO_TEST_SUITE(ProgramFactoryTest)
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(build_should_load_program_from_file)
|
BOOST_AUTO_TEST_CASE(build_should_load_programs_from_files)
|
||||||
{
|
{
|
||||||
TemporaryDirectory tempDir;
|
TemporaryDirectory tempDir;
|
||||||
|
vector<string> sources{"{}", "{{}}", "{{{}}}"};
|
||||||
|
ProgramFactory::Options options{/* inputFiles = */ {
|
||||||
|
tempDir.memberPath("program1.yul"),
|
||||||
|
tempDir.memberPath("program2.yul"),
|
||||||
|
tempDir.memberPath("program3.yul"),
|
||||||
|
}};
|
||||||
|
|
||||||
|
for (size_t i = 0; i < sources.size(); ++i)
|
||||||
{
|
{
|
||||||
ofstream tmpFile(tempDir.memberPath("program.yul"));
|
ofstream tmpFile(options.inputFiles[i]);
|
||||||
tmpFile << "{}" << endl;
|
tmpFile << sources[i] << endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
ProgramFactory::Options options{/* inputFile = */ tempDir.memberPath("program.yul")};
|
vector<Program> programs = ProgramFactory::build(options);
|
||||||
CharStream expectedProgramSource("{}", "");
|
|
||||||
|
|
||||||
auto program = ProgramFactory::build(options);
|
BOOST_TEST(programs.size() == sources.size());
|
||||||
|
for (size_t i = 0; i < sources.size(); ++i)
|
||||||
BOOST_TEST(toString(program) == toString(get<Program>(Program::load(expectedProgramSource))));
|
{
|
||||||
|
CharStream sourceStream(sources[i], options.inputFiles[i]);
|
||||||
|
BOOST_TEST(toString(programs[i]) == toString(get<Program>(Program::load(sourceStream))));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOST_AUTO_TEST_SUITE_END()
|
BOOST_AUTO_TEST_SUITE_END()
|
||||||
|
@ -146,25 +146,39 @@ FitnessMetricFactory::Options FitnessMetricFactory::Options::fromCommandLine(po:
|
|||||||
|
|
||||||
unique_ptr<FitnessMetric> FitnessMetricFactory::build(
|
unique_ptr<FitnessMetric> FitnessMetricFactory::build(
|
||||||
Options const& _options,
|
Options const& _options,
|
||||||
Program _program
|
vector<Program> _programs
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
|
assert(_programs.size() > 0 && "Validations should prevent this from being executed with zero files.");
|
||||||
|
|
||||||
|
vector<shared_ptr<FitnessMetric>> metrics;
|
||||||
switch (_options.metric)
|
switch (_options.metric)
|
||||||
{
|
{
|
||||||
case MetricChoice::CodeSize:
|
case MetricChoice::CodeSize:
|
||||||
return make_unique<ProgramSize>(
|
{
|
||||||
move(_program),
|
for (Program& program: _programs)
|
||||||
|
metrics.push_back(make_unique<ProgramSize>(
|
||||||
|
move(program),
|
||||||
_options.chromosomeRepetitions
|
_options.chromosomeRepetitions
|
||||||
);
|
));
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
case MetricChoice::RelativeCodeSize:
|
case MetricChoice::RelativeCodeSize:
|
||||||
return make_unique<RelativeProgramSize>(
|
{
|
||||||
move(_program),
|
for (Program& program: _programs)
|
||||||
|
metrics.push_back(make_unique<RelativeProgramSize>(
|
||||||
|
move(program),
|
||||||
_options.relativeMetricScale,
|
_options.relativeMetricScale,
|
||||||
_options.chromosomeRepetitions
|
_options.chromosomeRepetitions
|
||||||
);
|
));
|
||||||
|
break;
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
assertThrow(false, solidity::util::Exception, "Invalid MetricChoice value.");
|
assertThrow(false, solidity::util::Exception, "Invalid MetricChoice value.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return make_unique<FitnessMetricAverage>(move(metrics));
|
||||||
}
|
}
|
||||||
|
|
||||||
PopulationFactory::Options PopulationFactory::Options::fromCommandLine(po::variables_map const& _arguments)
|
PopulationFactory::Options PopulationFactory::Options::fromCommandLine(po::variables_map const& _arguments)
|
||||||
@ -246,20 +260,26 @@ Population PopulationFactory::buildFromFile(
|
|||||||
ProgramFactory::Options ProgramFactory::Options::fromCommandLine(po::variables_map const& _arguments)
|
ProgramFactory::Options ProgramFactory::Options::fromCommandLine(po::variables_map const& _arguments)
|
||||||
{
|
{
|
||||||
return {
|
return {
|
||||||
_arguments["input-file"].as<string>(),
|
_arguments["input-files"].as<vector<string>>(),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
Program ProgramFactory::build(Options const& _options)
|
vector<Program> ProgramFactory::build(Options const& _options)
|
||||||
{
|
{
|
||||||
CharStream sourceCode = loadSource(_options.inputFile);
|
vector<Program> inputPrograms;
|
||||||
|
for (auto& path: _options.inputFiles)
|
||||||
|
{
|
||||||
|
CharStream sourceCode = loadSource(path);
|
||||||
variant<Program, ErrorList> programOrErrors = Program::load(sourceCode);
|
variant<Program, ErrorList> programOrErrors = Program::load(sourceCode);
|
||||||
if (holds_alternative<ErrorList>(programOrErrors))
|
if (holds_alternative<ErrorList>(programOrErrors))
|
||||||
{
|
{
|
||||||
cerr << get<ErrorList>(programOrErrors) << endl;
|
cerr << get<ErrorList>(programOrErrors) << endl;
|
||||||
assertThrow(false, InvalidProgram, "Failed to load program " + _options.inputFile);
|
assertThrow(false, InvalidProgram, "Failed to load program " + path);
|
||||||
}
|
}
|
||||||
return move(get<Program>(programOrErrors));
|
inputPrograms.push_back(move(get<Program>(programOrErrors)));
|
||||||
|
}
|
||||||
|
|
||||||
|
return inputPrograms;
|
||||||
}
|
}
|
||||||
|
|
||||||
CharStream ProgramFactory::loadSource(string const& _sourcePath)
|
CharStream ProgramFactory::loadSource(string const& _sourcePath)
|
||||||
@ -303,7 +323,7 @@ Phaser::CommandLineDescription Phaser::buildCommandLineDescription()
|
|||||||
po::options_description generalDescription("GENERAL", lineLength, minDescriptionLength);
|
po::options_description generalDescription("GENERAL", lineLength, minDescriptionLength);
|
||||||
generalDescription.add_options()
|
generalDescription.add_options()
|
||||||
("help", "Show help message and exit.")
|
("help", "Show help message and exit.")
|
||||||
("input-file", po::value<string>()->required()->value_name("<PATH>"), "Input file.")
|
("input-files", po::value<vector<string>>()->required()->value_name("<PATH>"), "Input files.")
|
||||||
("seed", po::value<uint32_t>()->value_name("<NUM>"), "Seed for the random number generator.")
|
("seed", po::value<uint32_t>()->value_name("<NUM>"), "Seed for the random number generator.")
|
||||||
(
|
(
|
||||||
"rounds",
|
"rounds",
|
||||||
@ -443,7 +463,7 @@ Phaser::CommandLineDescription Phaser::buildCommandLineDescription()
|
|||||||
keywordDescription.add(metricsDescription);
|
keywordDescription.add(metricsDescription);
|
||||||
|
|
||||||
po::positional_options_description positionalDescription;
|
po::positional_options_description positionalDescription;
|
||||||
positionalDescription.add("input-file", 1);
|
positionalDescription.add("input-files", -1);
|
||||||
|
|
||||||
return {keywordDescription, positionalDescription};
|
return {keywordDescription, positionalDescription};
|
||||||
}
|
}
|
||||||
@ -465,8 +485,8 @@ optional<po::variables_map> Phaser::parseCommandLine(int _argc, char** _argv)
|
|||||||
return nullopt;
|
return nullopt;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (arguments.count("input-file") == 0)
|
if (arguments.count("input-files") == 0)
|
||||||
assertThrow(false, NoInputFiles, "Missing argument: input-file.");
|
assertThrow(false, NoInputFiles, "Missing argument: input-files.");
|
||||||
|
|
||||||
return arguments;
|
return arguments;
|
||||||
}
|
}
|
||||||
@ -501,8 +521,8 @@ void Phaser::runAlgorithm(po::variables_map const& _arguments)
|
|||||||
auto populationOptions = PopulationFactory::Options::fromCommandLine(_arguments);
|
auto populationOptions = PopulationFactory::Options::fromCommandLine(_arguments);
|
||||||
auto algorithmOptions = GeneticAlgorithmFactory::Options::fromCommandLine(_arguments);
|
auto algorithmOptions = GeneticAlgorithmFactory::Options::fromCommandLine(_arguments);
|
||||||
|
|
||||||
Program program = ProgramFactory::build(programOptions);
|
vector<Program> programs = ProgramFactory::build(programOptions);
|
||||||
unique_ptr<FitnessMetric> fitnessMetric = FitnessMetricFactory::build(metricOptions, move(program));
|
unique_ptr<FitnessMetric> fitnessMetric = FitnessMetricFactory::build(metricOptions, move(programs));
|
||||||
Population population = PopulationFactory::build(populationOptions, move(fitnessMetric));
|
Population population = PopulationFactory::build(populationOptions, move(fitnessMetric));
|
||||||
|
|
||||||
unique_ptr<GeneticAlgorithm> geneticAlgorithm = GeneticAlgorithmFactory::build(
|
unique_ptr<GeneticAlgorithm> geneticAlgorithm = GeneticAlgorithmFactory::build(
|
||||||
|
@ -108,7 +108,7 @@ public:
|
|||||||
|
|
||||||
static std::unique_ptr<FitnessMetric> build(
|
static std::unique_ptr<FitnessMetric> build(
|
||||||
Options const& _options,
|
Options const& _options,
|
||||||
Program _program
|
std::vector<Program> _programs
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -157,12 +157,12 @@ class ProgramFactory
|
|||||||
public:
|
public:
|
||||||
struct Options
|
struct Options
|
||||||
{
|
{
|
||||||
std::string inputFile;
|
std::vector<std::string> inputFiles;
|
||||||
|
|
||||||
static Options fromCommandLine(boost::program_options::variables_map const& _arguments);
|
static Options fromCommandLine(boost::program_options::variables_map const& _arguments);
|
||||||
};
|
};
|
||||||
|
|
||||||
static Program build(Options const& _options);
|
static std::vector<Program> build(Options const& _options);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static langutil::CharStream loadSource(std::string const& _sourcePath);
|
static langutil::CharStream loadSource(std::string const& _sourcePath);
|
||||||
|
Loading…
Reference in New Issue
Block a user