[yul-phaser] Population: Add symmetricCrossoverWithRemainder()

This commit is contained in:
Kamil Śliwak 2020-03-11 02:13:55 +01:00
parent 59011fcde6
commit ef8d0888af
3 changed files with 90 additions and 0 deletions

View File

@ -48,6 +48,14 @@ namespace solidity::phaser::test
class PopulationFixture
{
protected:
static ChromosomePair twoStepSwap(Chromosome const& _chromosome1, Chromosome const& _chromosome2)
{
return ChromosomePair{
Chromosome(vector<string>{_chromosome1.optimisationSteps()[0], _chromosome2.optimisationSteps()[1]}),
Chromosome(vector<string>{_chromosome2.optimisationSteps()[0], _chromosome1.optimisationSteps()[1]}),
};
}
shared_ptr<FitnessMetric> m_fitnessMetric = make_shared<ChromosomeLengthMetric>();
};
@ -309,6 +317,53 @@ BOOST_FIXTURE_TEST_CASE(crossover_should_return_empty_population_if_selection_is
BOOST_TEST(population.crossover(selection, fixedPointCrossover(0.5)).individuals().empty());
}
BOOST_FIXTURE_TEST_CASE(symmetricCrossoverWithRemainder_should_return_crossed_population_and_remainder, PopulationFixture)
{
Population population(m_fitnessMetric, {Chromosome("aa"), Chromosome("cc"), Chromosome("gg"), Chromosome("hh")});
PairMosaicSelection selection({{2, 1}}, 0.25);
assert(selection.materialise(population.individuals().size()) == (vector<tuple<size_t, size_t>>{{2, 1}}));
Population expectedCrossedPopulation(m_fitnessMetric, {Chromosome("gc"), Chromosome("cg")});
Population expectedRemainder(m_fitnessMetric, {Chromosome("aa"), Chromosome("hh")});
BOOST_TEST(
population.symmetricCrossoverWithRemainder(selection, twoStepSwap) ==
(tuple<Population, Population>{expectedCrossedPopulation, expectedRemainder})
);
}
BOOST_FIXTURE_TEST_CASE(symmetricCrossoverWithRemainder_should_allow_crossing_the_same_individual_multiple_times, PopulationFixture)
{
Population population(m_fitnessMetric, {Chromosome("aa"), Chromosome("cc"), Chromosome("gg"), Chromosome("hh")});
PairMosaicSelection selection({{0, 0}, {2, 1}}, 1.0);
assert(selection.materialise(population.individuals().size()) == (vector<tuple<size_t, size_t>>{{0, 0}, {2, 1}, {0, 0}, {2, 1}}));
Population expectedCrossedPopulation(m_fitnessMetric, {
Chromosome("aa"), Chromosome("aa"),
Chromosome("aa"), Chromosome("aa"),
Chromosome("gc"), Chromosome("cg"),
Chromosome("gc"), Chromosome("cg"),
});
Population expectedRemainder(m_fitnessMetric, {Chromosome("hh")});
BOOST_TEST(
population.symmetricCrossoverWithRemainder(selection, twoStepSwap) ==
(tuple<Population, Population>{expectedCrossedPopulation, expectedRemainder})
);
}
BOOST_FIXTURE_TEST_CASE(symmetricCrossoverWithRemainder_should_return_empty_population_if_selection_is_empty, PopulationFixture)
{
Population population(m_fitnessMetric, {Chromosome("aa"), Chromosome("cc")});
PairMosaicSelection selection({}, 0.0);
assert(selection.materialise(population.individuals().size()).empty());
BOOST_TEST(
population.symmetricCrossoverWithRemainder(selection, twoStepSwap) ==
(tuple<Population, Population>{Population(m_fitnessMetric), population})
);
}
BOOST_AUTO_TEST_SUITE_END()
BOOST_AUTO_TEST_SUITE_END()

View File

@ -117,6 +117,37 @@ Population Population::crossover(PairSelection const& _selection, function<Cross
return Population(m_fitnessMetric, crossedIndividuals);
}
tuple<Population, Population> Population::symmetricCrossoverWithRemainder(
PairSelection const& _selection,
function<SymmetricCrossover> _symmetricCrossover
) const
{
vector<int> indexSelected(m_individuals.size(), false);
vector<Individual> crossedIndividuals;
for (auto const& [i, j]: _selection.materialise(m_individuals.size()))
{
auto children = _symmetricCrossover(
m_individuals[i].chromosome,
m_individuals[j].chromosome
);
crossedIndividuals.emplace_back(move(get<0>(children)), *m_fitnessMetric);
crossedIndividuals.emplace_back(move(get<1>(children)), *m_fitnessMetric);
indexSelected[i] = true;
indexSelected[j] = true;
}
vector<Individual> remainder;
for (size_t i = 0; i < indexSelected.size(); ++i)
if (!indexSelected[i])
remainder.emplace_back(m_individuals[i]);
return {
Population(m_fitnessMetric, crossedIndividuals),
Population(m_fitnessMetric, remainder),
};
}
namespace solidity::phaser
{

View File

@ -100,6 +100,10 @@ public:
Population select(Selection const& _selection) const;
Population mutate(Selection const& _selection, std::function<Mutation> _mutation) const;
Population crossover(PairSelection const& _selection, std::function<Crossover> _crossover) const;
std::tuple<Population, Population> symmetricCrossoverWithRemainder(
PairSelection const& _selection,
std::function<SymmetricCrossover> _symmetricCrossover
) const;
friend Population operator+(Population _a, Population _b);