/*
Copyright 2009 by Marcin Szubert
Licensed under the Academic Free License version 3.0
*/
package cecj.archive;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import ec.EvolutionState;
import ec.Individual;
import ec.util.Parameter;
/**
* Layered Pareto-Coevolution Archive.
*
* This archive is a modified version of the IPCA archive. While the original one can grow
* indefinitely (tests are never removed from the archive), this type of archive limits the maximum
* number of stored individuals. However, this goal is achieved for the price of reducing the
* reliability of the algorithm. After appending non-dominated candidate solutions and useful tests
* to appropriate archives, maintainLayers
and updateTestArchive
methods
* are invoked in order to decrease the amount of used memory. The first one checks which candidate
* solutions belong to the first num-layers
Pareto layers and keeps them in the
* archive. The second retains only these tests which make distinctions between neighboring layers.
*
* @author Marcin Szubert
*
*/
public class LAPCArchive extends ParetoCoevolutionArchive {
private static final String P_NUM_LAYERS = "num-layers";
private int numLayers;
private List> layers;
@Override
public void setup(EvolutionState state, Parameter base) {
super.setup(state, base);
Parameter numLayersParameter = base.push(P_NUM_LAYERS);
numLayers = state.parameters.getInt(numLayersParameter, null, 1);
if (numLayers <= 0) {
state.output.fatal("Number of LAPCA layers must be > 0.\n");
}
layers = new ArrayList>(numLayers);
}
/*
* It is implemented in a IPCA-like way. Another method is to extend both existing archives by
* new individuals, then find first n layers of candidates with respect to all tests in the
* archive and in the population and finally select necessary tests making distinctions between
* layers.
*/
@Override
protected void submit(EvolutionState state, List candidates,
List cArchive, List tests, List tArchive) {
List testsCopy = new ArrayList(tests);
List usefulTests;
for (Individual candidate : candidates) {
if (isUseful(state, candidate, cArchive, tArchive, testsCopy)) {
usefulTests = findUsefulTests(state, candidate, cArchive, tArchive, testsCopy);
cArchive.add(candidate);
tArchive.addAll(usefulTests);
testsCopy.removeAll(usefulTests);
}
}
maintainLayers(state, cArchive, tArchive);
updateTestArchive(state, tArchive);
}
private void updateTestArchive(EvolutionState state, List tArchive) {
Set tset = new HashSet();
tset.addAll(findDistinguishingTests(state, layers.get(0), layers.get(0), tArchive));
for (int l = 1; l < numLayers; l++) {
tset.addAll(findDistinguishingTests(state, layers.get(l - 1), layers.get(l), tArchive));
}
tArchive.clear();
tArchive.addAll(tset);
}
private List findDistinguishingTests(EvolutionState state, List layer1,
List layer2, List tests) {
List distinguishingTests = new ArrayList();
for (Individual candidate1 : layer1) {
for (Individual candidate2 : layer2) {
if (candidate1.equals(candidate2))
continue;
Individual test = findUsefulTest(state, candidate1, candidate2, tests);
if ((test != null) && (!distinguishingTests.contains(test))) {
distinguishingTests.add(test);
}
}
}
return distinguishingTests;
}
private void maintainLayers(EvolutionState state, List cArchive,
List tArchive) {
List cArchiveCopy = new ArrayList(cArchive);
for (int layer = 0; layer < numLayers; layer++) {
List frontPareto = findNonDominatedCandidates(state, cArchiveCopy, tArchive);
layers.set(layer, frontPareto);
cArchiveCopy.removeAll(frontPareto);
}
cArchive.removeAll(cArchiveCopy);
}
private List findNonDominatedCandidates(EvolutionState state,
List cArchive, List tArchive) {
List result = new ArrayList();
for (Individual candidate : cArchive) {
if (!isDominated(state, candidate, cArchive, tArchive)) {
result.add(candidate);
}
}
return result;
}
}