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. * * 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; } }