/* This file is part of solidity. solidity is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. solidity is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with solidity. If not, see . */ #pragma once #include #include #include #include #include #include namespace solidity::phaser { class Population; } // This operator+ must be declared in the global namespace. Otherwise it would shadow global // operator+ overloads from CommonData.h (e.g. the one for vector) in the namespace it was declared in. solidity::phaser::Population operator+(solidity::phaser::Population _a, solidity::phaser::Population _b); namespace solidity::phaser { /** * Information describing the state of an individual member of the population during the course * of the genetic algorithm. */ struct Individual { Chromosome chromosome; size_t fitness; bool operator==(Individual const& _other) const { return fitness == _other.fitness && chromosome == _other.chromosome; } bool operator!=(Individual const& _other) const { return !(*this == _other); } friend std::ostream& operator<<(std::ostream& _stream, Individual const& _individual); }; /// Determines which individual is better by comparing fitness values. If fitness is the same /// takes into account all the other properties of the individual to make the comparison /// deterministic as long as the individuals are not equal. bool isFitter(Individual const& a, Individual const& b); /** * Represents a changing set of individuals undergoing a genetic algorithm. * Each round of the algorithm involves mutating existing individuals, evaluating their fitness * and selecting the best ones for the next round. * * An individual is a sequence of optimiser steps represented by a @a Chromosome instance. * Individuals are always ordered by their fitness (based on @_fitnessMetric and @a isFitter()). * The fitness is computed using the metric as soon as an individual is inserted into the population. */ class Population { public: static constexpr size_t MaxChromosomeLength = 30; explicit Population( std::shared_ptr _fitnessMetric, std::vector _chromosomes = {} ): Population( _fitnessMetric, chromosomesToIndividuals(*_fitnessMetric, std::move(_chromosomes)) ) {} static Population makeRandom( std::shared_ptr _fitnessMetric, size_t _size, std::function _chromosomeLengthGenerator ); static Population makeRandom( std::shared_ptr _fitnessMetric, size_t _size, size_t _minChromosomeLength, size_t _maxChromosomeLength ); void run(std::optional _numRounds, std::ostream& _outputStream); friend Population (::operator+)(Population _a, Population _b); std::shared_ptr fitnessMetric() const { return m_fitnessMetric; } std::vector const& individuals() const { return m_individuals; } static size_t uniformChromosomeLength(size_t _min, size_t _max) { return SimulationRNG::uniformInt(_min, _max); } static size_t binomialChromosomeLength(size_t _max) { return SimulationRNG::binomialInt(_max, 0.5); } bool operator==(Population const& _other) const; bool operator!=(Population const& _other) const { return !(*this == _other); } friend std::ostream& operator<<(std::ostream& _stream, Population const& _population); private: explicit Population(std::shared_ptr _fitnessMetric, std::vector _individuals): m_fitnessMetric(std::move(_fitnessMetric)), m_individuals{sortedIndividuals(std::move(_individuals))} {} void doMutation(); void doSelection(); static void randomizeWorstChromosomes( FitnessMetric const& _fitnessMetric, std::vector& _individuals, size_t _count ); static std::vector chromosomesToIndividuals( FitnessMetric const& _fitnessMetric, std::vector _chromosomes ); static std::vector sortedIndividuals(std::vector _individuals); std::shared_ptr m_fitnessMetric; std::vector m_individuals; }; }