eva2/src/eva2/server/go/populations/Population.java
2008-09-17 09:58:26 +00:00

1108 lines
39 KiB
Java

package eva2.server.go.populations;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.PriorityQueue;
import java.util.Set;
import wsi.ra.math.RNG;
import eva2.server.go.IndividualInterface;
import eva2.server.go.InterfacePopulationChangedEventListener;
import eva2.server.go.PopulationInterface;
import eva2.server.go.individuals.AbstractEAIndividual;
import eva2.server.go.individuals.AbstractEAIndividualComparator;
import eva2.server.go.individuals.GAIndividualBinaryData;
import eva2.server.go.operators.distancemetric.InterfaceDistanceMetric;
import eva2.server.go.operators.distancemetric.PhenotypeMetric;
import eva2.server.go.operators.selection.probability.AbstractSelProb;
import eva2.tools.EVAERROR;
import eva2.tools.Mathematics;
import eva2.tools.Pair;
/** This is a basic implementation for a EA Population.
* Copyright: Copyright (c) 2003
* Company: University of Tuebingen, Computer Architecture
* @author Felix Streichert, Marcel Kronfeld
* @version: $Revision: 307 $
* $Date: 2007-12-04 14:31:47 +0100 (Tue, 04 Dec 2007) $
* $Author: mkron $
*/
public class Population extends ArrayList implements PopulationInterface, Cloneable, java.io.Serializable {
protected int m_Generation = 0;
protected int m_FunctionCalls = 0;
protected int m_Size = 50;
protected Population m_Archive = null;
transient private ArrayList<AbstractEAIndividual> sortedArr = null;
transient private ArrayList<InterfacePopulationChangedEventListener> listeners = null;
// transient protected InterfacePopulationChangedEventListener m_Listener = null;
// the evaluation interval at which listeners are notified
protected int notifyEvalInterval = 0;
protected HashMap<String, Object> additionalPopData = null;
public static final String funCallIntervalReached = "FunCallIntervalReached";
public static final String populationInitialized = "PopulationReinitOccured";
public static final String nextGenerationPerformed = "NextGenerationPerformed";
boolean useHistory = false;
public ArrayList<AbstractEAIndividual> m_History = new ArrayList<AbstractEAIndividual>();
// remember when the last sorted queue was prepared
private int lastQModCount = -1;
// remember when the last evaluation was performed
private Pair<Integer,Integer> evaluationTimeHashes = null;
// remember when the last evaluation was performed
private int evaluationTimeModCount = -1;
public Population() {
}
/**
* Constructor setting initial capacity and population size to the given
* integer value.
*
* @param initialCapacity initial capacity and population size of the instance
*/
public Population(int initialCapacity) {
super(initialCapacity);
setPopulationSize(initialCapacity);
}
public Population(Population population) {
setSameParams(population);
for (int i = 0; i < population.size(); i++) {
if (population.get(i) != null)
this.add((((AbstractEAIndividual)population.get(i))).clone());
}
copyHistAndArchive(population);
}
public void copyHistAndArchive(Population population) {
if (population.m_Archive != null) this.m_Archive = (Population)population.m_Archive.clone();
if (population.m_History != null) this.m_History = (ArrayList)population.m_History.clone();
}
/**
* Takes over all scalar parameters of the given population.
* @param population
*/
public void setSameParams(Population population) {
this.m_Generation = population.m_Generation;
this.m_FunctionCalls = population.m_FunctionCalls;
this.m_Size = population.m_Size;
this.useHistory = population.useHistory;
this.notifyEvalInterval = population.notifyEvalInterval;
// this.m_Listener = population.m_Listener;
if (population.listeners != null) this.listeners = (ArrayList<InterfacePopulationChangedEventListener>)population.listeners.clone();
else listeners = null;
if (population.additionalPopData != null) {
additionalPopData = new HashMap<String, Object>();
Set<String> keys = additionalPopData.keySet();
for (String key : keys) {
additionalPopData.put(key, population.additionalPopData.get(key));
}
}
}
public void putData(String key, Object value) {
if (additionalPopData == null) additionalPopData = new HashMap<String, Object>();
additionalPopData.put(key, value);
}
public Object getData(String key) {
if (additionalPopData == null) return null;
else return additionalPopData.get(key);
}
public boolean hasData(String key) {
if (additionalPopData != null) return (additionalPopData.get(key)!=null);
else return false;
}
public Object clone() {
return (Object) new Population(this);
}
/**
* Clone the population without cloning every individual. This produces an empty population
* which can be used to fill with the next generation by an EA and is implemented for efficiency.
*
* @return an empty population with equal members but not containing any individuals
*/
public Population cloneWithoutInds() {
// these two basically clone without cloning every individual
Population res = new Population();
res.setSameParams(this);
res.copyHistAndArchive(this);
if (additionalPopData!=null) res.additionalPopData = (HashMap<String, Object>)(additionalPopData.clone());
return res;
}
/** This method inits the state of the population AFTER the individuals
* have been inited by a problem
*/
public void init() {
this.m_History = new ArrayList();
this.m_Generation = 0;
this.m_FunctionCalls = 0;
evaluationTimeHashes = null;
evaluationTimeModCount = -1;
if (this.m_Archive != null) {
this.m_Archive.clear();
this.m_Archive.init();
}
firePropertyChangedEvent(Population.populationInitialized);
}
/** This method inits the population. Function and generation counters
* are reset and m_Size default Individuals are created and initialized by
* the GAIndividual default init() method.
*/
public void defaultInitPopulation() {
GAIndividualBinaryData tmpIndy;
this.m_Generation = 0;
this.m_FunctionCalls = 0;
this.m_Archive = null;
this.clear();
for (int i = 0; i < this.m_Size; i++) {
tmpIndy = new GAIndividualBinaryData();
tmpIndy.defaultInit();
super.add(tmpIndy);
}
}
/**
* Activate or deactivate the history tracking, which stores the best individual in every
* generation in the incrGeneration() method.
*
* @param useHist
*/
public void setUseHistory(boolean useHist) {
useHistory = useHist;
}
/** This method will allow you to increment the current number of function calls.
*/
public void incrFunctionCalls() {
this.m_FunctionCalls++;
if (doEvalNotify()) {
// System.out.println("checking funcall event...");
if ((m_FunctionCalls % notifyEvalInterval) == 0) firePropertyChangedEvent(funCallIntervalReached);
}
}
/**
* This method will allow you to increment the current number of function calls by a number > 1.
* Notice that it might slightly disturb notification if a notifyEvalInterval is set.
*
* @param d The number of function calls to increment.
*/
public void incrFunctionCallsBy(int d) {
if (doEvalNotify()) {
// System.out.println("checking funcall event...");
int nextStep; // next interval boundary
while ((nextStep = calcNextBoundary()) <= (m_FunctionCalls+d)) {
// the notify interval will be stepped over or hit
int toHit = (nextStep - m_FunctionCalls);
this.m_FunctionCalls += toHit; // little cheat, notify may be after some more evals
firePropertyChangedEvent(funCallIntervalReached);
d = d-toHit;
// this.m_FunctionCalls += (d-toHit);
}
if (d>0) this.m_FunctionCalls += d; // add up the rest
} else this.m_FunctionCalls += d;
}
private int calcNextBoundary() {
return ((m_FunctionCalls/notifyEvalInterval)+1) * notifyEvalInterval;
}
/** Something has changed
*/
protected void firePropertyChangedEvent(String name) {
if (listeners != null) {
for (Iterator iterator = listeners.iterator(); iterator.hasNext();) {
InterfacePopulationChangedEventListener listener = (InterfacePopulationChangedEventListener) iterator.next();
if (listener!=null) listener.registerPopulationStateChanged(this, name);
}
}
}
private boolean doEvalNotify() {
return ((listeners != null) && (listeners.size() > 0) && (notifyEvalInterval > 0));
}
/** This method return the current number of function calls performed.
* @return The number of function calls performed.
*/
public int getFunctionCalls() {
return this.m_FunctionCalls;
}
/** This method set the current number of function calls performed.
* Use with care
* @param d The new number of functioncalls.
*/
public void SetFunctionCalls(int d) {
this.m_FunctionCalls = d;
}
/**
* To initialize (or invalidate) all current fitness values, this method sets them
* to the given array.
*
* @param f
*/
public void setAllFitnessValues(double[] f) {
AbstractEAIndividual indy;
for (int i=0; i<size(); i++) {
indy = getEAIndividual(i);
indy.SetFitness(f.clone());
}
}
/** This method allows you to increment the current number of generations.
* This will be the trigger for the Population, that has moved from t to t+1.
* Here overaged Individuals can be removed. The best of class can be identified.
* Stagnation measured etc. pp.
*/
public void incrGeneration() {
if (useHistory && (this.size() >= 1)) this.m_History.add(this.getBestEAIndividual());
for (int i=0; i<size(); i++) ((AbstractEAIndividual)get(i)).incrAge();
this.m_Generation++;
firePropertyChangedEvent(nextGenerationPerformed);
}
/** This method returns the current generation.
* @return The current generation index.
*/
public int getGeneration() {
return this.m_Generation;
}
/** This method sets the generation.
* @param gen the value to set as new generation index
*/
public void setGenerationTo(int gen) {
this.m_Generation = gen;
}
/** This method allows you to add the LectureGUI as listener to the Optimizer
* @param ea
*/
public void addPopulationChangedEventListener(InterfacePopulationChangedEventListener ea) {
if (ea != null) {
if (listeners == null) listeners = new ArrayList<InterfacePopulationChangedEventListener>(3);
if (!listeners.contains(ea)) {
listeners.add(ea);
}
}
}
public void removePopulationChangedEventListener(InterfacePopulationChangedEventListener ea) {
if (listeners != null) {
listeners.remove(ea);
}
}
/** This method allows you to add a complete population to the current population.
* Note: After this operation the target population size may be exceeded.
* @param pop The population that is to be added.
*/
public void addPopulation(Population pop) {
if (pop == null) return;
for (int i = 0; i < pop.size(); i++) {
AbstractEAIndividual indy = (AbstractEAIndividual)pop.get(i);
if (indy != null) {
this.add(indy);
}
}
}
/**
* Resets the fitnes to the maximum possible value for the given individual.
*
* @param indy an individual whose fitness will be reset
*/
public void resetFitness(IndividualInterface indy) {
double[] tmpFit = indy.getFitness();
java.util.Arrays.fill(tmpFit, Double.MAX_VALUE);
indy.SetFitness(tmpFit);
}
/**
* Return all individuals dominating an individual given by index.
*
* @param index
* @return all individuals dominating a given individual
*/
public Population getDominatingSet(int index) {
Population domSet = new Population();
AbstractEAIndividual indy;
for (int i = 0; i < super.size(); i++) {
if (i != index) {
indy = getEAIndividual(i);
if (indy.isDominatingDebConstraints(getEAIndividual(index))) domSet.add(indy);
}
}
return domSet;
}
/**
* Return all individuals dominating a given individual.
*
* @param indy
* @return all individuals dominating a given individual
*/
public Population getDominatingSet(AbstractEAIndividual indy) {
Population domSet = new Population();
AbstractEAIndividual tmpIndy;
for (int i = 0; i < super.size(); i++) {
tmpIndy = getEAIndividual(i);
if (tmpIndy.isDominatingDebConstraints(indy)) domSet.add(tmpIndy);
}
return domSet;
}
private boolean compareFit(boolean bChooseBetter, double[] fit1, double[] fit2) {
if (bChooseBetter) return AbstractEAIndividual.isDominatingFitness(fit1, fit2);
else return AbstractEAIndividual.isDominatingFitness(fit2, fit1);
}
/**
* This method will return the index of the current best individual from the
* population. If the population is empty, -1 is returned.
*
* @see getIndexOfBestOrWorstIndividual()
* @return The index of the best individual.
*/
public int getIndexOfBestIndividual() {
if (size()<1) return -1;
return getIndexOfBestOrWorstIndividual(true, true);
}
/**
* This method will return the index of the current best individual from the
* population.
*
* @see getIndexOfBestOrWorstIndividual()
* @return The index of the best individual.
*/
public int getIndexOfWorstIndividual() {
return getIndexOfBestOrWorstIndividual(false, false);
}
/**
* This method will return the index of the current best (worst) individual from the
* population. If indicated, only those are regarded which do not violate the constraints.
* If all violate the constraints, the smallest (largest) violation is selected.
* Comparisons are done multicriterial, but note that for incomparable sets (pareto fronts)
* this selection will not be fair (always the lowest index of incomparable sets will be returned).
*
* @param bBest if true, smallest fitness (regarded best) index is returned, else the highest one
* @param indicate whether constraints should be regarded
* @return The index of the best (worst) individual.
*/
public int getIndexOfBestOrWorstIndividual(boolean bBest, boolean checkConstraints) {
int result = -1;
double[] curSelFitness = null;
boolean allViolate = true;
for (int i = 0; i < super.size(); i++) {
if (!checkConstraints || !(getEAIndividual(i).violatesConstraint())) {
allViolate = false;
if ((result<0) || (compareFit(bBest, getEAIndividual(i).getFitness(), curSelFitness))) {
// fit i is better than remembered
result = i;
curSelFitness = getEAIndividual(i).getFitness(); // remember fit i
}
}
}
if (result < 0) {
if (checkConstraints && allViolate) {
// darn all seem to violate the constraint
// so lets search for the guy who is close to feasible
// to avoid problems with NaN or infinite fitness value, preselect an ind.
result = 0;
double minViol = getEAIndividual(0).getConstraintViolation();
for (int i = 1; i < super.size(); i++) {
if ((bBest && getEAIndividual(i).getConstraintViolation() < minViol) ||
(!bBest && (getEAIndividual(i).getConstraintViolation() > minViol))) {
result = i;
minViol = ((AbstractEAIndividual)super.get(i)).getConstraintViolation();
}
}
System.err.println("Population reports: All individuals violate the constraints, choosing smallest constraint violation.");
} else {
// not all violate, maybe all are NaN!
// so just select a random one
System.err.println("Population reports: All individuals seem to have NaN or infinite fitness!");
result = RNG.randomInt(size());
}
}
return result;
}
/**
* This method returns the current best individual from the population.
* If the population is empty, null is returned.
*
* @return The best individual
*/
public AbstractEAIndividual getBestEAIndividual() {
if (size()<1) return null;
int best = this.getIndexOfBestIndividual();
if (best == -1) {
System.err.println("This shouldnt happen!");
return null;
} else {
AbstractEAIndividual result = (AbstractEAIndividual)this.get(best);
if (result == null) System.err.println("Serious Problem! Population Size: " + this.size());
return result;
}
}
/**
* This method returns the n current best individuals from the population, where
* the sorting criterion is delivered by an AbstractEAIndividualComparator.
* There are less than n individuals returned if the population is smaller than n.
* If n is <= 0, then all individuals are returned and effectively just sorted
* by fitness.
* This does not check constraints!
*
* @param n number of individuals to look out for
* @return The m best individuals, where m <= n
*
*/
public Population getBestNIndividuals(int n) {
return getSortedNIndividuals(n, true);
}
/**
* This method returns a clone of the population instance with sorted individuals, where
* the sorting criterion is delivered by an AbstractEAIndividualComparator.
* @see #getSortedNIndividuals(int, boolean, Population)
*
* @return a clone of the population instance with sorted individuals, best fitness first
*/
public Population getSortedBestFirst() {
Population result = this.cloneWithoutInds();
getSortedNIndividuals(size(), true, result);
result.setPopulationSize(result.size());
return result;
}
/**
* This method returns the n current best individuals from the population, where
* the sorting criterion is delivered by an AbstractEAIndividualComparator.
* @see getSortedNIndividuals(int n, boolean bBestOrWorst, Population res)
*
* @param n number of individuals to look out for
* @param bBestOrWorst if true, the best n are returned, else the worst n individuals
* @return The m sorted best or worst individuals, where m <= n
*
*/
public Population getSortedNIndividuals(int n, boolean bBestOrWorst) {
Population result = new Population(n);
getSortedNIndividuals(n, bBestOrWorst, result);
return result;
}
/**
* This method returns the n current best individuals from the population, where
* the sorting criterion is delivered by an AbstractEAIndividualComparator.
* There are less than n individuals returned if the population is smaller than n.
* This does not check constraints!
*
* @param n number of individuals to look out for
* @param bBestOrWorst if true, the best n are returned, else the worst n individuals
* @param res sorted result population, will be cleared
* @return The m sorted best or worst individuals, where m <= n
*
*/
public void getSortedNIndividuals(int n, boolean bBestOrWorst, Population res) {
if ((n < 0) || (n>super.size())) {
// this may happen, treat it gracefully
//System.err.println("invalid request to getSortedNIndividuals: n="+n + ", size is " + super.size());
n = super.size();
}
int skip = 0;
if (!bBestOrWorst) skip = super.size()-n;
ArrayList<AbstractEAIndividual> sorted = getSorted();
res.clear();
for (int i = skip; i < skip+n; i++) {
res.add(sorted.get(i));
}
res.setPopulationSize(res.size());
}
/**
* Avoids having to sort again in several calls without modifications in between.
* The returned array should not be modified!
*
* @return
*/
protected ArrayList<AbstractEAIndividual> getSorted() {
if (sortedArr == null || (super.modCount != lastQModCount)) {
PriorityQueue<AbstractEAIndividual> sQueue = new PriorityQueue<AbstractEAIndividual>(super.size(), new AbstractEAIndividualComparator());
for (int i = 0; i < super.size(); i++) {
sQueue.add(getEAIndividual(i));
}
lastQModCount = super.modCount;
if (sortedArr==null) sortedArr = new ArrayList<AbstractEAIndividual>(this.size());
else sortedArr.clear();
AbstractEAIndividual indy;
while ((indy=sQueue.poll())!=null) sortedArr.add(indy);
}
return sortedArr;
}
/** This method returns n random best individuals from the population.
*
* @param n number of individuals to look out for
* @return The n best individuals
*
*/
public List<AbstractEAIndividual> getRandNIndividuals(int n) {
return getRandNIndividualsExcept(n, new Population());
}
/** This method returns the n current best individuals from the population in an object array.
*
* @param n number of individuals to look out for
* @return The n best individuals
*
*/
public Population getRandNIndividualsExcept(int n, Population exclude) {
return moveNInds(n, filter(exclude), new Population());
}
/**
* Moves n random individuals from src Population to dst Population and returns dst Population.
*
* @param n
* @param from
* @param to
* @return
*/
public static Population moveNInds(int n, Population src, Population dst) {
if ((n == 0) || (src.size() == 0)) return dst;
else { // Ingenious superior Scheme tail recursive style!
moveRandIndFromTo(src, dst);
return moveNInds(n-1, src, dst);
}
}
/**
* Move one random individual from src to dst population.
* @param from
* @param to
*/
public static void moveRandIndFromTo(Population src, Population dst) {
int k = RNG.randomInt(src.size());
dst.add(src.remove(k));
}
/**
* Returns a subset of this population which does not contain the individuals
* in the given exclude list as shallow copies.
* @param exclude
* @return
*/
public Population filter(Population exclude) {
if (exclude.size() == 0) return this;
Population pop = new Population();
for (Object o : this) {
if (!exclude.contains(o)) pop.add(o);
}
return pop;
}
/**
* This method returns the currently worst individual from the population
* @return The best individual
*/
public AbstractEAIndividual getWorstEAIndividual() {
return getEAIndividual(getIndexOfWorstIndividual());
}
/**
* This method will remove N individuals from the population
* Note: the current strategy will be remove N individuals
* at random but later a special heuristic could be introduced.
* @param n The number of individuals for be removed
*/
public void removeNIndividuals(int n) {
for (int i = 0; i < n; i++) {
this.remove(RNG.randomInt(0, this.size()-1));
}
}
/** This method will remove double instances from the population.
* This method relies on the implementation of the equals method
* in the individuals.
*/
public void removeDoubleInstances() {
for (int i = 0; i < this.size(); i++) {
for (int j = i+1; j < this.size(); j++) {
if (((AbstractEAIndividual)this.get(i)).equals(this.get(j))) {
this.remove(j);
j--;
}
}
}
}
/** This method will remove double instances from the population.
* This method relies on the implementation of the equals method
* in the individuals.
*/
public void removeDoubleInstancesUsingFitness() {
for (int i = 0; i < this.size(); i++) {
for (int j = i+1; j < this.size(); j++) {
if (((AbstractEAIndividual)this.get(i)).equalFitness((AbstractEAIndividual)this.get(j))) {
this.remove(j);
j--;
}
}
}
}
/** This method returns all marked individuals
* @return a population of marked individuals
*/
public Population getMarkedIndividuals() {
Population result = new Population();
for (int i = 0; i < this.size(); i++) {
if (((AbstractEAIndividual)this.get(i)).isMarked()) {
result.add(this.get(i));
}
}
return result;
}
/** This method will unmark all individual in the population
*/
public void unmarkAllIndividuals() {
for (int i = 0; i < this.size(); i++) {
((AbstractEAIndividual)this.get(i)).unmark();
}
}
/** This method returns problem specific data
* @return double[]
*/
public double[] getSpecificData() {
return null;
}
/** This method returns identifiers for the
* specific data
* Note: "Pareto-Front" is reserved for mulit-crit. Problems
* @return String[]
*/
public String[] getSpecificDataNames() {
return null;
}
/** This method allows you to access the archive
* @return The archive
*/
public Population getArchive() {
return this.m_Archive;
}
/** This method allows you to set the current archive
* @param a The new archive
*/
public void SetArchive(Population a) {
this.m_Archive = a;
}
/** This method will return a string description of the GAIndividal
* noteably the Genotype.
* @return A descriptive string
*/
public String getStringRepresentation() {
StringBuilder strB = new StringBuilder(200);
strB.append("Population:\nPopulation size: ");
strB.append("Population size: ");
strB.append(this.size());
strB.append("\nFunction calls : ");
strB.append(this.m_FunctionCalls);
strB.append("\nGenerations : ");
strB.append(this.m_Generation);
strB.append("\n");
for (int i = 0; i < this.size(); i++) {
strB.append(((AbstractEAIndividual)this.get(i)).getStringRepresentation());
strB.append("\n");
}
return strB.toString();
}
/**
* Return a list of individual IDs from the population.
* @return
*/
public Long[] getIDList() {
Long[] idList = new Long[size()];
for (int i=0; i<idList.length; i++) {
idList[i]=getEAIndividual(i).getIndyID();
}
return idList;
}
// public Long[][] getParentalIDList() {
// Long[][] idList = new Long[size()][];
// for (int i=0; i<idList.length; i++) {
// idList[i]=getEAIndividual(i).getHeritage();
// }
// return idList;
// }
/**
* Get a string containing representations of all individuals contained.
*/
public String getIndyList() {
StringBuffer sb = new StringBuffer();
for (int i=0; i<size(); i++) {
sb.append(AbstractEAIndividual.getDefaultStringRepresentation(getEAIndividual(i)));
sb.append(", generation: ");
sb.append(getGeneration());
sb.append("\n");
}
return sb.toString();
}
/**********************************************************************************************************************
* These are for GUI
*/
/** This method returns a global info string
* @return description
*/
public String globalInfo() {
return "A population stores the individuals of a generation.";
}
/** This method allows you to set the population size
* @param size
*/
public void setPopulationSize(int size) {
this.m_Size = size;
// int rand;
// if (this.size() != 0) {
// while (this.size() < size) {
// rand = RNG.randomInt(0, this.size()-1);
// this.add(((AbstractEAIndividual)this.get(rand)).clone());
// }
// while (this.size() > size) {
// rand = RNG.randomInt(0, this.size()-1);
// this.remove(rand);
// }
// }
// System.out.println("This.size() = "+this.size() +" this.getSize() = " + this.m_Size);
}
public int getPopulationSize() {
return this.m_Size;
}
public String populationSizeTipText() {
return "The population size.";
}
public AbstractEAIndividual getEAIndividual(int i) {
return (AbstractEAIndividual)this.get(i);
}
/**********************************************************************************************************************
* Implementing the PopulationInterface
*/
public Object getClone() {
return this.clone();
}
public IndividualInterface getIndividual(int i) {
return (IndividualInterface)this.get(i);
}
public boolean add(IndividualInterface o) {
return addIndividual((IndividualInterface)o);
}
/**
* ArrayList does not increase the modCount in set. Why???
*/
public Object set(int index, Object element) {
Object prev = super.set(index, element);
modCount++;
return prev;
}
public boolean addIndividual(IndividualInterface ind) {
super.add(ind);
return true;
}
/**
* Remove an individual from the population efficiently by switching it with last position
* and removing that.
*
* @param index individual index to be removed
*/
public void removeIndexSwitched(int index) {
int lastIndex = size()-1;
if (index < lastIndex) set(index, get(lastIndex));
remove(lastIndex);
}
/**
* Replaces an individual at a certain index with the given one. The old one is returned.
*
* @param index
* @param ind
* @return
*/
public IndividualInterface replaceIndividualAt(int index, IndividualInterface ind) {
return (IndividualInterface)set(index, ind);
}
public void removeIndividual (IndividualInterface ind) {
for (int i = 0; i < this.size(); i++) {
if (ind.equals(this.get(i))) {
this.remove(i);
return;
}
}
}
public IndividualInterface getBestIndividual() {
return (IndividualInterface)this.getBestEAIndividual();
}
public IndividualInterface getWorstIndividual() {
return (IndividualInterface)this.getWorstEAIndividual();
}
public double[] getBestFitness() {
return this.getBestEAIndividual().getFitness();
}
public double[] getWorstFitness() {
return this.getWorstEAIndividual().getFitness();
}
public double[] getMeanFitness() {
double[] result, tmp;
tmp = this.getBestFitness();
result = new double[tmp.length];
for (int i = 0; i <this.size(); i++) {
tmp = ((AbstractEAIndividual)this.get(i)).getFitness();
for (int j = 0; j < result.length; j++) {
result[j] += tmp[j];
}
}
for (int j = 0; j < result.length; j++) {
result[j] = result[j]/((double)this.size());
}
return result;
}
/**
* Returns the average, minimal and maximal phenotypic individual distance as diversity measure for the population.
* Distances are thus scaled by the problem range.
*
* @return the average, minimal and maximal mean distance of individuals in an array of three
*/
public double[] getPopulationMeasures() {
return getPopulationMeasures(new PhenotypeMetric());
}
/**
* Returns the average, minimal and maximal individual distance as diversity measure for the population.
* If the given metric argument is null, the euclidian distance of individual positions is used, which
* presumes that {@link AbstractEAIndividual.getDoublePosition(indy)} returns a valid double position for the
* individuals of the population.
* This is of course rather expensive computationally.
*
* @return the average, minimal and maximal mean distance of individuals in an array of three
*/
public double[] getPopulationMeasures(InterfaceDistanceMetric metric) {
double d;
double[] res = new double[3];
double meanDist = 0.;
double maxDist = Double.MIN_VALUE;
double minDist = Double.MAX_VALUE;
for (int i = 0; i < this.size(); i++) {
for (int j = i+1; j < this.size(); j++) {
if (metric == null) d = PhenotypeMetric.euclidianDistance(AbstractEAIndividual.getDoublePosition(getEAIndividual(i)),
AbstractEAIndividual.getDoublePosition(getEAIndividual(j)));
else d = metric.distance((AbstractEAIndividual)this.get(i), (AbstractEAIndividual)this.get(j));
meanDist += d;
if (d < minDist) minDist = d;
if (d > maxDist) maxDist = d;
}
}
res[0] = meanDist / (this.size() * (this.size()-1) / 2);
res[1] = minDist;
res[2] = maxDist;
return res;
}
/**
* Calculate the average position of the population.
*
* @return the average position of the population
*/
public double[] getCenter() {
if (size()==0) EVAERROR.errorMsgOnce("Invalid pop size in DistractingPopulation:getCenter!");
double[] centerPos = AbstractEAIndividual.getDoublePosition(getEAIndividual(0));
for (int i=1; i<size(); i++) {
Mathematics.vvAdd(centerPos, AbstractEAIndividual.getDoublePosition(getEAIndividual(i)), centerPos);
}
Mathematics.svDiv(size(), centerPos, centerPos);
return centerPos;
}
/**
* Calculate the weighted center position of the population. Weights must add up to one!
*
* @return the average position of the population
*/
public double[] getCenterWeighted(double[] weights) {
if (size()==0 || (weights.length > size())) EVAERROR.errorMsgOnce("Invalid pop size in DistractingPopulation:getCenterWeighted!");
double[] centerPos = AbstractEAIndividual.getDoublePosition(getEAIndividual(0));
Mathematics.svMult(weights[0], centerPos, centerPos);
for (int i=1; i<weights.length; i++) {
Mathematics.svvAddScaled(weights[i], AbstractEAIndividual.getDoublePosition(getEAIndividual(i)), centerPos, centerPos);
}
return centerPos;
}
/**
* Return the population center weighted by fitness, using the same scaling as provided
* by a SelectionProbability instance.
* This only works for those individuals that have a position representation, meaning that
* AbstractEAIndidivual.getDoublePosition(individual) returns a valid position.
* If they dont, null is returned.
*
* @see AbstractEAIndidivual.getDoublePosition(individual)
* @param criterion
* @return
*/
public double[] getCenterWeighted(AbstractSelProb selProb, int criterion, boolean obeyConst) {
selProb.computeSelectionProbability(this, "Fitness", obeyConst);
double[] mean = AbstractEAIndividual.getDoublePosition(getEAIndividual(0));
if (mean != null) {
Arrays.fill(mean, 0.);
AbstractEAIndividual indy = null;
for (int i=0; i<size(); i++) {
indy = getEAIndividual(i);
double[] pos = AbstractEAIndividual.getDoublePosition(indy);
Mathematics.svvAddScaled(indy.getSelectionProbability(criterion), pos, mean, mean);
}
}
return mean;
}
/**
* Fire an event every n function calls, the event sends the public String funCallIntervalReached.
* Be aware that if this interval is smaller than the population size, it may happen that a notification
* is fired before all individuals have been evaluated once, meaning that a false zero fitness
* appears at the beginning of the optimization.
*
* @param notifyEvalInterval the notifyEvalInterval to set
*/
public void setNotifyEvalInterval(int notifyEvalInterval) {
this.notifyEvalInterval = notifyEvalInterval;
}
/**
* Fit the population to its targeted population size. If it contains too many
* individuals, the last ones are removed. If it contains too few individuals,
* the first ones are cloned in a cycle.
* If the size matches, nothing happens. If there is no individual already contained,
* this method cannot grow, of course.
*/
public void fitToSize() {
if (size() != getPopulationSize()) {
while (size() > getPopulationSize()) remove(size()-1);
if (size() < getPopulationSize()) {
if (size() == 0) System.err.println("Cannot grow empty population!");
else {
int origSize=size();
int k=0;
while (size()< getPopulationSize()) {
addIndividual((AbstractEAIndividual)getEAIndividual(k%origSize).clone());
}
}
}
}
}
/**
* Calculate the fitness sum over all individuals for one criterion.
*
* @param criterion
* @return the fitness sum over all individuals for one criterio
*/
public double getFitSum(int criterion) {
double fSum = 0.;
for (int i=0; i<size(); i++) {
fSum += getEAIndividual(i).getFitness(criterion);
}
return fSum;
}
/**
* Set the desired population size parameter to the actual current size.
*
*/
public void synchSize() {
setPopulationSize(size());
}
// /**
// * Check whether the population at the current state has been marked as
// * evaluated. This allows to avoid double evaluations.
// *
// * @return true if the population has been marked as evaluated in its current state, else false
// */
// public boolean isEvaluated() {
// if (evaluationTimeModCount != modCount) return false;
// Pair<Integer,Integer> hashes = getIndyHashSums();
//
// if (evaluationTimeHashes == null) return false;
// else return ((hashes.head().equals(evaluationTimeHashes.head())) && (hashes.tail().equals(evaluationTimeHashes.tail())) && (evaluationTimeModCount == modCount));
// }
// /**
// * Mark the population at the current state as evaluated. Changes to the modCount or hashes of individuals
// * will invalidate the mark.
// *
// * @see isEvaluated()
// */
// public void setEvaluated() {
// evaluationTimeModCount = modCount;
// evaluationTimeHashes = getIndyHashSums();
// }
// private Pair<Integer,Integer> getIndyHashSums() {
// int hashSum = 0, hashSumAbs = 0;
// int hash;
// for (int i=0; i<size(); i++) {
// hash = get(i).hashCode();
// hashSum += hash;
// hashSumAbs += Math.abs(hash);
// }
// return new Pair(hashSum, hashSumAbs);
// }
}