mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Merge pull request #9800 from ethereum/yul-phaser-make-tests-less-brittle
Yul phaser make tests less brittle
This commit is contained in:
commit
f264f5474d
@ -73,8 +73,8 @@ BOOST_AUTO_TEST_CASE(makeRandom_should_return_different_chromosome_each_time)
|
||||
BOOST_AUTO_TEST_CASE(makeRandom_should_use_every_possible_step_with_the_same_probability)
|
||||
{
|
||||
SimulationRNG::reset(1);
|
||||
constexpr int samplesPerStep = 100;
|
||||
constexpr double relativeTolerance = 0.01;
|
||||
constexpr int samplesPerStep = 500;
|
||||
constexpr double relativeTolerance = 0.02;
|
||||
|
||||
map<string, size_t> stepIndices = enumerateOptmisationSteps();
|
||||
auto chromosome = Chromosome::makeRandom(stepIndices.size() * samplesPerStep);
|
||||
@ -120,6 +120,15 @@ BOOST_AUTO_TEST_CASE(constructor_should_allow_duplicate_steps)
|
||||
BOOST_TEST(Chromosome("ttfuf").genes() == "ttfuf");
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(constructor_should_allow_genes_that_do_not_correspond_to_any_step)
|
||||
{
|
||||
assert(OptimiserSuite::stepAbbreviationToNameMap().count('.') == 0);
|
||||
assert(OptimiserSuite::stepAbbreviationToNameMap().count('b') == 0);
|
||||
|
||||
BOOST_TEST(Chromosome(".").genes() == ".");
|
||||
BOOST_TEST(Chromosome("a..abatbb").genes() == "a..abatbb");
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(output_operator_should_create_concise_and_unambiguous_string_representation)
|
||||
{
|
||||
vector<string> allSteps;
|
||||
@ -140,8 +149,8 @@ BOOST_AUTO_TEST_CASE(optimisationSteps_should_translate_chromosomes_genes_to_opt
|
||||
BOOST_AUTO_TEST_CASE(randomOptimisationStep_should_return_each_step_with_same_probability)
|
||||
{
|
||||
SimulationRNG::reset(1);
|
||||
constexpr int samplesPerStep = 100;
|
||||
constexpr double relativeTolerance = 0.01;
|
||||
constexpr int samplesPerStep = 500;
|
||||
constexpr double relativeTolerance = 0.02;
|
||||
|
||||
map<string, size_t> stepIndices = enumerateOptmisationSteps();
|
||||
vector<size_t> samples;
|
||||
|
@ -22,6 +22,7 @@
|
||||
#include <tools/yulPhaser/SimulationRNG.h>
|
||||
|
||||
#include <libsolutil/CommonIO.h>
|
||||
#include <libyul/optimiser/Suite.h>
|
||||
|
||||
#include <boost/test/unit_test.hpp>
|
||||
#include <boost/algorithm/string/predicate.hpp>
|
||||
@ -31,6 +32,7 @@
|
||||
|
||||
using namespace std;
|
||||
using namespace solidity::util;
|
||||
using namespace solidity::yul;
|
||||
|
||||
namespace solidity::phaser::test
|
||||
{
|
||||
@ -41,19 +43,32 @@ BOOST_AUTO_TEST_SUITE(GeneRandomisationTest)
|
||||
|
||||
BOOST_AUTO_TEST_CASE(geneRandomisation_should_iterate_over_genes_and_replace_them_with_random_ones_with_given_probability)
|
||||
{
|
||||
Chromosome chromosome("fcCUnDvejs");
|
||||
function<Mutation> mutation01 = geneRandomisation(0.1);
|
||||
function<Mutation> mutation05 = geneRandomisation(0.5);
|
||||
function<Mutation> mutation10 = geneRandomisation(1.0);
|
||||
size_t constexpr inputLength = 1000;
|
||||
double constexpr tolerance = 0.05;
|
||||
|
||||
// Use genes that do not represent valid step abbreviations to be able to easily spot added steps.
|
||||
assert(OptimiserSuite::stepAbbreviationToNameMap().count('.') == 0);
|
||||
Chromosome input = Chromosome(string(inputLength, '.'));
|
||||
|
||||
SimulationRNG::reset(1);
|
||||
BOOST_TEST(countDifferences(mutation01(chromosome), chromosome), 2);
|
||||
BOOST_TEST(countDifferences(mutation05(chromosome), chromosome), 5);
|
||||
BOOST_TEST(countDifferences(mutation10(chromosome), chromosome), 7);
|
||||
SimulationRNG::reset(2);
|
||||
BOOST_TEST(countDifferences(mutation01(chromosome), chromosome), 1);
|
||||
BOOST_TEST(countDifferences(mutation05(chromosome), chromosome), 3);
|
||||
BOOST_TEST(countDifferences(mutation10(chromosome), chromosome), 9);
|
||||
for (size_t randomisationChancePercent = 20; randomisationChancePercent <= 100; randomisationChancePercent += 20)
|
||||
{
|
||||
double const randomisationChance = (randomisationChancePercent / 100.0);
|
||||
|
||||
Chromosome output = geneRandomisation(randomisationChance)(input);
|
||||
string outputGenes = output.genes();
|
||||
BOOST_REQUIRE(output.length() == input.length());
|
||||
|
||||
double const expectedValue = randomisationChance;
|
||||
double const variance = randomisationChance * (1 - randomisationChance);
|
||||
double const randomisedGeneCount = input.length() - static_cast<size_t>(count(outputGenes.begin(), outputGenes.end(), '.'));
|
||||
double const squaredError =
|
||||
(inputLength - randomisedGeneCount) * expectedValue * expectedValue +
|
||||
randomisedGeneCount * (1 - expectedValue) * (1 - expectedValue);
|
||||
|
||||
BOOST_TEST(abs(randomisedGeneCount / inputLength - expectedValue) < tolerance);
|
||||
BOOST_TEST(abs(squaredError / inputLength - variance) < tolerance);
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(geneRandomisation_should_return_identical_chromosome_if_probability_is_zero)
|
||||
@ -66,17 +81,33 @@ BOOST_AUTO_TEST_CASE(geneRandomisation_should_return_identical_chromosome_if_pro
|
||||
|
||||
BOOST_AUTO_TEST_CASE(geneDeletion_should_iterate_over_genes_and_delete_them_with_given_probability)
|
||||
{
|
||||
Chromosome chromosome("fcCUnDvejs");
|
||||
function<Mutation> mutation01 = geneDeletion(0.1);
|
||||
function<Mutation> mutation05 = geneDeletion(0.5);
|
||||
size_t constexpr inputLength = 1000;
|
||||
double constexpr tolerance = 0.05;
|
||||
|
||||
// Use genes that do not represent valid step abbreviations to be able to easily spot added steps.
|
||||
assert(OptimiserSuite::stepAbbreviationToNameMap().count('.') == 0);
|
||||
Chromosome input = Chromosome(string(inputLength, '.'));
|
||||
|
||||
SimulationRNG::reset(1);
|
||||
// fcCUnDvejs
|
||||
BOOST_TEST(mutation01(chromosome) == Chromosome(stripWhitespace("fcCU Dvejs")));
|
||||
BOOST_TEST(mutation05(chromosome) == Chromosome(stripWhitespace(" D ejs")));
|
||||
SimulationRNG::reset(2);
|
||||
BOOST_TEST(mutation01(chromosome) == Chromosome(stripWhitespace("fcUnDvejs")));
|
||||
BOOST_TEST(mutation05(chromosome) == Chromosome(stripWhitespace(" Un s")));
|
||||
for (size_t deletionChancePercent = 20; deletionChancePercent < 100; deletionChancePercent += 20)
|
||||
{
|
||||
double const deletionChance = (deletionChancePercent / 100.0);
|
||||
|
||||
Chromosome output = geneDeletion(deletionChance)(input);
|
||||
string outputGenes = output.genes();
|
||||
BOOST_REQUIRE(output.length() <= input.length());
|
||||
BOOST_REQUIRE(static_cast<size_t>(count(outputGenes.begin(), outputGenes.end(), '.')) == output.length());
|
||||
|
||||
double const expectedValue = deletionChance;
|
||||
double const variance = deletionChance * (1 - deletionChance);
|
||||
double const deletedGeneCount = input.length() - output.length();
|
||||
double const squaredError =
|
||||
(inputLength - deletedGeneCount) * expectedValue * expectedValue +
|
||||
deletedGeneCount * (1 - expectedValue) * (1 - expectedValue);
|
||||
|
||||
BOOST_TEST(abs(deletedGeneCount / inputLength - expectedValue) < tolerance);
|
||||
BOOST_TEST(abs(squaredError / inputLength - variance) < tolerance);
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(geneDeletion_should_return_identical_chromosome_if_probability_is_zero)
|
||||
@ -97,17 +128,37 @@ BOOST_AUTO_TEST_CASE(geneDeletion_should_delete_all_genes_if_probability_is_one)
|
||||
|
||||
BOOST_AUTO_TEST_CASE(geneAddition_should_iterate_over_gene_positions_and_insert_new_genes_with_given_probability)
|
||||
{
|
||||
Chromosome chromosome("fcCUnDvejs");
|
||||
function<Mutation> mutation01 = geneAddition(0.1);
|
||||
function<Mutation> mutation05 = geneAddition(0.5);
|
||||
size_t constexpr inputLength = 1000;
|
||||
double constexpr tolerance = 0.05;
|
||||
size_t constexpr maxAdditions = inputLength + 1;
|
||||
|
||||
// Use genes that do not represent valid step abbreviations to be able to easily spot added steps.
|
||||
assert(OptimiserSuite::stepAbbreviationToNameMap().count('.') == 0);
|
||||
Chromosome input = Chromosome(string(inputLength, '.'));
|
||||
|
||||
SimulationRNG::reset(1);
|
||||
// f c C U n D v e j s
|
||||
BOOST_TEST(mutation01(chromosome) == Chromosome(stripWhitespace(" f c C UC n D v e jx s"))); // 20% more
|
||||
BOOST_TEST(mutation05(chromosome) == Chromosome(stripWhitespace("s f cu C U nj D v eO j sf"))); // 50% more
|
||||
SimulationRNG::reset(2);
|
||||
BOOST_TEST(mutation01(chromosome) == Chromosome(stripWhitespace(" f cp C U n D v e j s"))); // 10% more
|
||||
BOOST_TEST(mutation05(chromosome) == Chromosome(stripWhitespace("M f ce Ce U n D v e jo s"))); // 40% more
|
||||
for (size_t additionChancePercent = 20; additionChancePercent < 100; additionChancePercent += 20)
|
||||
{
|
||||
double const additionChance = (additionChancePercent / 100.0);
|
||||
|
||||
Chromosome output = geneAddition(additionChance)(input);
|
||||
BOOST_REQUIRE(output.length() >= input.length());
|
||||
BOOST_REQUIRE(output.length() <= inputLength + maxAdditions);
|
||||
|
||||
string_view outputGenes = output.genes();
|
||||
size_t preservedGeneCount = static_cast<size_t>(count(outputGenes.begin(), outputGenes.end(), '.'));
|
||||
BOOST_REQUIRE(preservedGeneCount == input.length());
|
||||
|
||||
double const expectedValue = additionChance;
|
||||
double const variance = additionChance * (1 - additionChance);
|
||||
double const addedGeneCount = (output.length() - preservedGeneCount);
|
||||
double const squaredError =
|
||||
(maxAdditions - addedGeneCount) * expectedValue * expectedValue +
|
||||
addedGeneCount * (1 - expectedValue) * (1 - expectedValue);
|
||||
|
||||
BOOST_TEST(abs(addedGeneCount / maxAdditions - expectedValue) < tolerance);
|
||||
BOOST_TEST(abs(squaredError / maxAdditions - variance) < tolerance);
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(geneAddition_should_be_able_to_insert_before_first_position)
|
||||
|
@ -67,6 +67,11 @@ string const& Chromosome::randomOptimisationStep()
|
||||
return stepNames[SimulationRNG::uniformInt(0, stepNames.size() - 1)];
|
||||
}
|
||||
|
||||
char Chromosome::randomGene()
|
||||
{
|
||||
return OptimiserSuite::stepNameToAbbreviationMap().at(randomOptimisationStep());
|
||||
}
|
||||
|
||||
string Chromosome::stepsToGenes(vector<string> const& _optimisationSteps)
|
||||
{
|
||||
string genes;
|
||||
|
@ -44,6 +44,8 @@ public:
|
||||
explicit Chromosome(std::vector<std::string> _optimisationSteps):
|
||||
m_genes(stepsToGenes(_optimisationSteps)) {}
|
||||
explicit Chromosome(std::string _genes):
|
||||
// NOTE: We don't validate the genes - they're only checked at the point of conversion to
|
||||
// actual optimisation steps names. This is very convenient in mutation tests.
|
||||
m_genes(std::move(_genes)) {}
|
||||
static Chromosome makeRandom(size_t _length);
|
||||
|
||||
@ -58,6 +60,7 @@ public:
|
||||
bool operator!=(Chromosome const& _other) const { return !(*this == _other); }
|
||||
|
||||
static std::string const& randomOptimisationStep();
|
||||
static char randomGene();
|
||||
static std::string stepsToGenes(std::vector<std::string> const& _optimisationSteps);
|
||||
static std::vector<std::string> genesToSteps(std::string const& _genes);
|
||||
|
||||
|
@ -36,15 +36,15 @@ function<Mutation> phaser::geneRandomisation(double _chance)
|
||||
{
|
||||
return [=](Chromosome const& _chromosome)
|
||||
{
|
||||
vector<string> optimisationSteps;
|
||||
for (auto const& step: _chromosome.optimisationSteps())
|
||||
optimisationSteps.push_back(
|
||||
string genes;
|
||||
for (char gene: _chromosome.genes())
|
||||
genes.push_back(
|
||||
SimulationRNG::bernoulliTrial(_chance) ?
|
||||
Chromosome::randomOptimisationStep() :
|
||||
step
|
||||
Chromosome::randomGene() :
|
||||
gene
|
||||
);
|
||||
|
||||
return Chromosome(move(optimisationSteps));
|
||||
return Chromosome(move(genes));
|
||||
};
|
||||
}
|
||||
|
||||
@ -52,12 +52,12 @@ function<Mutation> phaser::geneDeletion(double _chance)
|
||||
{
|
||||
return [=](Chromosome const& _chromosome)
|
||||
{
|
||||
vector<string> optimisationSteps;
|
||||
for (auto const& step: _chromosome.optimisationSteps())
|
||||
string genes;
|
||||
for (char gene: _chromosome.genes())
|
||||
if (!SimulationRNG::bernoulliTrial(_chance))
|
||||
optimisationSteps.push_back(step);
|
||||
genes.push_back(gene);
|
||||
|
||||
return Chromosome(move(optimisationSteps));
|
||||
return Chromosome(move(genes));
|
||||
};
|
||||
}
|
||||
|
||||
@ -65,19 +65,19 @@ function<Mutation> phaser::geneAddition(double _chance)
|
||||
{
|
||||
return [=](Chromosome const& _chromosome)
|
||||
{
|
||||
vector<string> optimisationSteps;
|
||||
string genes;
|
||||
|
||||
if (SimulationRNG::bernoulliTrial(_chance))
|
||||
optimisationSteps.push_back(Chromosome::randomOptimisationStep());
|
||||
genes.push_back(Chromosome::randomGene());
|
||||
|
||||
for (auto const& step: _chromosome.optimisationSteps())
|
||||
for (char gene: _chromosome.genes())
|
||||
{
|
||||
optimisationSteps.push_back(step);
|
||||
genes.push_back(gene);
|
||||
if (SimulationRNG::bernoulliTrial(_chance))
|
||||
optimisationSteps.push_back(Chromosome::randomOptimisationStep());
|
||||
genes.push_back(Chromosome::randomGene());
|
||||
}
|
||||
|
||||
return Chromosome(move(optimisationSteps));
|
||||
return Chromosome(move(genes));
|
||||
};
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user