Java tutorial
/* * To change this license header, choose License Headers in Project Properties. * To change this template file, choose Tools | Templates * and open the template in the editor. */ package mase.spec; import ec.EvolutionState; import ec.Exchanger; import ec.Individual; import ec.Population; import ec.Subpopulation; import ec.util.Parameter; import java.io.Serializable; import java.util.ArrayList; import java.util.Arrays; import java.util.Comparator; import java.util.List; import mase.evaluation.MetaEvaluator; import mase.evaluation.BehaviourResult; import mase.evaluation.ExpandedFitness; import mase.evaluation.MultiPopCoevolutionaryEvaluatorThreaded; import mase.evaluation.CompoundEvaluationResult; import org.apache.commons.lang3.StringUtils; /** * * @author jorge */ public class AbstractHybridExchanger extends Exchanger { // list of allocations, separated by comma (ex: 0,0,1,1,2,2) OR V_HOMOGENEOUS OR V_HETEROGENEOUS OR a single number with the number of pops (agents are equally divided among all pops) public static final String P_INITIAL_ALLOCATION = "initial-allocation"; public static final String V_HOMOGENEOUS = "homogeneous"; public static final String V_HETEROGENEOUS = "heterogeneous"; public static final String P_BEHAVIOUR_INDEX = "behaviour-index"; private static final long serialVersionUID = 1L; int popSize, nAgents; int behaviourIndex; List<MetaPopulation> metaPops; // array with the length == number of agents, where each position indicates the agent-subpop allocation int[] allocations; int merges, splits; @Override public void setup(EvolutionState state, Parameter base) { nAgents = state.parameters.getInt(new Parameter("pop.subpops"), null); // TODO: bad dependency allocations = new int[nAgents]; behaviourIndex = state.parameters.getInt(base.push(P_BEHAVIOUR_INDEX), null); String initial = state.parameters.getString(base.push(P_INITIAL_ALLOCATION), null); if (initial.equalsIgnoreCase(V_HOMOGENEOUS)) { setInitialAllocation(1); } else if (initial.equalsIgnoreCase(V_HETEROGENEOUS)) { setInitialAllocation(nAgents); } else if (StringUtils.isNumeric(initial)) { int pops = Integer.parseInt(initial); setInitialAllocation(pops); } else { String[] split = initial.split("[\\s\\,\\-]+"); if (split.length != nAgents) { state.output.fatal("Initial allocation (" + split.length + ") does not match the number of agents (" + nAgents + ").", base.push(P_INITIAL_ALLOCATION)); } for (int i = 0; i < allocations.length; i++) { allocations[i] = Integer.parseInt(split[i].trim()); } } } public void setInitialAllocation(int pops) { allocations = new int[nAgents]; int div = nAgents / pops; int rem = nAgents % pops; int index = 0; for (int i = 0; i < pops; i++) { for (int j = 0; j < div; j++) { allocations[index++] = i; } if (rem > 0) { allocations[index++] = i; rem--; } } } /* * Generic hybrid exchanger mechanics, with support for foreign individuals */ @Override public Population preBreedingExchangePopulation(EvolutionState state) { merges = 0; splits = 0; // initialization -- first time in each evolutionary run if (metaPops == null) { popSize = state.population.subpops[0].individuals.length; initializationProcess(state); } else { // Only allows one operation per generation // reason: its important to evaluate before making any more changes merges = mergeProcess(state); if (merges == 0) { splits = splitProcess(state); } if (merges > 0 || splits > 0) { updateRepresentatives(state); } } // Update allocations for (int i = 0; i < metaPops.size(); i++) { for (Integer ag : metaPops.get(i).agents) { allocations[ag] = i; } } // create new population with individuals from metapops Population newPop = (Population) state.population.emptyClone(); newPop.subpops = new Subpopulation[metaPops.size()]; for (int i = 0; i < metaPops.size(); i++) { newPop.subpops[i] = metaPops.get(i).pop; } return newPop; } /* Update after breeding and prepare populations for evaluation */ @Override public Population postBreedingExchangePopulation(EvolutionState state) { // Update metapop with new individuals generated by the breeding process for (int i = 0; i < metaPops.size(); i++) { metaPops.get(i).pop = state.population.subpops[i]; // Mark all individuals for re-evaluation // Needed since the non-bred pops are copied from previous gens for (int j = 0; j < state.population.subpops[i].individuals.length; j++) { state.population.subpops[i].individuals[j].evaluated = false; } } // breeding phase has passed - update ages for (MetaPopulation mp : metaPops) { mp.age++; } return state.population; } protected void updateRepresentatives(EvolutionState state) { MultiPopCoevolutionaryEvaluatorThreaded base = state.evaluator instanceof MetaEvaluator ? (MultiPopCoevolutionaryEvaluatorThreaded) ((MetaEvaluator) state.evaluator).getBaseEvaluator() : (MultiPopCoevolutionaryEvaluatorThreaded) state.evaluator; Individual[][] newElites = new Individual[metaPops.size()][base.getEliteIndividuals()[0].length]; for (int i = 0; i < metaPops.size(); i++) { MetaPopulation mp = metaPops.get(i); Individual[] allInds = sortedCopy(mp.pop.individuals); for (int j = 0; j < newElites[i].length; j++) { newElites[i][j] = (Individual) allInds[j].clone(); } } base.setEliteIndividuals(newElites); } /* Initialization, merging and spliting algorithms */ protected void initializationProcess(EvolutionState state) { metaPops = new ArrayList<>(); for (int i = 0; i < state.population.subpops.length; i++) { MetaPopulation mp = new MetaPopulation(); mp.age = 0; for (int j = 0; j < allocations.length; j++) { if (allocations[j] == i) { mp.agents.add(j); } } if (!mp.agents.isEmpty()) { mp.pop = state.population.subpops[i]; metaPops.add(mp); } } } protected int mergeProcess(EvolutionState state) { return 0; } protected int splitProcess(EvolutionState state) { return 0; } protected static class MetaPopulation implements Serializable { private static final long serialVersionUID = 1L; List<Integer> agents; Subpopulation pop; int age; int lockDown; MetaPopulation() { this.agents = new ArrayList<>(); this.age = 0; } @Override public String toString() { String s = "["; for (int i = 0; i < agents.size() - 1; i++) { s += agents.get(i) + ","; } if (agents.size() > 0) { s += agents.get(agents.size() - 1); } return s + "]"; } } public int[] getAllocations() { return allocations; } protected List<MetaPopulation> getMetaPopulations() { return metaPops; } @Override public String runComplete(EvolutionState state) { return null; } /** * UTIL METHODS */ /* Uses final scores Sorts from the highest fitness to the lowest fitness */ protected static class FitnessComparator implements Comparator<Individual> { @Override public int compare(Individual o1, Individual o2) { return Double.compare(o2.fitness.fitness(), o1.fitness.fitness()); } } protected static Individual[] sortedCopy(Individual[] inds) { inds = Arrays.copyOf(inds, inds.length); Arrays.sort(inds, new FitnessComparator()); return inds; } protected static Individual[] getElitePortion(Individual[] inds, int num) { inds = sortedCopy(inds); Individual[] elite = new Individual[num]; System.arraycopy(inds, 0, elite, 0, num); return elite; } protected static BehaviourResult getAgentBR(Individual ind, int agent, int index) { ExpandedFitness nf = (ExpandedFitness) ind.fitness; CompoundEvaluationResult ser = (CompoundEvaluationResult) nf.getEvaluationResults()[index]; return (BehaviourResult) ser.getEvaluation(agent); } }