/*
  Copyright 2009 by Marcin Szubert
  Licensed under the Academic Free License version 3.0
 */

package cecj.archive;

import java.util.List;

import cecj.eval.ArchivingCoevolutionaryEvaluator;
import cecj.eval.TDLImprovingEvaluator;

import ec.EvolutionState;
import ec.Individual;
import ec.Setup;
import ec.util.Parameter;

/**
 * The abstract class representing any archive used with coevolutionary algorithm. Archive
 * mechanisms play 3 important roles during the course of evolution:
 * 
 * <ul>
 * <li>
 * provide genetic material for future generations - archival individual can be chosen as parents of
 * future generations; this feature is implemented by coevolutionary breeding pipelines</li>
 * <li>
 * improve fitness evaluation of individuals in the population - they can interact with individuals
 * sampled from the archive; this feature is implemented in <code>ArchivingEvaluator</code></li>
 * <li>
 * approximate desired solution concept - while population performs exploration of solution space,
 * archive is aimed at storing the most promising individuals with respect to implemented solution
 * concept; this feature is implemented by this class and its subclasses.</li>
 * </ul>
 * 
 * Archives are incorporated into <code>ArchivingSubpopulation</code> objects and there are stored
 * archival individuals of the same species as the original population. In subclasses of
 * <code>CoevolutionaryArchive</code> only the method specifying how archives should be updated is
 * defined.
 * 
 * @author Marcin Szubert
 * 
 */
public abstract class CoevolutionaryArchive implements Setup {

	private static final String P_POP = "pop";
	private static final String P_SIZE = "subpops";

	/**
	 * Number of coevolving populations.
	 */
	protected int numSubpopulations;

	/**
	 * Checks if <code>ArchivingCoevolutionaryEvaluator</code> is used and reads the number of
	 * populations from the configuration.
	 */
	public void setup(EvolutionState state, Parameter base) {
		if (!(state.evaluator instanceof ArchivingCoevolutionaryEvaluator)
				&& !(state.evaluator instanceof TDLImprovingEvaluator)) {
			state.output.fatal("This archive can be used only with ArchivingEvaluator.\n");
		}

		Parameter popSizeParameter = new Parameter(P_POP).push(P_SIZE);
		numSubpopulations = state.parameters.getInt(popSizeParameter, null, 0);
	}

	/**
	 * Gets the list of archival individuals from given subpopulation.
	 * 
	 * @param state
	 *            the current evolution state
	 * @param subpop
	 *            the index of subpopulation
	 * @return the list of archival individuals of the subpopulation
	 */
	protected List<Individual> getArchive(EvolutionState state, int subpop) {
		ArchivingSubpopulation subpopulation = (ArchivingSubpopulation) state.population.subpops[subpop];
		return subpopulation.getArchivalIndividuals();
	}

	/**
	 * Gets the list of individuals from given subpopulation.
	 * 
	 * @param state
	 *            the current evolution state
	 * @param subpop
	 *            the index of subpopulation
	 * @return the list of current individuals in the subpopulation
	 */
	protected List<Individual> getIndividuals(EvolutionState state, int subpop) {
		ArchivingSubpopulation subpopulation = (ArchivingSubpopulation) state.population.subpops[subpop];
		return subpopulation.getIndividuals();
	}

	/**
	 * The main method of this class which is responsible by updating individuals in all archives
	 * basing on the current evolution state, specifically on new individuals in populations
	 * generated by coevolution process.
	 * 
	 * @param state
	 *            the current evolution state
	 */
	public abstract void submit(EvolutionState state);
}
