mirror of
				https://github.com/ethereum/solidity
				synced 2023-10-03 13:03:40 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			177 lines
		
	
	
		
			5.6 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			177 lines
		
	
	
		
			5.6 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| /*
 | |
| 	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 <http://www.gnu.org/licenses/>.
 | |
| */
 | |
| // SPDX-License-Identifier: GPL-3.0
 | |
| 
 | |
| #include <tools/yulPhaser/GeneticAlgorithms.h>
 | |
| #include <tools/yulPhaser/Mutations.h>
 | |
| #include <tools/yulPhaser/Selections.h>
 | |
| #include <tools/yulPhaser/PairSelections.h>
 | |
| 
 | |
| using namespace std;
 | |
| using namespace solidity;
 | |
| using namespace solidity::phaser;
 | |
| 
 | |
| function<Crossover> phaser::buildCrossoverOperator(
 | |
| 	CrossoverChoice _choice,
 | |
| 	optional<double> _uniformCrossoverSwapChance
 | |
| )
 | |
| {
 | |
| 	switch (_choice)
 | |
| 	{
 | |
| 		case CrossoverChoice::SinglePoint:
 | |
| 			return randomPointCrossover();
 | |
| 		case CrossoverChoice::TwoPoint:
 | |
| 			return randomTwoPointCrossover();
 | |
| 		case CrossoverChoice::Uniform:
 | |
| 			assert(_uniformCrossoverSwapChance.has_value());
 | |
| 			return uniformCrossover(_uniformCrossoverSwapChance.value());
 | |
| 		default:
 | |
| 			assertThrow(false, solidity::util::Exception, "Invalid CrossoverChoice value.");
 | |
| 	};
 | |
| }
 | |
| 
 | |
| function<SymmetricCrossover> phaser::buildSymmetricCrossoverOperator(
 | |
| 	CrossoverChoice _choice,
 | |
| 	optional<double> _uniformCrossoverSwapChance
 | |
| )
 | |
| {
 | |
| 	switch (_choice)
 | |
| 	{
 | |
| 		case CrossoverChoice::SinglePoint:
 | |
| 			return symmetricRandomPointCrossover();
 | |
| 		case CrossoverChoice::TwoPoint:
 | |
| 			return symmetricRandomTwoPointCrossover();
 | |
| 		case CrossoverChoice::Uniform:
 | |
| 			assert(_uniformCrossoverSwapChance.has_value());
 | |
| 			return symmetricUniformCrossover(_uniformCrossoverSwapChance.value());
 | |
| 		default:
 | |
| 			assertThrow(false, solidity::util::Exception, "Invalid CrossoverChoice value.");
 | |
| 	};
 | |
| }
 | |
| 
 | |
| Population RandomAlgorithm::runNextRound(Population _population)
 | |
| {
 | |
| 	RangeSelection elite(0.0, m_options.elitePoolSize);
 | |
| 
 | |
| 	Population elitePopulation = _population.select(elite);
 | |
| 	size_t replacementCount = _population.individuals().size() - elitePopulation.individuals().size();
 | |
| 
 | |
| 	return
 | |
| 		move(elitePopulation) +
 | |
| 		Population::makeRandom(
 | |
| 			_population.fitnessMetric(),
 | |
| 			replacementCount,
 | |
| 			m_options.minChromosomeLength,
 | |
| 			m_options.maxChromosomeLength
 | |
| 		);
 | |
| }
 | |
| 
 | |
| Population GenerationalElitistWithExclusivePools::runNextRound(Population _population)
 | |
