/*
Copyright 2009 by Marcin Szubert
Licensed under the Academic Free License version 3.0
*/
package cecj.eval;
import java.util.ArrayList;
import java.util.List;
import cecj.fitness.FitnessAggregateMethod;
import cecj.interaction.InteractionResult;
import cecj.interaction.InteractionScheme;
import cecj.sampling.SamplingMethod;
import cecj.statistics.CoevolutionaryStatistics;
import ec.EvolutionState;
import ec.Individual;
import ec.util.Parameter;
/**
*
* Simple coevolutionary evaluator without any additional mechanisms.
*
* This is the simplest implementation of conventional coevolutionary evaluation where interactions
* between individuals can be performed in an arbitrary order. However, the character and the scope
* of interactions can be different Ð it is defined by instantiating appropriate
* InteractionScheme
subclass. The evaluation proceeds as follows. First of all, a
* reference set of opponent individuals is selected from each subpopulation. This task is handled
* by a SamplingMethod
realization. Distinct sampling methods can be used by different
* subpopulations. Next, each subpopulation individuals are confronted with previously selected
* opponents from subpopulations pointed by the concrete InteractionScheme
class.
* Finally, FitnessAggregateMethod
is responsible for aggregating outcomes of these
* confrontations into a single fitness measure which is used later during selection stage of the
* evolutionary process. It evaluates individuals according to the outcomes of its interactions with
* other individuals. Interactions are not restricted to intraspecific or interspecific type, i.e.
* opponents can be chosen from the same population or any other coevolving population.
*
* In contrast to TournamentCoevolutionaryEvaluator
all interactions can be simulated
* in any order. There are no sequential dependencies between interactions.
*
* @author Marcin Szubert
*
*/
public class SimpleCoevolutionaryEvaluator extends CoevolutionaryEvaluator {
protected static final String P_SUBPOP = "subpop";
private static final String P_STATISTICS = "statistics";
private static final String P_FITNESS_METHOD = "fitness-method";
private static final String P_POP_INDS_WEIGHT = "pop-inds-weight";
private static final String P_SAMPLING_METHOD = "sampling-method";
private static final String P_INTERACTION_SCHEME = "interaction-scheme";
/**
* Tests used to interact with candidate solutions.
*/
protected List> opponents;
/**
* Methods of sampling the opponents from particular populations.
*/
protected SamplingMethod[] samplingMethod;
/**
* The Method of aggregating multiple interaction outcomes into single value.
*/
protected FitnessAggregateMethod[] fitnessAggregateMethod;
/**
* Specifies how interactions between populations look like.
*/
protected InteractionScheme interactionScheme;
/**
* Gathers statistics about evaluation stage.
*/
protected CoevolutionaryStatistics statistics;
/**
* Indicates how important are population opponents with respect to potential archival
* opponents.
*/
private int popIndsWeight;
@Override
public void setup(final EvolutionState state, final Parameter base) {
super.setup(state, base);
Parameter interactionSchemeParam = base.push(P_INTERACTION_SCHEME);
interactionScheme = (InteractionScheme) (state.parameters.getInstanceForParameter(
interactionSchemeParam, null, InteractionScheme.class));
interactionScheme.setup(state, interactionSchemeParam);
Parameter popIndsWeightParam = base.push(P_POP_INDS_WEIGHT);
popIndsWeight = state.parameters.getIntWithDefault(popIndsWeightParam, null, 1);
Parameter statisticsParam = base.push(P_STATISTICS);
if (state.parameters.exists(statisticsParam)) {
statistics = (CoevolutionaryStatistics) (state.parameters.getInstanceForParameter(
statisticsParam, null, CoevolutionaryStatistics.class));
statistics.setup(state, statisticsParam);
}
opponents = new ArrayList>(numSubpopulations);
samplingMethod = new SamplingMethod[numSubpopulations];
fitnessAggregateMethod = new FitnessAggregateMethod[numSubpopulations];
for (int subpop = 0; subpop < numSubpopulations; subpop++) {
opponents.add(new ArrayList());
setupSubpopulation(state, base, subpop);
}
}
/**
* Sets up fitness aggregate methods and sampling method for the given subpopulation.
*
* @param state
* the current evolutionary state
* @param base
* the base parameter
* @param subpop
* the subpopulation index
*/
private void setupSubpopulation(EvolutionState state, Parameter base, int subpop) {
Parameter samplingMethodParam = base.push(P_SUBPOP).push("" + subpop).push(
P_SAMPLING_METHOD);
samplingMethod[subpop] = (SamplingMethod) (state.parameters.getInstanceForParameter(
samplingMethodParam, null, SamplingMethod.class));
samplingMethod[subpop].setup(state, samplingMethodParam);
Parameter fitnessMethodParam = base.push(P_SUBPOP).push("" + subpop).push(P_FITNESS_METHOD);
fitnessAggregateMethod[subpop] = (FitnessAggregateMethod) (state.parameters
.getInstanceForParameter(fitnessMethodParam, null, FitnessAggregateMethod.class));
}
@Override
public void evaluatePopulation(EvolutionState state) {
for (int subpop = 0; subpop < numSubpopulations; subpop++) {
opponents.set(subpop, findOpponentsFromSubpopulation(state, subpop));
}
for (int subpop = 0; subpop < numSubpopulations; subpop++) {
List> subpopulationResults = interactionScheme
.performInteractions(state, subpop, opponents);
fitnessAggregateMethod[subpop].prepareToAggregate(state, subpop);
fitnessAggregateMethod[subpop].addToAggregate(state, subpop, subpopulationResults,
popIndsWeight);
fitnessAggregateMethod[subpop].assignFitness(state, subpop);
if (statistics != null) {
statistics.printInteractionResults(state, subpopulationResults, subpop);
}
}
}
/**
* Samples subpopulation to choose a reference set of individuals. Other individuals can be
* evaluated on the basis of interactions with this reference set. It may happen that
* individuals from the same subpopulation are tested int this way - it depends on
*
* @param subpop
* the index of subpopulation
* @return a list of individuals sampled from the given subpopulation
*/
private List findOpponentsFromSubpopulation(EvolutionState state, int subpop) {
return samplingMethod[subpop].sample(state, state.population.subpops[subpop].individuals);
}
/**
* Returns the interaction scheme used during the evaluation.
*
* @return the interaction scheme used by this evaluator
*/
public InteractionScheme getInteractionScheme() {
return interactionScheme;
}
}