/*
* Datei: RekombinationTrivial.java
* Autor(en): Lukas K�nig
* Java-Version: 1.4
* Erstellt (vor): 17.12.2007
*
* (c) Lukas K�nig, die Datei unterliegt der LGPL
* -> http://www.gnu.de/lgpl-ger.html
*/
package fmg.fmg8.endlAutomat.rekombination;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.Random;
import fmg.fmg8.endlAutomat.RobCode;
import fmg.fmg8.endlAutomat.conditions.Condition;
import fmg.fmg8.sonstiges.SonstMeth;
import fmg.fmg8.umgebung2D.Roboter;
/**
* Implementiert eine triviale Rekombination, bei der in Abh�ngigkeit von der
* Fitness mit gr��erer Wahrscheinlichkeit das bessere Genom (von zweien)
* zur�ckgegeben wird.
*
* @author Lukas K�nig
*/
public class RekTrivial implements RekVerfahren {
/**
* Die Anzahl der Eltern.
*/
private int anzElt;
/**
* Die Anzahl der Kinder.
*/
private int anzKind;
/**
* Ob die Anzahl der Kinder maximal die Gr��e der urspr�nglichen
* Population sein soll.
*/
private boolean normieren;
/**
* Die gr��te m�gliche zur�ckgegebene Populationsgr��e.
*/
private int maxPopSize;
/**
* Der Zufallsgenerator.
*/
private Random rand;
/**
* Erzeugt ein Objekt der Klasse RekombinationTrivial, wobei eine
* Rekombination mit der angegebenen Anzahl von Eltern und Kinder
* eingestellt wird. Die Auswirkung auf die Anzahl der Individuen in der
* Kindpopulation muss jedoch erst daraus abgeleitet werden. Bitte die
* �brigen Kommentare beachten!
*
* @param anzEltern Die Anzahl der Eltern, die bei einer Rekombination
* betrachtet werden sollen.
* @param anzKinder Die Anzal der Kinder, die erzeugt werden sollen.
* @param norm Ob die Anzahl der Kinder maximal die Anzahl der
* Eltern sein soll.
* @param maxChild Die gr��te m�gliche zur�ckgegebene Populationsgr��e.
* @param random Der Zufallsgenerator.
*/
public RekTrivial(
final int anzEltern,
final int anzKinder,
final boolean norm,
final int maxChild,
final Random random) {
this.anzElt = anzEltern;
this.anzKind = anzKinder;
this.normieren = norm;
this.rand = random;
this.maxPopSize = maxChild;
}
/**
* Erzeugt soviele Kinder wie angegeben, wobei der beste Automat der Liste
* (im Sinne der Fitnessfunktion) geklont wird. Wenn es mehre gleich gute
* beste gibt, wird der erste beste Automat genommen. Die Fitness wird
* auch bei allen Kindern auf den Wert des Automaten des besten Elternteils
* gesetzt. Dieses Vorgehen wird, falls ein Roboter mehrere Automaten hat,
* f�r jeden Automaten einzeln durchgef�hrt.
* <BR>
* Bei so vielen Kinder wie es Eltern gibt wird als ID die ID eines
* Elternteils benutzt, um eine sp�tere Zuordnung zu einem Elternteil
* zu erm�glichen. Bei allen �brigen Kindern (falls vorhanden) wird die
* ID auf den ung�ltigen Wert -1 gesetzt. Insbesondere kann f�r Kinder > 1
* vorkommen, dass mehrere Kinder dieselbe ID haben: die zur�ckgegebenen
* Kinder stellen also im Allgemeinen KEINE g�ltige Population dar.
*
* @param rob Die Roboter.
*
* @return Die neue Roboterliste als Tupel (ID, Fitness, Code).
*/
@SuppressWarnings(value = { "unchecked" })
public RobCode[] rekombEinz(final Roboter[] rob) {
int[] bestFit = new int[rob[0].vAuts().length];
int[] bestInd = new int[rob[0].vAuts().length];
RobCode[] kinder = new RobCode[this.anzKind];
Condition[] conds;
int id;
int[] fits = new int[rob[0].vAuts().length];
String[] transStdCodes = new String[rob[0].vAuts().length];
LinkedList<Integer>[] verhCodes
= new LinkedList[rob[0].vAuts().length];
LinkedList<Integer>[] transCodes
= new LinkedList[rob[0].vAuts().length];
// Bestes Individuum suchen.
for (int j = 0; j < rob[0].vAuts().length; j++) {
bestFit[j] = Integer.MIN_VALUE;
bestInd[j] = 0;
}
for (int i = 0; i < rob[0].vAuts().length; i++) {
for (int j = 0; j < rob.length; j++) {
if (rob[j] != null && bestFit[i] < rob[j].getFitness()[i]) {
bestFit[i] = rob[j].getFitness()[i];
bestInd[i] = j;
}
}
}
// Bestes Individuum merken.
for (int i = 0; i < rob[0].vAuts().length; i++) {
verhCodes[i] = rob[bestInd[i]].getVerhCodes()[i];
transCodes[i] = rob[bestInd[i]].getTransCodes()[i];
transStdCodes[i] = rob[bestInd[i]].getTransStdCodes()[i];
fits[i] = rob[bestInd[i]].getFitness()[i];
}
// Neue Robcodes als Klone des besten erzeugen.
for (int i = 0; i < this.anzKind; i++) {
if (i < rob.length) {
id = rob[i].getId();
conds = rob[i].getConds(); // TODO
} else {
id = rob[0].getId();
conds = rob[0].getConds(); // TODO
}
kinder[i] = new RobCode(
id,
fits,
SonstMeth.stringAusListSeqs(verhCodes),
conds,
transStdCodes,
SonstMeth.stringAusListSeqs(transCodes),
SonstMeth.stringAusListSeqs(verhCodes));
}
return kinder;
}
/**
* F�hrt eine Rekombination der gesamten Population durch. Die
* Rekombination geschieht auf Basis der Methode <code>rekombEinz</code>.
* Es werden die am n�chsten zusammenstehenden Roboter rekombiniert.
* <BR>
* Zu beachten ist, dass von JEDEM Roboter aus einmal die n�chsten
* berechnet und diese zusammen zu Kindern rekombiniert werden.
* Um die Population bei gleicher Gr��e zu belassen, gen�gt also ein
* Verh�ltnis (Eltern / Kinder) = N / 1. Bei dieser Rekombination ist
* es nicht m�glich, eine Kindpopulation zu erzeugen, die kleiner ist als
* die Elternpopulation (au�er durch setzen des Normierungsattributs).
*
* @param elternPop Die zu rekombinierende Population von Robotern.
*
* @return Die rekombinierte Population als Tupel (ID, Code).
*/
public ArrayList<RobCode> rekombiniere(
final ArrayList<Roboter> elternPop) {
Iterator<Roboter> it;
Roboter rob1;
Roboter rob2;
Roboter[] eltern = new Roboter[this.anzElt];
RobCode[] kinder;
ArrayList<RobCode> kindPop = new ArrayList<RobCode>();
HashSet<Roboter> nicht = new HashSet<Roboter>(this.anzElt);
it = elternPop.iterator();
while (it.hasNext()) {
nicht.clear();
rob1 = it.next();
eltern[0] = rob1;
nicht.add(rob1);
for (int i = 1; i < this.anzElt; i++) {
rob2 = rob1.getUmg().holeNahenNorm(
(int) rob1.getPosition().x,
(int) rob1.getPosition().y,
nicht);
if (rob2 == null) {
rob2 = rob1;
}
nicht.add(rob2);
eltern[i] = rob2;
}
kinder = this.rekombEinz(eltern);
for (int i = 0; i < this.anzKind; i++) {
kindPop.add(kinder[i]);
}
}
if (this.normieren) {
while (kindPop.size() > elternPop.size()) {
kindPop.remove(this.rand.nextInt(kindPop.size()));
}
}
while (kindPop.size() > this.maxPopSize) {
kindPop.remove(this.rand.nextInt(kindPop.size()));
}
return kindPop;
}
}