| {
 | |
| 	double elitePoolSize = 1.0 - (m_options.mutationPoolSize + m_options.crossoverPoolSize);
 | |
| 
 | |
| 	RangeSelection elitePool(0.0, elitePoolSize);
 | |
| 	RandomSelection mutationPoolFromElite(m_options.mutationPoolSize / elitePoolSize);
 | |
| 	RandomPairSelection crossoverPoolFromElite(m_options.crossoverPoolSize / elitePoolSize);
 | |
| 
 | |
| 	std::function<Mutation> mutationOperator = alternativeMutations(
 | |
| 		m_options.randomisationChance,
 | |
| 		geneRandomisation(m_options.percentGenesToRandomise),
 | |
| 		alternativeMutations(
 | |
| 			m_options.deletionVsAdditionChance,
 | |
| 			geneDeletion(m_options.percentGenesToAddOrDelete),
 | |
| 			geneAddition(m_options.percentGenesToAddOrDelete)
 | |
| 		)
 | |
| 	);
 | |
| 	std::function<Crossover> crossoverOperator = buildCrossoverOperator(
 | |
| 		m_options.crossover,
 | |
| 		m_options.uniformCrossoverSwapChance
 | |
| 	);
 | |
| 
 | |
| 	return
 | |
| 		_population.select(elitePool) +
 | |
| 		_population.select(elitePool).mutate(mutationPoolFromElite, mutationOperator) +
 | |
| 		_population.select(elitePool).crossover(crossoverPoolFromElite, crossoverOperator);
 | |
| }
 | |
| 
 | |
| Population ClassicGeneticAlgorithm::runNextRound(Population _population)
 | |
| {
 | |
| 	Population elite = _population.select(RangeSelection(0.0, m_options.elitePoolSize));
 | |
| 	Population rest = _population.select(RangeSelection(m_options.elitePoolSize, 1.0));
 | |
| 
 | |
| 	Population selectedPopulation = select(_population, rest.individuals().size());
 | |
| 
 | |
| 	std::function<SymmetricCrossover> crossoverOperator = buildSymmetricCrossoverOperator(
 | |
| 		m_options.crossover,
 | |
| 		m_options.uniformCrossoverSwapChance
 | |
| 	);
 | |
| 
 | |
| 	Population crossedPopulation = Population::combine(
 | |
| 		selectedPopulation.symmetricCrossoverWithRemainder(
 | |
| 			PairsFromRandomSubset(m_options.crossoverChance),
 | |
| 			crossoverOperator
 | |
| 		)
 | |
| 	);
 | |
| 
 | |
| 	std::function<Mutation> mutationOperator = mutationSequence({
 | |
| 		geneRandomisation(m_options.mutationChance),
 | |
| 		geneDeletion(m_options.deletionChance),
 | |
| 		geneAddition(m_options.additionChance),
 | |
| 	});
 | |
| 
 | |
| 	RangeSelection all(0.0, 1.0);
 | |
| 	Population mutatedPopulation = crossedPopulation.mutate(all, mutationOperator);
 | |
| 
 | |
| 	return elite + mutatedPopulation;
 | |
| }
 | |
| 
 | |
| Population ClassicGeneticAlgorithm::select(Population _population, size_t _selectionSize)
 | |
| {
 | |
| 	if (_population.individuals().size() == 0)
 | |
| 		return _population;
 | |
| 
 | |
| 	size_t maxFitness = 0;
 | |
| 	for (auto const& individual: _population.individuals())
 | |
| 		maxFitness = max(maxFitness, individual.fitness);
 | |
| 
 | |
| 	size_t rouletteRange = 0;
 | |
| 	for (auto const& individual: _population.individuals())
 | |
| 		// Add 1 to make sure that every chromosome has non-zero probability of being chosen
 | |
| 		rouletteRange += maxFitness + 1 - individual.fitness;
 | |
| 
 | |
| 	vector<Individual> selectedIndividuals;
 | |
| 	for (size_t i = 0; i < _selectionSize; ++i)
 | |
| 	{
 | |
| 		size_t ball = SimulationRNG::uniformInt(0, rouletteRange - 1);
 | |
| 
 | |
| 		size_t cumulativeFitness = 0;
 | |
| 		for (auto const& individual: _population.individuals())
 | |
| 		{
 | |
| 			size_t pocketSize = maxFitness + 1 - individual.fitness;
 | |
| 			if (ball < cumulativeFitness + pocketSize)
 | |
| 			{
 | |
| 				selectedIndividuals.push_back(individual);
 | |
| 				break;
 | |
| 			}
 | |
| 			cumulativeFitness += pocketSize;
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	assert(selectedIndividuals.size() == _selectionSize);
 | |
| 	return Population(_population.fitnessMetric(), selectedIndividuals);
 | |
| }
 |