/*
Copyright 2009 by Marcin Szubert
Licensed under the Academic Free License version 3.0
*/
package cecj.archive;
import java.util.ArrayList;
import java.util.List;
import cecj.interaction.InteractionResult;
import ec.EvolutionState;
import ec.Individual;
/**
* Represents the archive for Pareto-Coevolution paradigm where each test is viewed as an objective
* in the sense of Multi-Objective Optimization.
*
* This class provides methods for comparing individuals on the basis of their interactions outcomes
* considered in the context of Pareto dominance relation (methods: dominates
,
* isDominated
). According to the results of these comparisons a test can be found
* useful if it proves that a particular candidate solution is not dominated by any other individual
* in the archive. Such usefulness can be verified using the methods of this class (
* isUseful
, findUsefulTest
). It provides methods for comparing
* individuals on the basis of their interaction results.
*
* @author Marcin Szubert
*
*/
public abstract class ParetoCoevolutionArchive extends CandidateTestArchive {
/**
* Tries to find a test for which candidate1
has better outcome than
* candidate2. It is needed for candidate1
to be non-dominated and thus
* useful to be stored in the archive. If the test is found it makes distinction between
* candidates.
*
* @param state
* the current evolution state
* @param candidate1
* the candidate which should appear to be better at some test
* @param candidate2
* the reference candidate solution which is checked for dominating the candidate1
* @param tests
* the list of test to be searched
* @return null
if there is no such test
*/
protected Individual findUsefulTest(EvolutionState state, Individual candidate1,
Individual candidate2, List tests) {
for (Individual test : tests) {
InteractionResult result1 = problem.test(state, candidate1, test).first;
InteractionResult result2 = problem.test(state, candidate2, test).first;
if (result1.betterThan(result2)) {
return test;
}
}
return null;
}
/**
* Checks if candidate1
Pareto-dominates candidate2
or both candidates
* are equal with respect to tests
. One candidate is Pareto-dominated if it has
* better or equal outcomes for all tests
and for at least one - strictly better.
*
* @param state
* the current evolution state
* @param candidate1
* the candidate solution which is checked for dominating the other candidate
* @param candidate2
* the candidate solutions which is checked for being dominated
* @param tests
* the set of tests with respect to which dominance is checked
* @return true
if candidate1
dominates candidate2
or
* they are equal with respect to tests
, false
otherwise
*/
protected boolean dominatesOrEqual(EvolutionState state, Individual candidate1,
Individual candidate2, List tests) {
return (findUsefulTest(state, candidate2, candidate1, tests) == null);
}
/**
* Checks if candidate1
Pareto-dominates candidate2
with respect to
* tests
. One candidate is Pareto-dominated if it has better or equal outcomes for
* all tests
and for at least one - strictly better.
*
* @param state
* the current evolution state
* @param candidate1
* the candidate solution which is checked for dominating the other candidate
* @param candidate2
* the candidate solutions which is checked for being dominated
* @param tests
* the set of tests with respect to which dominance is checked
* @return true
if candidate1
dominates candidate2
with
* respect to tests
, false
otherwise
*/
protected boolean dominates(EvolutionState state, Individual candidate1, Individual candidate2,
List tests) {
if ((findUsefulTest(state, candidate2, candidate1, tests) == null)
&& (findUsefulTest(state, candidate1, candidate2, tests) != null)) {
return true;
} else {
return false;
}
}
/**
* Verifies if candidate
is dominated by any candidate solution present in
* cArchive
with respect to tests in tArchive
or if another solution
* has equivalent outcomes for all tests in tArchive
.
*
* If the archive contains a candidate
, the outcome is true
.
*
* @param state
* the current evolution state
* @param candidate
* the candidate which is checked for being dominated; it should not be in the
* archive
* @param cArchive
* the archive of candidate solutions
* @param tArchive
* the archive of tests
* @return true
if candidate
is dominated by or equal to another
* solution in the archive
*/
protected boolean isDominatedOrEqual(EvolutionState state, Individual candidate,
List cArchive, List tArchive) {
for (Individual otherCandidate : cArchive) {
if (dominatesOrEqual(state, otherCandidate, candidate, tArchive)) {
return true;
}
}
return false;
}
/**
* Verifies if candidate
is dominated by any candidate solution present in
* cArchive
with respect to tests in tArchive
.
*
* @param state
* the current evolution state
* @param candidate
* the candidate which is checked for being dominated
* @param cArchive
* the archive of candidate solutions
* @param tArchive
* the archive of tests
* @return true
if candidate
is dominated by any solution in the
* archive
*/
protected boolean isDominated(EvolutionState state, Individual candidate,
List cArchive, List tArchive) {
for (Individual otherCandidate : cArchive) {
if (dominates(state, otherCandidate, candidate, tArchive)) {
return true;
}
}
return false;
}
/**
* Checks if newCandidate
is useful with respect to current archives of candidates
* and tests and new population of generated tests. A candidate solutions is considered
* useful if it is non-dominated and no solution is already present with identical
* outcomes for all tests.
*
* @param state
* the current evolution state
* @param newCandidate
* the candidate whose usefulness is verified
* @param cArchive
* the archive of candidate solutions
* @param tArchive
* the archive of tests
* @param newTests
* the population of new tests
* @return true
if newCandidate
is useful and should be
* included in the archive.
*/
protected boolean isUseful(EvolutionState state, Individual newCandidate,
List cArchive, List tArchive, List newTests) {
if (isDominatedOrEqual(state, newCandidate, cArchive, tArchive)
&& isDominatedOrEqual(state, newCandidate, cArchive, newTests)) {
return false;
} else {
return true;
}
}
/**
* Finds tests which are needed to prove usefulness of given newCandidate
. These
* tests should make distinctions between existing solutions in the cArchive
and
* the new one. If the newCandidate
solution is non-dominated without adding any of
* newTests
to the test archive, the returned list is empty.
*
* @param state
* the current evolution state
* @param newCandidate
* the candidate solution whose non-dominated status is to be guaranteed
* @param cArchive
* the archive of candidate solutions
* @param tArchive
* the archive of tests
* @param newTests
* the population of new tests
* @return the list of test individuals from newTests
which should be added to the
* tArchive
to make newCandidate
non-dominated. If even adding
* all test is not sufficient, null
is returned.
*/
protected List findUsefulTests(EvolutionState state, Individual newCandidate,
List cArchive, List tArchive, List newTests) {
List selected = new ArrayList();
List rest = new ArrayList(newTests);
for (Individual candidate : cArchive) {
if (dominatesOrEqual(state, candidate, newCandidate, tArchive)
&& dominatesOrEqual(state, candidate, newCandidate, selected)) {
Individual test = findUsefulTest(state, newCandidate, candidate, rest);
if (test == null) {
return null;
} else {
selected.add(test);
rest.remove(test);
}
}
}
return selected;
}
}