[yul-phaser] Phaser: Refactor object creation in runAlgorithm() into a set of factories

This commit is contained in:
Kamil Śliwak 2020-02-21 17:18:13 +01:00
parent 25e81f6bd3
commit 2d177c7623
2 changed files with 168 additions and 48 deletions

View File

@ -68,10 +68,77 @@ ostream& phaser::operator<<(ostream& _outputStream, Algorithm _algorithm)
return _outputStream; return _outputStream;
} }
namespace GeneticAlgorithmFactory::Options GeneticAlgorithmFactory::Options::fromCommandLine(po::variables_map const& _arguments)
{ {
return {
_arguments["algorithm"].as<Algorithm>(),
};
}
CharStream loadSource(string const& _sourcePath) unique_ptr<GeneticAlgorithm> GeneticAlgorithmFactory::build(
Options const& _options,
size_t _populationSize,
size_t _minChromosomeLength,
size_t _maxChromosomeLength
)
{
assert(_populationSize > 0);
switch (_options.algorithm)
{
case Algorithm::Random:
return make_unique<RandomAlgorithm>(RandomAlgorithm::Options{
/* elitePoolSize = */ 1.0 / _populationSize,
/* minChromosomeLength = */ _minChromosomeLength,
/* maxChromosomeLength = */ _maxChromosomeLength,
});
case Algorithm::GEWEP:
return make_unique<GenerationalElitistWithExclusivePools>(GenerationalElitistWithExclusivePools::Options{
/* mutationPoolSize = */ 0.25,
/* crossoverPoolSize = */ 0.25,
/* randomisationChance = */ 0.9,
/* deletionVsAdditionChance = */ 0.5,
/* percentGenesToRandomise = */ 1.0 / _maxChromosomeLength,
/* percentGenesToAddOrDelete = */ 1.0 / _maxChromosomeLength,
});
default:
assertThrow(false, solidity::util::Exception, "Invalid Algorithm value.");
}
}
unique_ptr<FitnessMetric> FitnessMetricFactory::build(
Program _program
)
{
return make_unique<ProgramSize>(move(_program), RepetitionCount);
}
Population PopulationFactory::build(
shared_ptr<FitnessMetric> _fitnessMetric
)
{
return Population::makeRandom(
move(_fitnessMetric),
PopulationSize,
MinChromosomeLength,
MaxChromosomeLength
);
}
ProgramFactory::Options ProgramFactory::Options::fromCommandLine(po::variables_map const& _arguments)
{
return {
_arguments["input-file"].as<string>(),
};
}
Program ProgramFactory::build(Options const& _options)
{
CharStream sourceCode = loadSource(_options.inputFile);
return Program::load(sourceCode);
}
CharStream ProgramFactory::loadSource(string const& _sourcePath)
{ {
assertThrow(boost::filesystem::exists(_sourcePath), InvalidProgram, "Source file does not exist"); assertThrow(boost::filesystem::exists(_sourcePath), InvalidProgram, "Source file does not exist");
@ -79,8 +146,6 @@ CharStream loadSource(string const& _sourcePath)
return CharStream(sourceCode, _sourcePath); return CharStream(sourceCode, _sourcePath);
} }
}
int Phaser::main(int _argc, char** _argv) int Phaser::main(int _argc, char** _argv)
{ {
CommandLineParsingResult parsingResult = parseCommandLine(_argc, _argv); CommandLineParsingResult parsingResult = parseCommandLine(_argc, _argv);
@ -89,10 +154,7 @@ int Phaser::main(int _argc, char** _argv)
initialiseRNG(parsingResult.arguments); initialiseRNG(parsingResult.arguments);
runAlgorithm( runAlgorithm(parsingResult.arguments);
parsingResult.arguments["input-file"].as<string>(),
parsingResult.arguments["algorithm"].as<Algorithm>()
);
return 0; return 0;
} }
@ -167,46 +229,22 @@ void Phaser::initialiseRNG(po::variables_map const& _arguments)
cout << "Random seed: " << seed << endl; cout << "Random seed: " << seed << endl;
} }
void Phaser::runAlgorithm(string const& _sourcePath, Algorithm _algorithm) void Phaser::runAlgorithm(po::variables_map const& _arguments)
{ {
constexpr size_t populationSize = 20; auto programOptions = ProgramFactory::Options::fromCommandLine(_arguments);
constexpr size_t minChromosomeLength = 12; auto algorithmOptions = GeneticAlgorithmFactory::Options::fromCommandLine(_arguments);
constexpr size_t maxChromosomeLength = 30;
CharStream sourceCode = loadSource(_sourcePath); Program program = ProgramFactory::build(programOptions);
shared_ptr<FitnessMetric> fitnessMetric = make_shared<ProgramSize>(Program::load(sourceCode), 5); unique_ptr<FitnessMetric> fitnessMetric = FitnessMetricFactory::build(move(program));
auto population = Population::makeRandom( Population population = PopulationFactory::build(move(fitnessMetric));
fitnessMetric,
populationSize, unique_ptr<GeneticAlgorithm> geneticAlgorithm = GeneticAlgorithmFactory::build(
minChromosomeLength, algorithmOptions,
maxChromosomeLength population.individuals().size(),
PopulationFactory::MinChromosomeLength,
PopulationFactory::MaxChromosomeLength
); );
AlgorithmRunner algorithmRunner(population, AlgorithmRunner::Options{}, cout); AlgorithmRunner algorithmRunner(population, AlgorithmRunner::Options{}, cout);
switch (_algorithm) algorithmRunner.run(*geneticAlgorithm);
{
case Algorithm::Random:
{
RandomAlgorithm algorithm({
/* elitePoolSize = */ 1.0 / populationSize,
/* minChromosomeLength = */ minChromosomeLength,
/* maxChromosomeLength = */ maxChromosomeLength,
});
algorithmRunner.run(algorithm);
break;
}
case Algorithm::GEWEP:
{
GenerationalElitistWithExclusivePools algorithm({
/* mutationPoolSize = */ 0.25,
/* crossoverPoolSize = */ 0.25,
/* randomisationChance = */ 0.9,
/* deletionVsAdditionChance = */ 0.5,
/* percentGenesToRandomise = */ 1.0 / maxChromosomeLength,
/* percentGenesToAddOrDelete = */ 1.0 / maxChromosomeLength,
});
algorithmRunner.run(algorithm);
break;
}
}
} }

