public virtual void EvalRoundRobin( IEvolutionState state, int[] origins, int[] numinds, IList <Individual> individuals, int subpop, IGroupedProblem prob) { if (state.EvalThreads == 1) { EvalRoundRobinPopChunk( state, origins[0], numinds[0], 0, individuals, subpop, prob); } else { ParallelEvaluation <RoundRobinCompetitiveEvaluatorThread>( state, origins, numinds, individuals, subpop, prob); } }
void ParallelEvaluation <TEvalThread>( IEvolutionState state, int[] origins, int[] numinds, IList <Individual> individuals, int subpop, IGroupedProblem prob) where TEvalThread : CompetitiveEvaluatorThread, new() { // BRS: TPL DataFlow is cleaner and safer than using raw threads. // Limit the concurrency in case the user has gone overboard! var maxDegree = Math.Min(Environment.ProcessorCount, state.BreedThreads); var options = new ExecutionDataflowBlockOptions { MaxDegreeOfParallelism = maxDegree }; Action <CompetitiveEvaluatorThread> act = t => t.Run(); var actionBlock = new ActionBlock <CompetitiveEvaluatorThread>(act, options); for (var i = 0; i < state.EvalThreads; i++) { var runnable = new TEvalThread { ThreadNum = i, State = state, Subpop = subpop, NumInds = numinds[i], From = origins[i], Problem = prob, Evaluator = this, Inds = individuals }; actionBlock.Post(runnable); } actionBlock.Complete(); actionBlock.Completion.Wait(); }
public virtual void EvalNRandomTwoWayPopChunk(IEvolutionState state, int origin, int numinds, int threadnum, IList <Individual> individuals, int subpop, IGroupedProblem prob) { // the number of games played for each player var individualsOrdered = new EncapsulatedIndividual[individuals.Count]; var queue = new EncapsulatedIndividual[individuals.Count]; for (var i = 0; i < individuals.Count; i++) { individualsOrdered[i] = new EncapsulatedIndividual(individuals[i], 0); } var competition = new Individual[2]; var subpops = new[] { subpop, subpop }; var updates = new bool[2]; updates[0] = true; var upperBound = origin + numinds; for (var x = origin; x < upperBound; x++) { Array.Copy(individualsOrdered, 0, queue, 0, queue.Length); competition[0] = queue[x].Ind; // if the rest of individuals is not enough to fill // all games remaining for the current individual // (meaning that the current individual has left a // lot of games to play versus players with index // greater than his own), then it should play with // all. In the end, we should check that he finished // all the games he needs. If he did, everything is // ok, otherwise he should play with some other players // with index smaller than his own, but all these games // will count only for his fitness evaluation, and // not for the opponents' (unless allowOverEvaluations is set to true) // if true, it means that he has to play against all opponents with greater index if (individuals.Count - x - 1 <= GroupSize - queue[x].NumOpponentsMet) { for (var y = x + 1; y < queue.Length; y++) { competition[1] = queue[y].Ind; updates[1] = queue[y].NumOpponentsMet < GroupSize || AllowOverEvaluation; prob.Evaluate(state, competition, updates, false, subpops, 0); queue[x].NumOpponentsMet++; if (updates[1]) { queue[y].NumOpponentsMet++; } } } // here he has to play against a selection of the opponents with greater index else { // we can use the queue structure because we'll just rearrange the indexes // but we should make sure we also rearrange the other vectors referring to the individuals for (var y = 0; GroupSize > queue[x].NumOpponentsMet; y++) { // swap to the end and remove from list var index = state.Random[0].NextInt(queue.Length - x - 1 - y) + x + 1; competition[1] = queue[index].Ind; updates[1] = queue[index].NumOpponentsMet < GroupSize || AllowOverEvaluation; prob.Evaluate(state, competition, updates, false, subpops, 0); queue[x].NumOpponentsMet++; if (updates[1]) { queue[index].NumOpponentsMet++; } // swap the players (such that a player will not be considered twice) var temp = queue[index]; queue[index] = queue[queue.Length - y - 1]; queue[queue.Length - y - 1] = temp; } } // if true, it means that the current player needs to play some games with other players with lower indexes. // this is an unfortunate situation, since all those players have already had their groupSize games for the evaluation if (queue[x].NumOpponentsMet < GroupSize) { for (var y = queue[x].NumOpponentsMet; y < GroupSize; y++) { // select a random opponent with smaller index (don't even care for duplicates) int index; if (x > 0) { // if x is 0, then there are no players with smaller index, therefore pick a random one index = state.Random[0].NextInt(x); } else { index = state.Random[0].NextInt(queue.Length - 1) + 1; } // use the opponent for the evaluation competition[1] = queue[index].Ind; updates[1] = (queue[index].NumOpponentsMet < GroupSize) || AllowOverEvaluation; prob.Evaluate(state, competition, updates, false, subpops, 0); queue[x].NumOpponentsMet++; if (updates[1]) { queue[index].NumOpponentsMet++; } } } } }
public virtual void EvalNRandomOneWayPopChunk(IEvolutionState state, int origin, int numinds, int threadnum, IList <Individual> individuals, int subpop, IGroupedProblem prob) { var queue = individuals.ToArray(); int len = queue.Length; var competition = new Individual[2]; var subpops = new[] { subpop, subpop }; var updates = new bool[2]; updates[0] = true; updates[1] = false; var upperBound = origin + numinds; for (var x = origin; x < upperBound; x++) { competition[0] = individuals[x]; // fill up our tournament for (var y = 0; y < GroupSize;) { // swap to end and remove var index = state.Random[0].NextInt(len - y); competition[1] = queue[index]; queue[index] = queue[len - y - 1]; queue[len - y - 1] = competition[1]; // if the opponent is not the actual individual, we can // have a competition if (!competition[1].Equals(individuals[x])) { prob.Evaluate(state, competition, updates, false, subpops, 0); y++; } } } }
/// <summary> /// A private helper function for evalutatePopulation which evaluates a chunk /// of individuals in a subpop for a given thread. /// /// Although this method is declared public (for the benefit of a private /// helper class in this file), you should not call it. /// </summary> public virtual void EvalRoundRobinPopChunk(IEvolutionState state, int origin, int numinds, int threadnum, IList <Individual> individuals, int subpop, IGroupedProblem prob) { var competition = new Individual[2]; var subpops = new[] { subpop, subpop }; var updates = new bool[2]; updates[0] = updates[1] = true; var upperBound = origin + numinds; // evaluate chunk of population against entire population // since an individual x will be evaluated against all // other individuals <x in other threads, only evaluate it against // individuals >x in this thread. for (var x = origin; x < upperBound; x++) { for (var y = x + 1; y < individuals.Count; y++) { competition[0] = individuals[x]; competition[1] = individuals[y]; prob.Evaluate(state, competition, updates, false, subpops, 0); } } }
public virtual void EvalSingleElimination(IEvolutionState state, IList <Individual> individuals, int subpop, IGroupedProblem prob) { // for a single-elimination tournament, the subpop[0] size must be 2^n for // some value n. We don't check that here! Check it in Setup. // create the tournament array var tourn = individuals.ToArray(); var len = tourn.Length; var competition = new Individual[2]; var subpops = new[] { subpop, subpop }; var updates = new bool[2]; updates[0] = updates[1] = true; // the "top half" of our array will be losers. // the bottom half will be winners. Then we cut our array in half and repeat. while (len > 1) { for (var x = 0; x < len / 2; x++) { competition[0] = tourn[x]; competition[1] = tourn[len - x - 1]; prob.Evaluate(state, competition, updates, true, subpops, 0); } for (var x = 0; x < len / 2; x++) { // if the second individual is better, or coin flip if equal, than we switch them around if (tourn[len - x - 1].Fitness.BetterThan(tourn[x].Fitness) || tourn[len - x - 1].Fitness.EquivalentTo(tourn[x].Fitness) && state.Random[0].NextBoolean()) { Individual temp = tourn[x]; tourn[x] = tourn[len - x - 1]; tourn[len - x - 1] = temp; } } // last part of the tournament: deal with odd values of len! if (len % 2 != 0) { len = 1 + len / 2; } else { len /= 2; } } }
public virtual void AfterCoevolutionaryEvaluation(IEvolutionState state, Population pop, IGroupedProblem prob) { if (NumElite > 0) { for (var i = 0; i < state.Population.Subpops.Count; i++) { if (ShouldEvaluateSubpop(state, i, 0)) // only load elites for subpopulations which are actually changing { LoadElites(state, i); } } } // copy over the previous population if (NumPrev > 0) { _previousPopulation = (Population)(state.Population.EmptyClone()); for (var i = 0; i < _previousPopulation.Subpops.Count; i++) { for (var j = 0; j < _previousPopulation.Subpops[i].Individuals.Count; j++) { _previousPopulation.Subpops[i].Individuals[j] = (Individual)(state.Population.Subpops[i].Individuals[j].Clone()); } } } }
public virtual void PerformCoevolutionaryEvaluation(IEvolutionState state, Population pop, IGroupedProblem prob) { var evaluations = 0; _inds = new Individual[pop.Subpops.Count]; _updates = new bool[pop.Subpops.Count]; // we start by warming up the selection methods if (NumCurrent > 0) { for (var i = 0; i < _selectionMethodCurrent.Length; i++) { _selectionMethodCurrent[i].PrepareToProduce(state, i, 0); } } if (NumPrev > 0) { for (var i = 0; i < _selectionMethodPrev.Length; i++) { // do a hack here var currentPopulation = state.Population; state.Population = _previousPopulation; _selectionMethodPrev[i].PrepareToProduce(state, i, 0); state.Population = currentPopulation; } } // build subpopulation array to pass in each time var subpops = new int[state.Population.Subpops.Count]; for (var j = 0; j < subpops.Length; j++) { subpops[j] = j; } // handle shuffled always if (NumShuffled > 0) { int[] /*numShuffled*/ [] /*subpop*/ [] /*shuffledIndividualIndexes*/ ordering = null; // build shuffled orderings ordering = TensorFactory.Create <Int32>(NumShuffled, state.Population.Subpops.Count, state.Population.Subpops[0].Individuals.Count); for (var c = 0; c < NumShuffled; c++) { for (var m = 0; m < state.Population.Subpops.Count; m++) { for (var i = 0; i < state.Population.Subpops[0].Individuals.Count; i++) { ordering[c][m][i] = i; } if (m != 0) { Shuffle(state, ordering[c][m]); } } } // for each individual for (var i = 0; i < state.Population.Subpops[0].Individuals.Count; i++) { for (var k = 0; k < NumShuffled; k++) { for (var ind = 0; ind < _inds.Length; ind++) { _inds[ind] = state.Population.Subpops[ind].Individuals[ordering[k][ind][i]]; _updates[ind] = true; } prob.Evaluate(state, _inds, _updates, false, subpops, 0); evaluations++; } } } // for each subpopulation for (var j = 0; j < state.Population.Subpops.Count; j++) { // now do elites and randoms if (!ShouldEvaluateSubpop(state, j, 0)) { continue; // don't evaluate this subpopulation } // for each individual for (var i = 0; i < state.Population.Subpops[j].Individuals.Count; i++) { var individual = state.Population.Subpops[j].Individuals[i]; // Test against all the elites for (var k = 0; k < _eliteIndividuals[j].Length; k++) { for (var ind = 0; ind < _inds.Length; ind++) { if (ind == j) { _inds[ind] = individual; _updates[ind] = true; } else { _inds[ind] = _eliteIndividuals[ind][k]; _updates[ind] = false; } } prob.Evaluate(state, _inds, _updates, false, subpops, 0); evaluations++; } // test against random selected individuals of the current population for (var k = 0; k < NumCurrent; k++) { for (var ind = 0; ind < _inds.Length; ind++) { if (ind == j) { _inds[ind] = individual; _updates[ind] = true; } else { _inds[ind] = ProduceCurrent(ind, state, 0); _updates[ind] = true; } } prob.Evaluate(state, _inds, _updates, false, subpops, 0); evaluations++; } // Test against random selected individuals of previous population for (int k = 0; k < NumPrev; k++) { for (int ind = 0; ind < _inds.Length; ind++) { if (ind == j) { _inds[ind] = individual; _updates[ind] = true; } else { _inds[ind] = ProducePrevious(ind, state, 0); _updates[ind] = false; } } prob.Evaluate(state, _inds, _updates, false, subpops, 0); evaluations++; } } } // now shut down the selection methods if (NumCurrent > 0) { for (var i = 0; i < _selectionMethodCurrent.Length; i++) { _selectionMethodCurrent[i].FinishProducing(state, i, 0); } } if (NumPrev > 0) { for (var i = 0; i < _selectionMethodPrev.Length; i++) { // do a hack here var currentPopulation = state.Population; state.Population = _previousPopulation; _selectionMethodPrev[i].FinishProducing(state, i, 0); state.Population = currentPopulation; } } state.Output.Message("Evaluations: " + evaluations); }
public virtual void BeforeCoevolutionaryEvaluation(IEvolutionState state, Population pop, IGroupedProblem prob) { if (state.Generation == 0) { // create arrays for the elite individuals in the population at the previous generation. // deep clone the elite individuals as random individuals (in the initial generation, nobody has been evaluated yet). // deal with the elites _eliteIndividuals = TensorFactory.Create <Individual>(state.Population.Subpops.Count, NumElite); // copy the first individuals in each subpop (they are already randomly generated) for (var i = 0; i < _eliteIndividuals.Length; i++) { if (NumElite > state.Population.Subpops[i].Individuals.Count) { state.Output.Fatal("Number of elite partners is greater than the size of the subpop."); } for (var j = 0; j < NumElite; j++) { _eliteIndividuals[i][j] = (Individual)(state.Population.Subpops[i].Individuals[j].Clone()); // just take the first N individuals of each subpopulation } } // test for shuffled if (NumShuffled > 0) { var size = state.Population.Subpops[0].Individuals.Count; for (var i = 0; i < state.Population.Subpops.Count; i++) { if (state.Population.Subpops[i].Individuals.Count != size) { state.Output.Fatal("Shuffling was requested in MultiPopCoevolutionaryEvaluator, but the subpopulation sizes are not the same. " + "Specifically, subpopulation 0 has size " + size + " but subpopulation " + i + " has size " + state.Population.Subpops[i].Individuals.Count); } } } } }