\begin{matlab}
function strengthga( overallfitness )
%STRENGTHGA Genetischer Algorithmus zur Anpassung der Fitnesswerte
%   Dieser GA soll nach mehreren erfolgten Simulationsläufen mit dem
%   gleichen Regelsatz aber unterschiedlichen Fitnesswerten der einzelnen
%   Regeln die Ergebnisse der Läufe miteinander vergleichen und aufgrund
%   der globalen Fitness der entstandenen Strukturen die einzelnen
%   Stärkewerte der Regeln genetisch rekombinieren. Dadurch sollen neue
%   Regelsätze erzeugt werden, die sich nur durch die Fitness der einzelnen
%   Regeln von den alten Regelsätzen unterscheiden.

global wespe;
global Wabengitter;
global MittelWabe;

% variable Parameter:
probcrossover = 0.6; % Crossoverwahrscheinlichkeit
probmutation = 0.2; % Mutationswahrscheinlichkeit
elternzahl = 100; % Zahl der auszuwählenden Individuen pro GA-Durchlauf
                  % - Muss ein Vielfaches von 2 sein

% wWichtig für Roulette-Wheel-Selektion:
%
% Die reziproken Werte der Gesamtfitness
% zur Berechnung der zu löschenden Elemente
overallrezip = 1 ./ overallfitness; 
%
% Normierung auf Gesamtsumme 1
overallrezip = overallrezip / sum(overallrezip); 
%
% Normierung auf Gesamtfitness 1
overallfitness = overallfitness / sum(overallfitness); 

% Es werden zwei Vektoren (\texttt{maxfitness} und \texttt{maxrezip}) erzeugt, in denen für
% jeden Regelsatz in wespe ein Wert abgespeichert ist, der der Position des
% jeweiligen Abschnitts auf dem Roulette-Wheel entspricht. Der Vektor ist
% normiert auf 1, d.h. der letzte Wert im Vektor beträgt 1.0.
cumulfitness = 0;
cumulrezip = 0;
for regelsatz=1:length(overallfitness)
 cumulfitness = cumulfitness + overallfitness(regelsatz);
 maxfitness(regelsatz) = cumulfitness;
 cumulrezip = cumulrezip + overallrezip(regelsatz);
 maxrezip(regelsatz) = cumulrezip;
end

% Selektion
eltern = roulettemz(overallfitness, maxfitness);

% Rekombination
newstrings = onepointxover(eltern);

% Mutation
newstrings = mutation(newstrings);

% Selektion der zu löschenden bauagent-Objekte
% - Es wird das gleiche Prinzip zur Roulette-Wheel-Selektion angewendet wie
% bei der Eltern-Selektion, nur dass auf den Kehrwerten der Fitnesswerte
% gearbeitet wird und deshalb die Selektionswahrscheinlichkeit mit
% steigender Fitness abnimmt, d.h. dass weniger fitte \texttt{bauagent}-Objekte mit
% höherer Wahrscheinlichkeit gelöscht werden.
todelete = roulette(overallrezip, maxrezip);

% Erzeugen von zwei zusätzlichen bauagent-Objekten in wespe
% - nicht mehr nötig, da die Populationsgröße konstant gehalten werden soll
% und für die neuen Objekte alte überschrieben werden
% Stattdessen direktes Ersetzen der zu löschenden Objekte und Einfügen der
% neuen Fitnessstrings
for elternindex=1:elternzahl
wespe(todelete(elternindex),1) = ...
 bauagent(Wabengitter(1:2, MittelWabe)', 1);
wespe(todelete(elternindex),1).classifierfitnessstring ...
 = newstrings(1,:);
wespe(todelete(elternindex),1).updatefitness;
end

function index = roulette(fitnessvektor, maxvektor)
% Roulette-Wheel-Selection ohne Zurücklegen - wird zur Auswahl der aus
% der Population zu löschenden Individuen verwendet. Jedes Individuum kann
% nur einmal gelöscht werden.
for candid=1:elternzahl
 a = rand;
 for ruleset=length(fitnessvektor):-1:2
 if ( (a >= maxvektor(ruleset-1)) && ...
  (fitnessvektor(ruleset) > 0.0) )
  index(candid) = ruleset
  break;
  end
 end
 if ( a < maxvektor(1) )
 index(candid) = 1
end

% Fitness des gewählten Individuums auf 0 setzen
fitnessvektor(index(candid)) = 0.0;
% neue Normierung
fitnessvektor = fitnessvektor / sum(fitnessvektor);

cumul = 0;
% neuen Vektor mit Maximalwerten für Roulette-Selection erzeugen
for regel=1:length(fitnessvektor)
 cumul = cumul + fitnessvektor(regel);
 maxvektor(regel) = cumul;
end 
end
end

function index = roulettemz(fitnessvektor, maxvektor)
% Roulette-Wheel-Selection mit Zurücklegen - wird zur Auswahl der
% Eltern-Individuen verwendet. Jedes Individuum soll mehrmals ausgewählt
% werden können.
for candid=1:elternzahl
 a = rand;
 for ruleset=length(fitnessvektor):-1:2
  if ( (a >= maxvektor(ruleset-1)) && ...
   (fitnessvektor(ruleset) > 0.0) )
  index(candid) = ruleset
  break;
  end
 end
 if ( a < maxvektor(1) )
  index(candid) = 1
 end
end
end

function kinder = onepointxover(eltern)
for xoverindex=1:uint8(elternzahl/2)
 string1 = ...
  wespe(eltern(xoverindex),1).classifierfitnessstring;
 string2 = ...
  wespe(eltern(xoverindex+1),1).classifierfitnessstring;
% kopiert die Fitness-Strings der ausgewählten Eltern in Graycode
% in zwei lokale String-Variablen
% Es wird der Gesamtstring (Stärke aller Regeln
% hintereinander) verwendet
xoverpoint = uint16(rand * length(string1));
% wählt einen zufälligen Crossoverpunkt

if (rand <= probcrossover) 
% Nur dann Crossover, wenn Zufallszahl kleiner als
% Crossover-Wahrscheinlichkeit ist...
neustring1 = ...
 [string1(1:xoverpoint) string2(xoverpoint+1:length(string2))];
neustring2 = ...
 [string2(1:xoverpoint) string1(xoverpoint+1:length(string1))];
else % ...sonst werden die Elternstrings einfach kopiert
neustring1 = string1;
neustring2 = string2;
end

kinder(xoverindex,:) = neustring1;
kinder(xoverindex+1,:) = neustring2;
end
end

function newbitstring = mutation(bitstring)
for mutindex=1:uint8(elternzahl/2)
bitstring1 = bitstring(mutindex,:);
bitstring2 = bitstring(mutindex+1,:);

if (rand < probmutation)
 % wenn Zufallszahl unter Mutationswahrscheinlichkeit
mutbit = uint16(ceil(rand * length(bitstring1)));
if strcmp(bitstring1(mutbit),'0')
bitstring1(mutbit) = '1';
end
if strcmp(bitstring1(mutbit),'1')
bitstring1(mutbit) = '0';
end
end % für bitstring1

if (rand <= probmutation) 
 % wenn Zufallszahl unter Mutationswahrscheinlichkeit
mutbit = uint16(ceil(rand * length(bitstring2)));
if strcmp(bitstring2(mutbit),'0')
bitstring2(mutbit) = '1';
end
if strcmp(bitstring2(mutbit),'1')
bitstring2(mutbit) = '0';
end
end % für bitstring2

newbitstring(mutindex,:) = bitstring1;
newbitstring(mutindex+1,:) = bitstring2;
end

end

end
\end{matlab}