View File

@ -15,7 +15,8 @@
along with solidity. If not, see <http://www.gnu.org/licenses/>. along with solidity. If not, see <http://www.gnu.org/licenses/>.
*/ */
/** /**
* Contains the main class that controls yul-phaser based on command-line parameters. * Contains the main class that controls yul-phaser based on command-line parameters and
* associated factories for building instances of phaser's components.
*/ */
#pragma once #pragma once
@ -23,12 +24,25 @@
#include <boost/program_options.hpp> #include <boost/program_options.hpp>
#include <istream> #include <istream>
#include <memory>
#include <ostream> #include <ostream>
#include <string> #include <string>
namespace solidity::langutil
{
class CharStream;
}
namespace solidity::phaser namespace solidity::phaser
{ {
class FitnessMetric;
class GeneticAlgorithm;
class Population;
class Program;
enum class Algorithm enum class Algorithm
{ {
Random, Random,
@ -38,10 +52,78 @@ enum class Algorithm
std::istream& operator>>(std::istream& _inputStream, solidity::phaser::Algorithm& _algorithm); std::istream& operator>>(std::istream& _inputStream, solidity::phaser::Algorithm& _algorithm);
std::ostream& operator<<(std::ostream& _outputStream, solidity::phaser::Algorithm _algorithm); std::ostream& operator<<(std::ostream& _outputStream, solidity::phaser::Algorithm _algorithm);
/**
* Builds and validates instances of @a GeneticAlgorithm and its derived classes.
*/
class GeneticAlgorithmFactory
{
public:
struct Options
{
Algorithm algorithm;
static Options fromCommandLine(boost::program_options::variables_map const& _arguments);
};
static std::unique_ptr<GeneticAlgorithm> build(
Options const& _options,
size_t _populationSize,
size_t _minChromosomeLength,
size_t _maxChromosomeLength
);
};
/**
* Builds and validates instances of @a FitnessMetric and its derived classes.
*/
class FitnessMetricFactory
{
public:
static constexpr size_t RepetitionCount = 5;
static std::unique_ptr<FitnessMetric> build(
Program _program
);
};
/**
* Builds and validates instances of @a Population.
*/
class PopulationFactory
{
public:
static constexpr size_t PopulationSize = 20;
static constexpr size_t MinChromosomeLength = 12;
static constexpr size_t MaxChromosomeLength = 30;
static Population build(
std::shared_ptr<FitnessMetric> _fitnessMetric
);
};
/**
* Builds and validates instances of @a Program.
*/
class ProgramFactory
{
public:
struct Options
{
std::string inputFile;
static Options fromCommandLine(boost::program_options::variables_map const& _arguments);
};
static Program build(Options const& _options);
private:
static langutil::CharStream loadSource(std::string const& _sourcePath);
};
/** /**
* Main class that controls yul-phaser based on command-line parameters. The class is responsible * Main class that controls yul-phaser based on command-line parameters. The class is responsible
* for command-line parsing, initialisation of global objects (like the random number generator), * for command-line parsing, initialisation of global objects (like the random number generator),
* creating instances of main components and feeding them into @a AlgorithmRunner. * creating instances of main components using factories and feeding them into @a AlgorithmRunner.
*/ */
class Phaser class Phaser
{ {
@ -58,7 +140,7 @@ private:
static CommandLineParsingResult parseCommandLine(int _argc, char** _argv); static CommandLineParsingResult parseCommandLine(int _argc, char** _argv);
static void initialiseRNG(boost::program_options::variables_map const& _arguments); static void initialiseRNG(boost::program_options::variables_map const& _arguments);
static void runAlgorithm(std::string const& _sourcePath, Algorithm _algorithm); static void runAlgorithm(boost::program_options::variables_map const& _arguments);
}; };
} }