#include "tsp.hpp"
#include <time.h>
#include <assert.h>
#include <stdlib.h>
#define BOOL int
/***************************************************************************/
/* Parameter fuer Genetische Algorithmen */
static int PopulGroesse = 200; // Populationsgroesse
static int ReproRate = 18; // Reproduktionsrate (9%)
static int MutatRate = 2; // Mutationsrate (1%)
static int CORate = 120; // CrossOverRate (60%)
static int SelRate = 60; // Selektionsrate (30%) = Die ... Besten
/***************************************************************************/
/* Ein Chromosom mit zufaelligen Werten von 0.00 - 0.99 initialisieren. */
/* Parameter : Laenge des Chromosoms, das Chromosom (Ref.Par.) */
/* Funktionswert : keiner */
void InitChromosom(int ChrLaenge, CHROMOSOM & Chromo) {
for (int i=1; i<=ChrLaenge; i++) {
REAL ZufZahl;
// Zufallszahl erzeugen zwischen 0.00 und 0.99
ZufZahl=(float)rand()/(float)RAND_MAX;
// Zahl an das Chromosom anhaengen
Chromo.appr(ZufZahl);
}
}
/***************************************************************************/
/* Anfangspopulation fuer die genetischen Algorithmen initialisieren. */
/* Parameter : Laenge der Chromosome, Population (Ref.Par.) */
/* Funktionswert : keiner */
void InitPopulation(int ChrLaenge, POPULATION & Popul) {
for (int i=1; i<=PopulGroesse; i++) {
CHROMOSOM Chromo(empty);
// Ein Chromosom herstellen
InitChromosom(ChrLaenge, Chromo);
// Chromosom an die Population anhaengen
Popul.appr(Chromo);
}
}
/***************************************************************************/
/* Aus dem Chromosom den Weg berechnen = Sortierung der Gene ermitteln. */
/* Parameter : Das Chromosom, Laenge des Chromosom, Loesungsweg (Point.) */
/* Funktionswert : keiner */
void CalcPath(const CHROMOSOM & Chromo, int ChrLaenge, int* Loesung) {
BOOL* Taken; // Feld: Gen ausgewertet(J/N) ?
REAL Kleinster; // Kleinster Wert im Chromosom
unsigned int KleinstePos; // Pos. des kleinsten Wertes im Chromosom
int i; // Laufvariable
// Speicher fuer BOOLVektor alloziieren und Vektor initialisieren
Taken=new BOOL[ChrLaenge];
assert(Taken!=0);
for (i=0; i<ChrLaenge; i++) Taken[i]=FALSE;
for (i=0; i<ChrLaenge; i++) {
// Kleinster mit Wert groesser als alle Gene (max. 1.0) initialisieren
Kleinster=1.5;
// Chromosom durchlaufen und kleinstes Gen suchen
for (int j=1; j<=ChrLaenge; j++) {
if (Chromo.sel(j)<Kleinster && Taken[j-1]==FALSE) {
Kleinster=Chromo.sel(j);
KleinstePos=j;
}
}
// Reiseziel festlegen
Loesung[i]=KleinstePos;
// Bereits gewaehltes Gen blockieren
Taken[KleinstePos-1]=TRUE;
}
delete [] Taken;
}
/***************************************************************************/
/* Entfernungsmatrix mit den Entfernungswerten initialisieren. */
/* Parameter : String mit allen Werten (P), Entfernungsmatrix (RP) */
/* Funktionswert : Dimension der Matrix = Startpunkt der Reise */
int InitTable(char* Uebergabe, ZEILE & Tabelle) {
int i=0;
int Anzahl;
REAL entfernung;
float input;
// Datum Nr.1 lesen = Dimension der Entfernungsmatrix = Startpunkt
while (Uebergabe[i]!=' ') i++;
sscanf(Uebergabe,"%d",&Anzahl);
// Daten Nr.2 bis Nr.(Anzahl^2+1) lesen = Daten der Entfernungsmatrix
for (int j=1; j<=Anzahl; j++) {
SPALTE spalte(empty);
for (int k=1; k<=Anzahl; k++) {
// Zeiger zum naechsten Datum setzen
Uebergabe=Uebergabe+(i+1);
i=0;
// Nur weiterlaufen, wenn nicht letztes Element
if ( ! (j==Anzahl && k==Anzahl))
while (Uebergabe[i]!=' ') i++;
// Datum lesen und in die Matrix eintragen
sscanf(Uebergabe,"%f",&input);
entfernung=input;
spalte.appr(entfernung);
}
Tabelle.appr(spalte);
}
return Anzahl;
}
/***************************************************************************/
/* Laenge des ausgewaehlten Pfades anhand der Entfernungsmatrix berechnen. */
/* Parameter : Laenge des Chromosoms, Loesungsvektor (P), */
/* Entfernungsmatrix, Startpunkt der Reise */
/* Funktionswert : Laenge der Reise */
float CalcLength(int ChrLaenge, int* Loesung, const ZEILE & Tabelle,
int Start) {
float result=0; // Ergebnis der Weglaengenberechnungen
SPALTE spalte(empty); // Hilfsvariable
REAL erg; // Hilfsvariable
int i; // Laufvariable
// Vom Start zum ersten Punkt
spalte=Tabelle.sel(Start);
erg=spalte.sel(Loesung[0]);
result+=erg.cv_real();
// Vom ersten bis zum letzten Punkt
for (i=1; i<ChrLaenge; i++) {
spalte=Tabelle.sel(Loesung[i-1]);
erg=spalte.sel(Loesung[i]);
result+=erg.cv_real();
}
// Vom letzten Punkt zum Start zurueck
spalte=Tabelle.sel(Loesung[i-1]);
erg=spalte.sel(Start);
result+=erg.cv_real();
return result;
}
/***************************************************************************/
/* Das beste Chromosom bzgl. Weglaenge aus der Population suchen. */
/* Parameter : Population, Chromosomenlaenge, Entfernungsmatrix, */
/* Startpunkt, Das beste Chromosom */
/* Funktionswert : Index des besten Chromosom */
CHROMOSOM GetBest(const POPULATION & Popul, int ChrLaenge,
const ZEILE & Tabelle, int Start) {
CHROMOSOM BestChr(empty); // Bestes Chromosom
float BestWay,ZwErg; // Kuerzester Reiseweg + Zwischenergebnis
int* Loesung; // Loesungsvektor
// Speicher fuer Loesungsvektor alloziieren
Loesung=new int[ChrLaenge];
assert(Loesung!=0);
// Erstes Chromosom als Bestes festlegen
BestChr=Popul.sel(1);
CalcPath(BestChr,ChrLaenge,Loesung);
// Weg berechnen
BestWay=CalcLength(ChrLaenge,Loesung,Tabelle,Start);
// Die weiteren Chromosome der Population durchlaufen,
// ueberprufen, ob besser und bestes Chromosom evtl. ersetzen
for (int i=2; i<=Popul.len().cv_nat0(); i++) {
CalcPath(Popul.sel(i),ChrLaenge,Loesung);
ZwErg=CalcLength(ChrLaenge,Loesung,Tabelle,Start);
if (ZwErg<BestWay) {
BestWay=ZwErg;
BestChr=Popul.sel(i);
}
}
delete [] Loesung;
return BestChr;
}
/***************************************************************************/
/* Loesungvektor fuer Tcl/Tk in String konvertieren */
/* Parameter : Loesungsstring (P), Loesungsvektor (P), */
/* Chromosomenlaenge, Weglaenge */
/* Funktionswert : keiner */
void LoesungToString(char* String, int* Loesung, int ChrLaenge, float Laenge){
char* pAnfang; // Merkzeiger
// Weglaenge in den String schreiben
sprintf(String,"%f",Laenge);
strcat(String," ");
pAnfang=String;
// Die anzufahrenden Punkte in richtiger Reihenfolge in den String schreiben
for (int i=0; i<ChrLaenge; i++) {
String+=strlen(String);
sprintf(String,"%d",Loesung[i]);
strcat(String," ");
}
// Zeiger zurueck auf den Stringanfang setzen
String=pAnfang;
}
/***************************************************************************/
/* Zufaellige Auswahl eines Chromosoms fuer die Vererbungsmechanismen. */
/* Prinzip: - Zwei Chromsomen zufaellig auswaehlen */
/* - Chromosom mit besserer Fitness wird zurueckgeliefert */
/* Parameter : Population, Chromosomenlaenge, Entf.Matrix, Startpunkt */
/* Funktionswert : Das Chromosom */
CHROMOSOM SelectChromo(const POPULATION & Popul, int ChrLaenge,
const ZEILE & Tabelle, int Start) {
unsigned int Zuffi_1,Zuffi_2;
POPULATION HilfsPop(empty);
do {
Zuffi_1=(rand()%PopulGroesse)+1;
Zuffi_2=(rand()%PopulGroesse)+1;
}
while (Zuffi_1==Zuffi_2);
HilfsPop.appr(Popul.sel(Zuffi_1));
HilfsPop.appr(Popul.sel(Zuffi_2));
return GetBest(HilfsPop,ChrLaenge,Tabelle,Start);
}
/***************************************************************************/
/* Ein Verebungsschritt durchfuehren ==> Neue Population erzeugen. */
/* Parameter : Population, Chromosomenlaenge, Entfernungsmatrix, Startpt. */
/* Funktionswert : Die neue Population */
POPULATION Vererbung(POPULATION Popul, int ChrLaenge,
const ZEILE & Tabelle, int Start) {
POPULATION PopulNeu(empty); // Neue Population
// Chromosomen fuer Auswahl
CHROMOSOM Chromo(empty), Chromo_1(empty), Chromo_2(empty);
unsigned int iZuffi; // Zufallszahlen
REAL rZuffi; // -"-
int i; // Laufvariable
FITNESS Fit(empty); // Fitnessfeld
REAL FitWert; // Fitnesswert
int *Loesung; // Loesungsvektor
unsigned int Index; // Hilfsindex
// Fitness fuer alle Chromosomen berechnen und speichern
Loesung=new int[ChrLaenge];
assert(Loesung!=0);
for (i=1; i<=PopulGroesse; i++) {
CalcPath(Popul.sel(i),ChrLaenge,Loesung);
FitWert=CalcLength(ChrLaenge,Loesung,Tabelle,Start);
Fit.appr(FitWert);
}
delete [] Loesung;
// Reproduktion
for (i=1; i<=ReproRate; i++) {
// Chromosom einfach anhaengen
PopulNeu.appr(SelectChromo(Popul,ChrLaenge,Tabelle,Start));
}
// Mutation
for (i=1; i<=MutatRate; i++) {
// Chromosom auswaehlen
Chromo=SelectChromo(Popul,ChrLaenge,Tabelle,Start);
// Gen fuer die Mutation per Zufall bestimmen
iZuffi=(rand()%ChrLaenge)+1;
// Neuen Wert fuer Gen per Zufall bestimmen
rZuffi=(float)rand()/(float)RAND_MAX;
Chromo.ovwrt1(iZuffi,rZuffi);
PopulNeu.appr(Chromo);
}
// Crossover
for (i=1; i<=CORate; i++) {
// Chromosom 1 bestimmen
Chromo_1=SelectChromo(Popul,ChrLaenge,Tabelle,Start);
// Chromosom 2 bestimmen
Chromo_2=SelectChromo(Popul,ChrLaenge,Tabelle,Start);
// (Keine Ueberpruefung, ob zweimal das gleiche Chromosom gewaehlt wird,
// da unwahrscheinlich und erheblicher Overhead.)
// Start-Gen fuer Crossover per Zufall bestimmen
// Bed.: 3 <= Gen <= ChrLaenge-1, da sonst Reproduktion bzw. Mutation
iZuffi=(rand()%ChrLaenge)+1;
Chromo=Chromo_1.sub_tup(1,iZuffi)
+Chromo_2.sub_tup(iZuffi+1,ChrLaenge);
PopulNeu.appr(Chromo);
}
// Selektion
for (i=1; i<=SelRate; i++) {
Index=1;
FitWert=Fit.sel(1);
for (int j=2; j<=Fit.len().cv_nat0(); j++) {
if (Fit.sel(j)<FitWert) {
Index=j;
FitWert=Fit.sel(j);
}
}
PopulNeu.appr(Popul.sel(Index));
Popul.rmv1(Index);
Fit.rmv1(Index);
}
return PopulNeu;
}