summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorErich Eckner <git@eckner.net>2015-07-10 14:56:48 +0200
committerErich Eckner <git@eckner.net>2015-07-10 14:56:48 +0200
commitada93c9da7373367ce29daa3d57cb35ea90f54e5 (patch)
tree50eeefb2f0c9c3f51cb8f4d1a8a3f23a51d90bb4
downloadStabile-master.tar.xz
initialer CommitHEADmaster
-rw-r--r--.gitignore17
-rw-r--r--energiefunktion.inc221
-rw-r--r--grampsmath.pas79
-rw-r--r--grampstypen.pas2050
-rw-r--r--grampsunit.pas4674
-rwxr-xr-xmake3
-rw-r--r--stabile.lpi93
-rw-r--r--stabile.lpr95
-rw-r--r--stabile.lps194
9 files changed, 7426 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..00ca7bf
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,17 @@
+*.bmp
+*.png
+*.bak
+*.ppu
+*.o
+*.zip
+*.tar.gz
+*.out
+*.gramps
+*.exe
+*.backup
+*.gz
+*.xml
+lib
+*~
+Log*
+stabile
diff --git a/energiefunktion.inc b/energiefunktion.inc
new file mode 100644
index 0000000..946bd96
--- /dev/null
+++ b/energiefunktion.inc
@@ -0,0 +1,221 @@
+{$IFDEF Energie}
+{$IFDEF Gradient}
+ Ich kann nur Energie _oder_ Gradient berechnen!
+ Bitte Compilerschalter richtig setzen!
+{$ENDIF}
+{$ENDIF}
+
+{$IFNDEF Energie}
+{$IFNDEF Gradient}
+ Ich muss mindestens Energie oder Gradient berechnen!
+ Bitte Compilerschalter richtig setzen!
+{$ENDIF}
+{$ENDIF}
+
+// berechnet die Energie oder den Gradienten
+var
+ i,j,k: Longint;
+ tmp,tmp2: extended;
+{$IFDEF Gradient}
+ px,py,tmp3: extended;
+{$ENDIF}
+
+begin
+
+ // Initialisierung
+ {$IFDEF Energie}
+ Kreuzungen:=0;
+ Kreuzung:=-1;
+ result:=0;
+ {$ENDIF}
+ {$IFDEF Gradient}
+ if length(grad)<>length(p) then begin
+ writeln('*** Warnung ***');
+ writeln('Länge das Gradienten wurde angepasst!');
+ setlength(grad,length(p));
+ end;
+ for i:=0 to length(grad)-1 do
+ grad[i]:=0;
+ {$ENDIF}
+
+ {$IFDEF detaillierteZeitanalyse}
+ if mainThread then ffTimer.start;
+ {$ENDIF}
+
+ for I:=0 to length(FFInteraktionen)-1 do
+ with FFInteraktionen[I] do
+ // auf Kreuzung prüfen:
+ // ((B1-A1)x(A2-A1))*((B2-A1)x(A2-A1))<=0 und
+ // ((A1-B1)x(B2-B1))*((A2-B1)x(B2-B1))<=0 <=> Kreuzung
+ if (KreuzproduktZ(P,_Fs[1].Eltern[0],_Fs[0].Eltern[0],_Fs[0].Eltern[1],_Fs[0].Eltern[0]) *
+ KreuzproduktZ(P,_Fs[1].Eltern[1],_Fs[0].Eltern[0],_Fs[0].Eltern[1],_Fs[0].Eltern[0]) <= 0 ) and
+ (KreuzproduktZ(P,_Fs[0].Eltern[0],_Fs[1].Eltern[0],_Fs[1].Eltern[1],_Fs[1].Eltern[0]) *
+ KreuzproduktZ(P,_Fs[0].Eltern[1],_Fs[1].Eltern[0],_Fs[1].Eltern[1],_Fs[1].Eltern[0]) <= 0 )
+ then begin
+ {$IFDEF Energie}
+ inc(Kreuzungen);
+ if (Kreuzung=-1) or
+ (random*Kreuzungen<1) then Kreuzung:=i; // eine Kreuzung zufällig, gleichverteilt auswählen
+ {$ENDIF}
+
+ // jetzt soll belohnt (!) werden, wenn ein Elternteil der einen Familie nah an der "Kante" der anderen Familie liegt
+ // -> dadurch kann eine Energie-Optimierung auch Kreuzungen entfernen
+ for j:=0 to 1 do // Familie
+ for k:=0 to 1 do begin // Elter
+ tmp:=(1e-9 + (QAbstand(P,_FS[j].Eltern[k],_FS[1-j].Eltern[0])
+ - ( sqr(Skalarprodukt(P,_FS[j].Eltern[k],_FS[1-j].Eltern[0],_FS[1-j].Eltern[1],_FS[1-j].Eltern[0]))
+ / (1e-9+QAbstand(P,_FS[1-j].Eltern[1],_FS[1-j].Eltern[0])))));
+ {$IFDEF Energie}
+ result:=result - Entkreuzungsbelohnungsskalierung * 1/tmp;
+ {$ENDIF}
+ {$IFDEF Gradient}
+ px:= P[_FS[1-j].Eltern[1].p2]-P[_FS[1-j].Eltern[0].p2];
+ py:=-P[_FS[1-j].Eltern[1].p1]+P[_FS[1-j].Eltern[0].p1];
+ tmp2:=1/sqrt(sqr(px)+sqr(py)+epsilon);
+ if (px*(P[_FS[j].Eltern[k].p1]-P[_FS[1-j].Eltern[0].p1])+py*(P[_FS[j].Eltern[k].p2]-P[_FS[1-j].Eltern[0].p2]) <= 0) then
+ tmp2:=-tmp2;
+ px:=px*tmp2;
+ py:=py*tmp2;
+ tmp2:=Entkreuzungsbelohnungsskalierung*2/sqr(tmp)*sqrt(tmp);
+
+ tmp:=Skalarprodukt(P,_FS[j].Eltern[k],_FS[1-j].Eltern[0],_FS[1-j].Eltern[1],_FS[1-j].Eltern[0]) / // (P-F1)*(F2-F1) / (F2-F1)^2
+ (1e-9+QAbstand(P,_FS[1-j].Eltern[1],_FS[1-j].Eltern[0]));
+
+ grad[_FS[j].Eltern[k].p1]:= // Ableitungen nach Position der Person
+ grad[_FS[j].Eltern[k].p1] + tmp2*px;
+ grad[_FS[j].Eltern[k].p2]:=
+ grad[_FS[j].Eltern[k].p2] + tmp2*py;
+
+ grad[_FS[1-j].Eltern[0].p1]:= // Ableitungen nach Position der Eltern
+ grad[_FS[1-j].Eltern[0].p1] - tmp2*(1-tmp)*px;
+ grad[_FS[1-j].Eltern[0].p2]:=
+ grad[_FS[1-j].Eltern[0].p2] - tmp2*(1-tmp)*py;
+
+ grad[_FS[1-j].Eltern[1].p1]:=
+ grad[_FS[1-j].Eltern[1].p1] - tmp2*tmp*px;
+ grad[_FS[1-j].Eltern[1].p2]:=
+ grad[_FS[1-j].Eltern[1].p2] - tmp2*tmp*py;
+ {$ENDIF}
+ end;
+ end;
+ {$IFDEF detaillierteZeitanalyse}
+ if mainThread then begin
+ ffTimer.stop;
+ mmTimer.start;
+ end;
+ {$ENDIF}
+
+ for I:=0 to length(MMInteraktionen)-1 do
+ with MMInteraktionen[I] do begin // 1/x^2 - Abstoßung
+ {$IFDEF Energie}
+ result:=result +
+ Laenge/(1e-9 + QAbstand(P,_Ps[0],_Ps[1]));
+ {$ENDIF}
+ {$IFDEF Gradient}
+ tmp:=1/(1e-9 + QAbstand(P,_Ps[0],_Ps[1]));
+ tmp:=-Laenge*2*sqr(tmp);
+ grad[_Ps[0].p1]:=
+ grad[_Ps[0].p1] + tmp * (P[_Ps[0].p1]-P[_Ps[1].p1]);
+ grad[_Ps[0].p2]:=
+ grad[_Ps[0].p2] + tmp * (P[_Ps[0].p2]-P[_Ps[1].p2]);
+ grad[_Ps[1].p1]:=
+ grad[_Ps[1].p1] + tmp * (P[_Ps[1].p1]-P[_Ps[0].p1]);
+ grad[_Ps[1].p2]:=
+ grad[_Ps[1].p2] + tmp * (P[_Ps[1].p2]-P[_Ps[0].p2]);
+ {$ENDIF}
+ end;
+
+ {$IFDEF detaillierteZeitanalyse}
+ if mainThread then begin
+ mmTimer.stop;
+ mfTimer.start;
+ end;
+ {$ENDIF}
+
+ for I:=0 to length(MFInteraktionen)-1 do
+ with MFInteraktionen[I] do begin
+ tmp:= Skalarprodukt(P,_P,_F.Eltern[0],_F.Eltern[1],_F.Eltern[0]) / // (P-F1)*(F2-F1) / (F2-F1)^2
+ (epsilon+QAbstand(P,_F.Eltern[1],_F.Eltern[0]));
+ if (tmp<=0) or (tmp>=1) then begin // Person liegt "vor"/"hinter" Familie -> Abstand zu Elter relevant
+ tmp2:=epsilon + QAbstand(P,_P,_F.Eltern[byte(tmp>0.5)]);
+ {$IFDEF Gradient}
+ tmp3:=-2*Laenge/sqr(tmp2);
+ grad[_P.p1]:=
+ grad[_P.p1] + tmp3*(P[_P.p1]-P[_F.Eltern[byte(tmp>0.5)].p1]);
+ grad[_P.p2]:=
+ grad[_P.p2] + tmp3*(P[_P.p2]-P[_F.Eltern[byte(tmp>0.5)].p2]);
+ grad[_F.Eltern[byte(tmp>0.5)].p1]:=
+ grad[_F.Eltern[byte(tmp>0.5)].p1] + tmp3*(P[_F.Eltern[byte(tmp>0.5)].p1]-P[_P.p1]);
+ grad[_F.Eltern[byte(tmp>0.5)].p2]:=
+ grad[_F.Eltern[byte(tmp>0.5)].p2] + tmp3*(P[_F.Eltern[byte(tmp>0.5)].p2]-P[_P.p2]);
+ {$ENDIF}
+ end
+ else begin // Person liegt "neben" Familie -> senkrechter Abstand relevant
+ tmp2:=1e-9 + QAbstand(P,_P,_F.Eltern[0]) - // Pythagoras
+ sqr(tmp)*QAbstand(P,_F.Eltern[1],_F.Eltern[0]);
+ {$IFDEF Gradient}
+ px:=-P[_F.Eltern[1].p2]+P[_F.Eltern[0].p2];
+ py:= P[_F.Eltern[1].p1]-P[_F.Eltern[0].p1];
+ tmp3:=1/sqrt(sqr(px)+sqr(py)+epsilon);
+ if (px*(P[_P.p1]-P[_F.Eltern[0].p1])+py*(P[_P.p2]-P[_F.Eltern[0].p2]) <= 0) then
+ tmp3:=-tmp3;
+ px:=px*tmp3;
+ py:=py*tmp3;
+
+ tmp2:=-2*Laenge/sqr(tmp2)*sqrt(tmp2);
+
+ grad[_P.p1]:= // Ableitungen nach Position der Person
+ grad[_P.p1] + tmp2*px;
+ grad[_P.p2]:=
+ grad[_P.p2] + tmp2*py;
+
+ grad[_F.Eltern[0].p1]:= // Ableitungen nach Position der Eltern
+ grad[_F.Eltern[0].p1] - tmp2*(1-tmp)*px;
+ grad[_F.Eltern[0].p2]:=
+ grad[_F.Eltern[0].p2] - tmp2*(1-tmp)*py;
+
+ grad[_F.Eltern[1].p1]:=
+ grad[_F.Eltern[1].p1] - tmp2*tmp*px;
+ grad[_F.Eltern[1].p2]:=
+ grad[_F.Eltern[1].p2] - tmp2*tmp*py;
+ {$ENDIF}
+ end;
+
+ {$IFDEF Energie}
+ result:=result + Laenge/tmp2;
+ {$ENDIF}
+ end;
+
+ {$IFDEF detaillierteZeitanalyse}
+ if mainThread then begin
+ mfTimer.stop;
+ famTimer.start;
+ end;
+ {$ENDIF}
+
+ {$IFDEF Energie}
+ for i:=0 to length(Familien)-1 do
+ result:=result +
+ Laengengewicht *
+ sqr(sqr(QAbstand(P,Familien[i].Eltern[0],Familien[i].Eltern[1])));
+ {$ENDIF}
+ {$IFDEF Gradient}
+ for i:=0 to length(Familien)-1 do begin
+ tmp:=QAbstand(P,Familien[i].Eltern[0],Familien[i].Eltern[1]);
+ tmp:=8*Laengengewicht*sqr(tmp)*tmp; // 8 (a-b)^6
+ grad[Familien[i].Eltern[0].p1]:=
+ grad[Familien[i].Eltern[0].p1] + tmp*(P[Familien[i].Eltern[0].p1]-P[Familien[i].Eltern[1].p1]);
+ grad[Familien[i].Eltern[0].p2]:=
+ grad[Familien[i].Eltern[0].p2] + tmp*(P[Familien[i].Eltern[0].p2]-P[Familien[i].Eltern[1].p2]);
+ grad[Familien[i].Eltern[1].p1]:=
+ grad[Familien[i].Eltern[1].p1] + tmp*(P[Familien[i].Eltern[1].p1]-P[Familien[i].Eltern[0].p1]);
+ grad[Familien[i].Eltern[1].p2]:=
+ grad[Familien[i].Eltern[1].p2] + tmp*(P[Familien[i].Eltern[1].p2]-P[Familien[i].Eltern[0].p2]);
+ end;
+ {$ENDIF}
+
+ {$IFDEF detaillierteZeitanalyse}
+ if mainThread then famTimer.stop;
+ {$ENDIF}
+
+end;
diff --git a/grampsmath.pas b/grampsmath.pas
new file mode 100644
index 0000000..6739273
--- /dev/null
+++ b/grampsmath.pas
@@ -0,0 +1,79 @@
+unit grampsmath;
+
+{$mode objfpc}{$H+}
+
+interface
+
+uses
+ Classes, SysUtils, grampstypen, math;
+
+function KreuzproduktZ(P: tExtendedArray; A1,A2,B1,B2: tPerson): extended; inline;
+function QAbstand(P: tExtendedArray; A1,A2: tPerson): extended; inline;
+function Skalarprodukt(P: tExtendedArray; A1,A2,B1,B2: tPerson): extended; inline;
+function rootDet(mat: array of tExtendedarray): extended;
+
+implementation
+
+function KreuzproduktZ(P: tExtendedArray; A1,A2,B1,B2: tPerson): extended;
+begin
+ result:= // ( (A1-A2) x (B1-B2) ).z =
+ (P[A1.p1]-P[A2.p1])*(P[B1.p2]-P[B2.p2]) // (A1.x - A2.x) * (B1.y - B2.y)
+ - (P[B1.p1]-P[B2.p1])*(P[A1.p2]-P[A2.p2]); // - (B1.x - B2.x) * (A1.y - A2.y)
+(* writeln((P[A1.p1]-P[A2.p1])*(P[B1.p2]-P[B2.p2]) - (P[B1.p1]-P[B2.p1])*(P[A1.p2]-P[A2.p2]));
+ writeln('(',P[A1.p1],' - ',P[A2.p1],') * (',P[B1.p2],' - ',P[B2.p2],') - (',P[B1.p1],' - ',P[B2.p1],') * (',P[A1.p2],' - ',P[A2.p2],')');
+ writeln('(',A1.p1,' - ',A2.p1,') * (',B1.p2,' - ',B2.p2,') - (',B1.p1,' - ',B2.p1,') * (',A1.p2,' - ',A2.p2,')'); *)
+end;
+
+function QAbstand(P: tExtendedArray; A1,A2: tPerson): extended;
+begin
+ result:=
+ sqr(P[A1.p1]-P[A2.p1]) +
+ sqr(P[A1.p2]-P[A2.p2]);
+end;
+
+function Skalarprodukt(P: tExtendedArray; A1,A2,B1,B2: tPerson): extended;
+begin
+ result:=
+ (P[A1.p1]-P[A2.p1])*(P[B1.p1]-P[B2.p1]) +
+ (P[A1.p2]-P[A2.p2])*(P[B1.p2]-P[B2.p2]);
+end;
+
+function rootDet(mat: array of tExtendedarray): extended;
+var
+ dim,i,j,k: longint;
+ fak,tmp: extended;
+begin
+ dim:=length(mat);
+ result:=1;
+
+ for i:=0 to dim-1 do begin // die zu eliminierende Spalte
+ k:=-1;
+ tmp:=0;
+ for j:=i to dim-1 do
+ if abs(mat[j,i])>tmp then begin
+ k:=j;
+ tmp:=abs(mat[j,i]);
+ end;
+
+ if tmp<1e-40 then begin // nur noch 0en in Spalte i
+ result:=0;
+ break;
+ end;
+
+ if k<>i then // Zeile k und i tauschen
+ for j:=i to dim-1 do begin
+ tmp:=mat[i,j];
+ mat[i,j]:=mat[k,j];
+ mat[k,j]:=tmp;
+ end;
+ result:=result*power(abs(mat[i,i]),1/dim);
+ for j:=i+1 to dim-1 do begin
+ fak:=-mat[j,i]/mat[i,i];
+ for k:=i to dim-1 do
+ mat[j,k]:=mat[j,k]+fak*mat[i,k];
+ end;
+ end;
+end;
+
+end.
+
diff --git a/grampstypen.pas b/grampstypen.pas
new file mode 100644
index 0000000..4505324
--- /dev/null
+++ b/grampstypen.pas
@@ -0,0 +1,2050 @@
+unit grampstypen;
+
+interface
+
+uses classes, matheunit;
+
+type
+ tExtendedArray = array of extended;
+ tIntArray = array of longint;
+ tIntArrayArray = array of tIntArray;
+ tBooleanArray = array of boolean;
+ tPointArray = array of tPoint;
+ tPointArrayArray = array of tPointArray;
+ tEreignisart = (eaDummy,eaGeburt,eaTod,eaHochzeit,eaTaufe,eaBeerdigung,eaSonstiges);
+ t4DPoint = record
+ x,y,z,u: longint;
+ end;
+ tExtPoint = record
+ x,y: extended;
+ end;
+ tSchrittErgebnis = record
+ besserAlsVorher,
+ faktorNeutralisiert: boolean;
+ Platzveraenderung: longint;
+ end;
+ t4DPointArray = array of t4DPoint;
+ tParameterAttribut = object
+ istKoordinate,istUnabhaengig,wirdBenutzt: boolean;
+ procedure setzeKoordinate(ik: boolean);
+ procedure setzeUnabhaengig(iu: boolean);
+ procedure setzeBenutzt(wb: boolean);
+ procedure fromChar(c: char);
+ function toChar: char;
+ end;
+ tParameterAttributArray = array of tParameterAttribut;
+ tGenerikum = class
+ ID: string;
+ index: longint;
+ constructor create;
+ destructor destroy; override;
+ procedure init(g: tGenerikum); dynamic;
+ function istGleich(g: tGenerikum): boolean; dynamic;
+ end;
+ tGenerikumArray = array of tGenerikum;
+ tEreignis = class;
+ tEreignisArray = array of tEreignis;
+ tPerson = class;
+ tPersonArray = array of tPerson;
+ tFamilie = class;
+ tFamilieArray = array of tFamilie;
+ tVerknuepfung = class;
+ tVerknuepfungArray = array of tVerknuepfung;
+ tMMInteraktion = class;
+ tMMInteraktionArray = array of tMMInteraktion;
+ tMFInteraktion = class;
+ tMFInteraktionArray = array of tMFInteraktion;
+ tFFInteraktion = class;
+ tFFInteraktionArray = array of tFFInteraktion;
+
+ tEreignis = class (tGenerikum)
+ Jahr: longint;
+ Art: tEreignisart;
+ function istDummy: boolean;
+ constructor create;
+ destructor destroy; override;
+ procedure init(e: tGenerikum); override;
+ function istGleich(e: tGenerikum): boolean; override;
+ end;
+ tPerson = class (tGenerikum)
+ Anfang,Ende: tEreignis;
+ Ereignisse: array[tEreignisart] of tEreignis;
+ KindIn: tFamilie;
+ ElterIn: tFamilieArray;
+ inputIn,outputIn: tVerknuepfungArray;
+ inMMInteraktion: tMMInteraktionArray;
+ inMFInteraktion: tMFInteraktionArray;
+ Vorname,Nachname: string;
+ p1,p2,p3: longint;
+ constructor create;
+ destructor destroy; override;
+ procedure entferneElterIn(wo: tFamilie);
+ procedure entferneKindIn(wo: tFamilie);
+ procedure fuegeInputInHinzu(wo: tVerknuepfung);
+ procedure entferneInputIn(wo: tVerknuepfung);
+ procedure fuegeOutputInHinzu(wo: tVerknuepfung);
+ procedure entferneOutputIn(wo: tVerknuepfung);
+ procedure fuegeInMMInteraktionHinzu(wo: tMMInteraktion);
+ procedure entferneInMMInteraktion(wo: tMMInteraktion);
+ procedure fuegeInMFInteraktionHinzu(wo: tMFInteraktion);
+ procedure entferneInMFInteraktion(wo: tMFInteraktion);
+ procedure init(p: tGenerikum); override; overload;
+ procedure init(p: tGenerikum; var es: tEreignisArray); overload;
+ procedure init(p: tGenerikum; var es: tEreignisArray; var fs: tFamilieArray); overload;
+ procedure init(p: tGenerikum; var es: tEreignisArray; var fs: tFamilieArray; darfErzeugen: boolean); overload;
+ function anzahlVerbindungen: longint;
+ function istGleich(p: tGenerikum): boolean; override;
+ function elterVonFamilie(eNum: longint): tFamilie;
+ function istElterIn(f: tFamilie): boolean;
+ end;
+ tFamilie = class (tGenerikum)
+ Anfang: tEreignis;
+ verheiratet: boolean;
+ Eltern: array[0..1] of tPerson;
+ Kinder: tPersonArray;
+ inMFInteraktion: tMFInteraktionArray;
+ inFFInteraktion: tFFInteraktionArray;
+ constructor create;
+ destructor destroy; override;
+ procedure entferneElter(wen: tPerson);
+ procedure entferneKind(wen: tPerson);
+ procedure fuegeInMFInteraktionHinzu(wo: tMFInteraktion);
+ procedure entferneInMFInteraktion(wo: tMFInteraktion);
+ procedure fuegeInFFInteraktionHinzu(wo: tFFInteraktion);
+ procedure entferneInFFInteraktion(wo: tFFInteraktion);
+ procedure init(f: tGenerikum); override; overload;
+ procedure init(f: tGenerikum; var Es: tEreignisArray; var Ps: tPersonArray); overload;
+ procedure init(f: tGenerikum; var Es: tEreignisArray; var Ps: tPersonArray; darfErzeugen: boolean); overload;
+ function anzahlVerbindungen: longint; inline;
+ function istGleich(f: tGenerikum): boolean; override;
+ function hatKind(p: tPerson): boolean; inline;
+ function hatElter(p: tPerson): boolean; inline;
+ end;
+ tVerknuepfung = class
+ private
+ _outP: tPerson;
+ procedure wOutP(p: tPerson);
+ public
+ index: longint;
+ Input: array[0..1,'x'..'y'] of Longint;
+ Lambda: Longint;
+ Output: array['x'..'y'] of Longint;
+ property outP: tPerson
+ read _outP
+ write wOutP;
+ destructor destroy; override;
+ function istGleich(v: tVerknuepfung; p2p: tIntArray): boolean;
+ end;
+ tMMInteraktion = class
+ private
+ __Ps: array[0..1] of tPerson;
+ function r_Ps(i: longint): tPerson; inline;
+ procedure w_Ps(i: longint; p: tPerson);
+ public
+ index: longint;
+ Laenge: extended;
+ property _Ps[i: integer]: tPerson
+ read r_Ps
+ write w_Ps;
+ destructor destroy; override;
+ function istGleich(ia: tMMInteraktion): boolean;
+ end;
+ tMFInteraktion = class
+ private
+ __P: tPerson;
+ __F: tFamilie;
+ procedure w_P(p: tPerson);
+ procedure w_F(f: tFamilie);
+ public
+ index: longint;
+ Laenge: extended;
+ property _P: tPerson
+ read __P
+ write w_P;
+ property _F: tFamilie
+ read __F
+ write w_F;
+ destructor destroy; override;
+ function istGleich(ia: tMFInteraktion): boolean;
+ end;
+ tFFInteraktion = class
+ private
+ __Fs: array[0..1] of tFamilie;
+ function r_Fs(i: longint): tFamilie; inline;
+ procedure w_Fs(i: longint; f: tFamilie);
+ public
+ index: longint;
+ property _Fs[i: integer]: tFamilie
+ read r_Fs
+ write w_Fs;
+ destructor destroy; override;
+ function istGleich(ia: tFFInteraktion): boolean;
+ end;
+
+ tZusammenhangskomponente = class
+ public
+ Familien: tFamilieArray;
+ constructor create;
+ destructor destroy; override;
+ function grenztAn(p: tPerson): boolean;
+ procedure verschmelzeMit(zhk: tZusammenhangskomponente);
+ procedure UmfeldEinfuegen(Fs: tFamilieArray; p: tPerson);
+ end;
+
+ tGraph = class
+ private
+ function entferneBlaetter(var f: tIntArray): tIntArray;
+ function Pfadigkeit(Ks: tIntArray; a,b: longint): longint; // 0 -> zu wenig; 1 -> ein Pfad; 2-> zu viel
+ function etwasDoppelt: boolean; overload;
+ function etwasDoppelt(Ks: tIntArray): boolean; overload;
+ function etwasRedundant(Ks1,Ks2: tIntArray): boolean;
+ procedure dumpKantenArray(Ks: tIntArray);
+ public
+ Ecken,Kanten: tPointArray;
+ constructor create;
+ destructor destroy; override;
+ function findeKreise: tIntArrayArray;
+ function findeKreise(f: tIntArray): tIntArrayArray;
+ end;
+
+ tSortObject = class
+ oG: tGenerikum;
+ oMM: tMMInteraktion;
+ oMF: tMFInteraktion;
+ oFF: tFFInteraktion;
+ oV: tVerknuepfung;
+ ID: string;
+ constructor create;
+ procedure assign(g: tGenerikum); overload;
+ procedure assign(i: tMMInteraktion); overload;
+ procedure assign(i: tMFInteraktion); overload;
+ procedure assign(i: tFFInteraktion); overload;
+ procedure assign(v: tVerknuepfung); overload;
+ end;
+ tSortObjectArray = array of tSortObject;
+
+function paramsGleich(p1,p2: longint; p2p: tIntArray): boolean; inline;
+function pEreignisToStr(E: tEreignis): string; inline;
+function pFamilieToStr(F: tFamilie): string; inline;
+function pPersonToStr(P: tPerson): string; inline;
+function tEreignisToStr(E: tEreignis): string; inline;
+function tPersonToStr(P: tPerson): string; inline;
+function tFamilieToStr(F: tFamilie): string; inline;
+function tVerknuepfungToStr(V: tVerknuepfung): string; inline;
+function tMMInteraktionToStr(I: tMMInteraktion): string; inline;
+function tMFInteraktionToStr(I: tMFInteraktion): string; inline;
+function tFFInteraktionToStr(I: tFFInteraktion): string; inline;
+function findeEreignis(var Es: tEreignisArray; eID: string): tEreignis;
+function findeFamilie(var Fs: tFamilieArray; fID: string): tFamilie; overload;
+function findeFamilie(var Fs: tFamilieArray; fID: string; darfErzeugen: boolean): tFamilie; overload;
+function findePerson(var Ps: tPersonArray; pID: string): tPerson; overload;
+function findePerson(var Ps: tPersonArray; pID: string; darfErzeugen: boolean): tPerson; overload;
+function findeMMInteraktion(var MMs: tMMInteraktionArray; var Ps: tPersonArray; ia: string): tMMInteraktion;
+function findeMFInteraktion(var MFs: tMFInteraktionArray; var Ps: tPersonArray; var Fs: tFamilieArray; ia: string): tMFInteraktion;
+function findeFFInteraktion(var FFs: tFFInteraktionArray; var Fs: tFamilieArray; ia: string): tFFInteraktion;
+procedure loescheEreignis(var Es: tEreignisArray; eID: string);
+procedure loescheFamilie(var Fs: tFamilieArray; fID: string);
+procedure loeschePerson(var Ps: tPersonArray; pID: string);
+procedure mergePerson(var Ps: tPersonArray; var P: tPerson);
+procedure mergeFamilie(var Fs: tFamilieArray; var F: tFamilie);
+function importEreignis(s: string; var Es: tEreignisArray): tEreignis;
+function importPerson(s: string; var Ps: tPersonArray; var Es: tEreignisArray; var Fs: tFamilieArray): tPerson;
+function importFamilie(s: string; var Ps: tPersonArray; var Es: tEreignisArray; var Fs: tFamilieArray): tFamilie;
+function strToTVerknuepfung(var Ps: tPersonArray; s: string): tVerknuepfung;
+function importMMInteraktion(var Ps: tPersonArray; s: string): tMMInteraktion;
+function importMFInteraktion(var Ps: tPersonArray; var Fs: tFamilieArray; s: string): tMFInteraktion;
+function importFFInteraktion(var Fs: tFamilieArray; s: string): tFFInteraktion;
+function importFamilieArray(var s: string; var Fs: tFamilieArray): tFamilieArray;
+function importPersonArray(var s: string; var Ps: tPersonArray): tPersonArray;
+procedure strToTIntArray(var s: string; var A: tIntArray);
+function Permutation(n: longint): tIntArray;
+function sortStringFromObject(g: tGenerikum): string; overload;
+function sortStringFromObject(i: tMMInteraktion): string; overload;
+function sortStringFromObject(i: tMFInteraktion): string; overload;
+function sortStringFromObject(i: tFFInteraktion): string; overload;
+function sortStringFromObject(v: tVerknuepfung): string; overload;
+function sortiere(arr: tGenerikumArray): tGenerikumArray; overload; inline;
+function sortiere(arr: tMMInteraktionArray): tMMInteraktionArray; overload; inline;
+function sortiere(arr: tMFInteraktionArray): tMFInteraktionArray; overload; inline;
+function sortiere(arr: tFFInteraktionArray): tFFInteraktionArray; overload; inline;
+function sortiere(arr: tVerknuepfungArray): tVerknuepfungArray; overload; inline;
+function sortiere(arr: tSortObjectArray): tSortObjectArray; overload; inline;
+procedure sortiere(var arr: tSortObjectArray; von,bis: longint; mi,ma: string); overload;
+
+implementation
+
+uses sysutils;
+
+function paramsGleich(p1,p2: longint; p2p: tIntArray): boolean;
+begin
+ if p2=-1 then result:=p1=-1
+ else result:=p2p[p2]=p1;
+end;
+
+function pEreignisToStr(E: tEreignis): string;
+begin
+ if assigned(E) then
+ result:=E.ID
+ else
+ result:='NIL';
+end;
+
+function pFamilieToStr(F: tFamilie): string;
+begin
+ if assigned(F) then
+ result:=F.ID
+ else
+ result:='NIL';
+end;
+
+function pPersonToStr(P: tPerson): string;
+begin
+ if assigned(P) then
+ result:=P.ID
+ else
+ result:='NIL';
+end;
+
+function TEreignisToStr(E: TEreignis): String;
+begin
+ TEreignisToStr:=
+ E.ID+' '+
+ inttostr(E.Jahr)+' '+
+ inttostr(Integer(E.Art));
+end;
+
+function TPersonToStr(P: TPerson): String;
+var
+ ea: TEreignisart;
+ I: Longint;
+begin
+ result:=
+ P.ID+' '+
+ pEreignisToStr(P.Anfang)+' '+
+ pEreignisToStr(P.Ende)+' ';
+ for ea:=low(TEreignisart) to high(TEreignisart) do
+ result:=result+PEreignisToStr(P.Ereignisse[ea])+' ';
+ result:=result+
+ pFamilieToStr(P.KindIn)+' '+
+ inttostr(length(P.ElterIn))+' ';
+ for I:=0 to length(P.ElterIn)-1 do
+ result:=result+
+ pFamilieToStr(P.ElterIn[I])+' ';
+ result:=result+
+ ''''+P.Vorname+''' '+
+ ''''+P.Nachname+''' '+
+ inttostr(P.P1)+' '+
+ inttostr(P.P2)+' '+
+ inttostr(P.P3);
+end;
+
+function TFamilieToStr(F: TFamilie): String;
+var
+ I: Longint;
+begin
+ result:=
+ F.ID+' '+
+ PEreignisToStr(F.Anfang)+' '+
+ inttostr(byte(F.Verheiratet))+' '+
+ pPersonToStr(F.Eltern[0])+' '+
+ pPersonToStr(F.Eltern[1])+' '+
+ inttostr(length(F.Kinder));
+ for I:=0 to length(F.Kinder)-1 do
+ result:=result+' '+
+ pPersonToStr(F.Kinder[I]);
+end;
+
+function TVerknuepfungToStr(V: TVerknuepfung): String;
+begin
+ result:=
+ pPersonToStr(V.outP)+' '+
+ inttostr(V.Input[0,'x'])+' '+
+ inttostr(V.Input[0,'y'])+' '+
+ inttostr(V.Input[1,'x'])+' '+
+ inttostr(V.Input[1,'y'])+' '+
+ inttostr(V.Lambda)+' '+
+ inttostr(V.Output['x'])+' '+
+ inttostr(V.Output['y']);
+end;
+
+function TMMInteraktionToStr(I: TMMInteraktion): String;
+begin
+ result:=
+ pPersonToStr(I._Ps[0])+' '+
+ pPersonToStr(I._Ps[1])+' '+
+ myfloattostr(I.Laenge);
+end;
+
+function TMFInteraktionToStr(I: TMFInteraktion): String;
+begin
+ TMFInteraktionToStr:=
+ pPersonToStr(I._P)+' '+
+ pFamilieToStr(I._F)+' '+
+ myfloattostr(I.Laenge);
+end;
+
+function TFFInteraktionToStr(I: TFFInteraktion): String;
+begin
+ TFFInteraktionToStr:=
+ pFamilieToStr(I._Fs[0])+' '+
+ pFamilieToStr(I._Fs[1]);
+end;
+
+function findeEreignis(var Es: tEreignisArray; eID: String): tEreignis;
+var i: longint;
+begin
+ if eID='NIL' then begin
+ result:=nil;
+ exit;
+ end;
+ for i:=0 to length(Es)-1 do
+ if Es[i].ID=eID then begin
+ result:=Es[i];
+ exit;
+ end;
+ result:=tEreignis.create;
+ result.ID:=eID;
+ setlength(Es,length(Es)+1);
+ Es[length(Es)-1]:=result;
+ Es[length(Es)-1].index:=length(Es)-1;
+end;
+
+function findeFamilie(var Fs: tFamilieArray; fID: String): tFamilie;
+begin
+ result:=findeFamilie(Fs,fID,true);
+end;
+
+function findeFamilie(var Fs: tFamilieArray; fID: String; darfErzeugen: boolean): tFamilie;
+var i: longint;
+begin
+ if fID='NIL' then begin
+ result:=nil;
+ exit;
+ end;
+ for i:=0 to length(Fs)-1 do
+ if Fs[i].ID=fID then begin
+ result:=Fs[i];
+ exit;
+ end;
+ if darfErzeugen then begin
+ result:=tFamilie.create;
+ result.ID:=fID;
+ setlength(Fs,length(Fs)+1);
+ Fs[length(Fs)-1]:=result;
+ Fs[length(Fs)-1].index:=length(Fs)-1;
+ end
+ else
+ result:=nil;
+end;
+
+function findePerson(var Ps: tPersonArray; pID: String): tPerson;
+begin
+ result:=findePerson(Ps,pID,true);
+end;
+
+function findePerson(var Ps: tPersonArray; pID: String; darfErzeugen: boolean): tPerson;
+var i: longint;
+begin
+ if pID='NIL' then begin
+ result:=nil;
+ exit;
+ end;
+ for i:=0 to length(Ps)-1 do
+ if Ps[i].ID=pID then begin
+ result:=Ps[i];
+ exit;
+ end;
+ if darfErzeugen then begin
+ result:=tPerson.create;
+ result.ID:=pID;
+ setlength(Ps,length(Ps)+1);
+ Ps[length(Ps)-1]:=result;
+ Ps[length(Ps)-1].index:=length(Ps)-1;
+ end
+ else
+ result:=nil;
+end;
+
+function findeMMInteraktion(var MMs: tMMInteraktionArray; var Ps: tPersonArray; ia: string): tMMInteraktion;
+var
+ i: longint;
+begin
+ for i:=0 to length(MMs)-1 do
+ if tMMInteraktionToStr(MMs[i])=ia then begin
+ result:=MMs[i];
+ exit;
+ end;
+ setlength(MMs,length(MMs)+1);
+ MMs[length(MMs)-1]:=importMMInteraktion(Ps,ia);
+ MMs[length(MMs)-1].index:=length(MMs)-1;
+end;
+
+function findeMFInteraktion(var MFs: tMFInteraktionArray; var Ps: tPersonArray; var Fs: tFamilieArray; ia: string): tMFInteraktion;
+var
+ i: longint;
+begin
+ for i:=0 to length(MFs)-1 do
+ if tMFInteraktionToStr(MFs[i])=ia then begin
+ result:=MFs[i];
+ exit;
+ end;
+ setlength(MFs,length(MFs)+1);
+ MFs[length(MFs)-1]:=importMFInteraktion(Ps,Fs,ia);
+ MFs[length(MFs)-1].index:=length(MFs)-1;
+end;
+
+function findeFFInteraktion(var FFs: tFFInteraktionArray; var Fs: tFamilieArray; ia: string): tFFInteraktion;
+var
+ i: longint;
+begin
+ for i:=0 to length(FFs)-1 do
+ if tFFInteraktionToStr(FFs[i])=ia then begin
+ result:=FFs[i];
+ exit;
+ end;
+ setlength(FFs,length(FFs)+1);
+ FFs[length(FFs)-1]:=importFFInteraktion(Fs,ia);
+ FFs[length(FFs)-1].index:=length(FFs)-1;
+end;
+
+procedure loescheEreignis(var Es: tEreignisArray; eID: string);
+var i,j: longint;
+begin
+ if eID='NIL' then
+ exit;
+ for i:=0 to length(Es)-1 do
+ if Es[i].ID=eID then begin
+ Es[i].free;
+ for j:=i+1 to length(Es)-1 do begin
+ Es[j-1]:=Es[j];
+ Es[j-1].index:=j-1;
+ end;
+ setlength(Es,length(Es)-1);
+ exit;
+ end;
+end;
+
+procedure loescheFamilie(var Fs: tFamilieArray; fID: string);
+var i,j: longint;
+begin
+ if fID='NIL' then
+ exit;
+ for i:=0 to length(Fs)-1 do
+ if Fs[i].ID=fID then begin
+ Fs[i].free;
+ for j:=i+1 to length(Fs)-1 do begin
+ Fs[j-1]:=Fs[j];
+ Fs[j-1].index:=j-1;
+ end;
+ setlength(Fs,length(Fs)-1);
+ exit;
+ end;
+end;
+
+procedure loeschePerson(var Ps: tPersonArray; pID: string);
+var i,j: longint;
+begin
+ if pID='NIL' then
+ exit;
+ for i:=0 to length(Ps)-1 do
+ if Ps[i].ID=pID then begin
+ Ps[i].free;
+ for j:=i+1 to length(Ps)-1 do begin
+ Ps[j-1]:=Ps[j];
+ Ps[j-1].index:=j-1;
+ end;
+ setlength(Ps,length(Ps)-1);
+ exit;
+ end;
+end;
+
+procedure mergePerson(var Ps: tPersonArray; var P: tPerson);
+var i: longint;
+begin
+ for i:=0 to length(Ps)-1 do
+ if Ps[i].ID=P.ID then begin
+ P.free;
+ P:=Ps[i];
+ exit;
+ end;
+ setlength(Ps,length(Ps)+1);
+ Ps[length(Ps)-1]:=P;
+ Ps[length(Ps)-1].index:=length(Ps)-1;
+end;
+
+procedure mergeFamilie(var Fs: tFamilieArray; var F: tFamilie);
+var i: longint;
+begin
+ for i:=0 to length(Fs)-1 do
+ if Fs[i].ID=F.ID then begin
+ F.free;
+ F:=Fs[i];
+ exit;
+ end;
+ setlength(Fs,length(Fs)+1);
+ Fs[length(Fs)-1]:=F;
+ Fs[length(Fs)-1].index:=length(Fs)-1;
+end;
+
+function ImportEreignis(S: string; var Es: tEreignisArray): tEreignis;
+var i: Longint;
+ found: boolean;
+begin
+ result:=tEreignis.create;
+ result.ID:=leftStr(S,pos(' ',S)-1);
+ found:=false;
+ for i:=0 to length(Es)-1 do
+ if result.ID = Es[i].ID then begin
+ result.free;
+ result:=Es[i];
+ found:=true;
+ break;
+ end;
+ if not found then begin
+ setlength(Es,length(Es)+1);
+ Es[length(Es)-1]:=result;
+ Es[length(Es)-1].index:=length(Es)-1;
+ end;
+ delete(S,1,pos(' ',S));
+ result.Jahr:=strtoint(leftStr(S,pos(' ',S)-1));
+ delete(S,1,pos(' ',S));
+ result.Art:=TEreignisart(strtoint(S));
+end;
+
+function ImportPerson(S: string; var Ps: tPersonArray; var Es: tEreignisArray; var Fs: tFamilieArray): tPerson;
+var i: longint;
+ found: boolean;
+ ea: TEreignisart;
+begin
+ result:=tPerson.create;
+ result.ID:=leftStr(S,pos(' ',S)-1);
+ found:=false;
+ for i:=0 to length(Ps)-1 do
+ if Ps[i].ID = result.ID then begin
+ result.free;
+ result:=Ps[i];
+ found:=true;
+ break;
+ end;
+ if not found then begin
+ setlength(Ps,length(Ps)+1);
+ Ps[length(Ps)-1]:=result;
+ Ps[length(Ps)-1].index:=length(Ps)-1;
+ end;
+ delete(S,1,pos(' ',S));
+ result.Anfang:=findeEreignis(Es,leftStr(S,pos(' ',S)-1));
+ delete(S,1,pos(' ',S));
+ result.Ende:=findeEreignis(Es,leftStr(S,pos(' ',S)-1));
+ delete(S,1,pos(' ',S));
+ for ea:=low(TEreignisart) to high(TEreignisart) do begin
+ result.Ereignisse[ea]:=findeEreignis(Es,leftStr(S,pos(' ',S)-1));
+ delete(S,1,pos(' ',S));
+ end;
+ result.KindIn:=findeFamilie(Fs,leftStr(S,pos(' ',S)-1));
+ delete(S,1,pos(' ',S));
+ result.ElterIn:=ImportFamilieArray(S,Fs);
+ delete(S,1,1);
+ result.Vorname:=leftStr(S,pos('''',S)-1);
+ delete(S,1,pos('''',S)+2);
+ result.Nachname:=leftStr(S,pos('''',S)-1);
+ delete(S,1,pos('''',S)+1);
+ result.P1:=strtoint(leftStr(S,pos(' ',S)-1));
+ delete(S,1,pos(' ',S));
+ result.P2:=strtoint(leftStr(S,pos(' ',S)-1));
+ delete(S,1,pos(' ',S));
+ result.P3:=strtoint(S);
+end;
+
+function ImportFamilie(s: string; var Ps: tPersonArray; var Es: tEreignisArray; var Fs: tFamilieArray): tFamilie;
+var i: longint;
+ found: boolean;
+begin
+ result:=tFamilie.create;
+ result.ID:=leftStr(S,pos(' ',S)-1);
+ found:=false;
+ for i:=0 to length(Fs)-1 do
+ if Fs[i].ID = result.ID then begin
+ result.free;
+ result:=Fs[i];
+ found:=true;
+ break;
+ end;
+ if not found then begin
+ setlength(Fs,length(Fs)+1);
+ Fs[length(Fs)-1]:=result;
+ Fs[length(Fs)-1].index:=length(Fs)-1;
+ end;
+ delete(S,1,pos(' ',S));
+ result.Anfang:=findeEreignis(Es,leftStr(S,pos(' ',S)-1));
+ delete(S,1,pos(' ',S));
+ result.Verheiratet:=leftStr(S,pos(' ',S)-1)='1';
+ delete(S,1,pos(' ',S));
+ result.Eltern[0]:=findePerson(Ps,leftStr(S,pos(' ',S)-1));
+ delete(S,1,pos(' ',S));
+ result.Eltern[1]:=findePerson(Ps,leftStr(S,pos(' ',S)-1));
+ delete(S,1,pos(' ',S));
+ S:=S+' ';
+ result.Kinder:=importPersonArray(S,Ps);
+end;
+
+function strToTVerknuepfung(var Ps: tPersonArray; S: String): tVerknuepfung;
+var i: Longint;
+ c: Char;
+begin
+ S:=S+' ';
+ result:=tVerknuepfung.create;
+ result.outP:=findePerson(Ps,leftStr(S,pos(' ',S)-1));
+ delete(S,1,pos(' ',S));
+ for i:=0 to 1 do
+ for c:='x' to 'y' do begin
+ result.Input[i,c]:=strtoint(leftStr(S,pos(' ',S)-1));
+ delete(S,1,pos(' ',S));
+ end;
+ result.Lambda:=strtoint(leftStr(S,pos(' ',S)-1));
+ delete(S,1,pos(' ',S));
+ for C:='x' to 'y' do begin
+ result.Output[C]:=strtoint(leftStr(S,pos(' ',S)-1));
+ delete(S,1,pos(' ',S));
+ end;
+end;
+
+function importMMInteraktion(var Ps: tPersonArray; S: String): tMMInteraktion;
+var i: Longint;
+begin
+ result:=tMMInteraktion.create;
+ for i:=0 to 1 do begin
+ result._Ps[i]:=findePerson(Ps,leftStr(S,pos(' ',S)-1));
+ delete(S,1,pos(' ',S));
+ end;
+ result.Laenge:=mystrtofloat(S);
+end;
+
+function importMFInteraktion(var Ps: tPersonArray; var Fs: tFamilieArray; S: String): tMFInteraktion;
+begin
+ result:=tMFInteraktion.create;
+ result._P:=findePerson(Ps,leftStr(S,pos(' ',S)-1));
+ delete(S,1,pos(' ',S));
+ result._F:=findeFamilie(Fs,leftStr(S,pos(' ',S)-1));
+ delete(S,1,pos(' ',S));
+ result.Laenge:=mystrtofloat(S);
+end;
+
+function importFFInteraktion(var Fs: tFamilieArray; S: String): tFFInteraktion;
+var i: longint;
+begin
+ result:=tFFInteraktion.create;
+ S:=S+' ';
+ for i:=0 to 1 do begin
+ result._Fs[i]:=findeFamilie(Fs,leftStr(S,pos(' ',S)-1));
+ delete(S,1,pos(' ',S));
+ end;
+end;
+
+function ImportFamilieArray(var S: String; var Fs: tFamilieArray): tFamilieArray;
+var I: Longint;
+begin
+ setlength(result,strtoint(leftStr(S,pos(' ',S)-1)));
+ delete(S,1,pos(' ',S));
+ for I:=0 to length(result)-1 do begin
+ result[I]:=findeFamilie(Fs,leftStr(S,pos(' ',S)-1));
+ result[I].index:=I;
+ delete(S,1,pos(' ',S));
+ end;
+end;
+
+function ImportPersonArray(var S: String; var Ps: tPersonArray): tPersonArray;
+var I: Longint;
+begin
+ setlength(result,strtoint(leftStr(S,pos(' ',S)-1)));
+ delete(S,1,pos(' ',S));
+ for I:=0 to length(result)-1 do begin
+ result[I]:=findePerson(Ps,leftStr(S,pos(' ',S)-1));
+ result[I].index:=I;
+ delete(S,1,pos(' ',S));
+ end;
+end;
+
+procedure StrToTIntArray(var S: String; var A: TIntArray);
+var I: Longint;
+begin
+ setlength(A,strtoint(leftStr(S,pos(' ',S)-1)));
+ delete(S,1,pos(' ',S));
+ for I:=0 to length(A)-1 do begin
+ A[I]:=strtoint(leftStr(S,pos(' ',S)-1));
+ delete(S,1,pos(' ',S));
+ end;
+end;
+
+function Permutation(n: Longint): TIntArray;
+var
+ I,J: integer;
+begin
+ if n<=0 then setlength(result,0)
+ else begin
+ result:=Permutation(n-1);
+ I:=random(n);
+ setlength(result,n);
+ for J:=n-1 downto I+1 do
+ result[J]:=result[J-1];
+ result[I]:=n-1;
+ end;
+end;
+
+// tParameterAttribut **********************************************************
+
+procedure tParameterAttribut.setzeKoordinate(ik: boolean);
+begin
+ if istKoordinate=ik then begin
+ write('Parameter ist bereits als ');
+ if not ik then write('nicht-');
+ writeln('Koordinate markiert!');
+ halt;
+ end;
+ istKoordinate:=ik;
+end;
+
+procedure tParameterAttribut.setzeUnabhaengig(iu: boolean);
+begin
+ if istUnabhaengig=iu then begin
+ write('Parameter ist bereits als ');
+ if iu then write('un');
+ writeln('abhängig markiert!');
+ halt;
+ end;
+ istUnabhaengig:=iu;
+end;
+
+procedure tParameterAttribut.setzeBenutzt(wb: boolean);
+begin
+ if wirdBenutzt=wb then begin
+ write('Parameter ist bereits als ');
+ if not wb then write('un');
+ writeln('benutzt markiert!');
+ halt;
+ end;
+ wirdBenutzt:=wb;
+end;
+
+procedure tParameterAttribut.fromChar(c: char);
+begin
+ if (c<'0') or (c>'7') then begin
+ writeln(''''+c+''' ist kein gültiger Wert für Parametereigenschaften, sondern nur 0..7.');
+ halt;
+ end;
+ istKoordinate:=odd(ord(c)-ord('0'));
+ istUnabhaengig:=odd((ord(c)-ord('0')) shr 1);
+ wirdBenutzt:=odd((ord(c)-ord('0')) shr 2);
+end;
+
+function tParameterAttribut.toChar: char;
+begin
+ result:=char(ord('0') + byte(istKoordinate) + 2*byte(istUnabhaengig) + 4*byte(wirdBenutzt));
+end;
+
+// tGenerikum ******************************************************************
+
+constructor tGenerikum.create;
+begin
+ inherited create;
+ fillchar(ID,sizeof(ID),#0);
+ index:=-1;
+end;
+
+destructor tGenerikum.destroy;
+begin
+ setlength(ID,0);
+ inherited destroy;
+end;
+
+procedure tGenerikum.init(g: tGenerikum);
+begin
+ ID:=g.ID;
+ index:=g.index;
+end;
+
+function tGenerikum.istGleich(g: tGenerikum): boolean;
+begin
+ result:=ID=g.ID; // Index wird absichtlich nicht mit überprüft, da die Reihenfolge im Array egal sein soll
+end;
+
+// tEreignis *******************************************************************
+
+function tEreignis.istDummy: boolean;
+begin
+ result:=(Art=eaDummy) or (Jahr=0);
+end;
+
+constructor tEreignis.create;
+begin
+ inherited create;
+ jahr:=0;
+ Art:=eaDummy;
+end;
+
+destructor tEreignis.destroy;
+begin
+ inherited destroy;
+end;
+
+procedure tEreignis.init(e: tGenerikum);
+begin
+ inherited init(e);
+ if not (e is tEreignis) then begin
+ writeln('Ereignis kann nicht mit nicht-Ereignis initialisiert werden!');
+ halt;
+ end;
+ jahr:=(e as tEreignis).Jahr;
+ Art:=(e as tEreignis).Art;
+end;
+
+function tEreignis.istGleich(e: tGenerikum): boolean;
+begin
+ result:=inherited istGleich(e);
+ if not (e is tEreignis) then begin
+ writeln('Ereignis kann nicht mit nicht-Ereignis verglichen werden!');
+ halt;
+ end;
+ result:=result and ((e as tEreignis).Jahr=Jahr) and ((e as tEreignis).Art=Art);
+end;
+
+// tPerson *********************************************************************
+
+constructor tPerson.create;
+var ea: tEreignisart;
+begin
+ inherited create;
+ Anfang:=nil;
+ Ende:=nil;
+ for ea:=low(ea) to high(ea) do
+ Ereignisse[ea]:=nil;
+ KindIn:=nil;
+ fillchar(ElterIn,sizeof(ElterIn),#0);
+ fillchar(inputIn,sizeof(inputIn),#0);
+ fillchar(outputIn,sizeof(outputIn),#0);
+ fillchar(Vorname,sizeof(Vorname),#0);
+ fillchar(Nachname,sizeof(Nachname),#0);
+ fillchar(inMMInteraktion,sizeof(inMMInteraktion),#0);
+ fillchar(inMFInteraktion,sizeof(inMFInteraktion),#0);
+ P1:=-1;
+ P2:=-1;
+ P3:=-1;
+end;
+
+destructor tPerson.destroy;
+var
+ i: longint;
+begin
+ if assigned(KindIn) then
+ KindIn.entferneKind(self);
+ for i:=0 to length(ElterIn)-1 do
+ if assigned(ElterIn[i]) then
+ ElterIn[i].entferneElter(self);
+ setlength(ElterIn,0);
+ setlength(Vorname,0);
+ setlength(Nachname,0);
+ if length(inMMInteraktion)<>0 then
+ raise Exception.create('Diese Person ist noch in einer MMInteraktion verzeichnet!');
+ setlength(inMMInteraktion,0);
+ if length(inMFInteraktion)<>0 then
+ raise Exception.create('Diese Person ist noch in einer MFInteraktion verzeichnet!');
+ setlength(inMFInteraktion,0);
+ inherited destroy;
+end;
+
+procedure tPerson.entferneElterIn(wo: tFamilie);
+var
+ i,j: longint;
+begin
+ for i:=length(ElterIn)-1 downto 0 do
+ if ElterIn[i]=wo then begin
+ for j:=i+1 to length(ElterIn)-1 do
+ ElterIn[j-1]:=ElterIn[j];
+ setlength(ElterIn,length(ElterIn)-1);
+ end;
+end;
+
+procedure tPerson.entferneKindIn(wo: tFamilie);
+begin
+ if KindIn=wo then
+ KindIn:=nil;
+end;
+
+procedure tPerson.fuegeInputInHinzu(wo: tVerknuepfung);
+var
+ i: longint;
+begin
+ for i:=0 to length(inputIn)-1 do
+ if inputIn[i]=wo then
+ writeln(inputIn[i+length(inputIn)].outP.id);
+ setlength(inputIn,length(inputIn)+1);
+ inputIn[length(inputIn)-1]:=wo;
+end;
+
+procedure tPerson.entferneInputIn(wo: tVerknuepfung);
+var
+ i,j: longint;
+begin
+ for i:=length(inputIn)-1 downto 0 do
+ if inputIn[i]=wo then begin
+ for j:=i+1 to length(inputIn)-1 do
+ inputIn[j-1]:=inputIn[j];
+ setlength(inputIn,length(inputIn)-1);
+ end;
+end;
+
+procedure tPerson.fuegeOutputInHinzu(wo: tVerknuepfung);
+var
+ i: longint;
+begin
+ for i:=0 to length(outputIn)-1 do
+ if outputIn[i]=wo then
+ writeln(outputIn[i+length(outputIn)].outP.id);
+ setlength(outputIn,length(outputIn)+1);
+ outputIn[length(outputIn)-1]:=wo;
+end;
+
+procedure tPerson.entferneOutputIn(wo: tVerknuepfung);
+var
+ i,j: longint;
+begin
+ for i:=length(outputIn)-1 downto 0 do
+ if outputIn[i]=wo then begin
+ for j:=i+1 to length(outputIn)-1 do
+ outputIn[j-1]:=outputIn[j];
+ setlength(outputIn,length(outputIn)-1);
+ end;
+end;
+
+procedure tPerson.fuegeInMMInteraktionHinzu(wo: tMMInteraktion);
+begin
+ setlength(inMMInteraktion,length(inMMInteraktion)+1);
+ inMMInteraktion[length(inMMInteraktion)-1]:=wo;
+end;
+
+procedure tPerson.entferneInMMInteraktion(wo: tMMInteraktion);
+var
+ i,j: longint;
+begin
+ for i:=length(inMMInteraktion)-1 downto 0 do
+ if inMMInteraktion[i]=wo then begin
+ for j:=i+1 to length(inMMInteraktion)-1 do
+ inMMInteraktion[j-1]:=inMMInteraktion[j];
+ setlength(inMMInteraktion,length(inMMInteraktion)-1);
+ end;
+end;
+
+procedure tPerson.fuegeInMFInteraktionHinzu(wo: tMFInteraktion);
+begin
+ setlength(inMFInteraktion,length(inMFInteraktion)+1);
+ inMFInteraktion[length(inMFInteraktion)-1]:=wo;
+end;
+
+procedure tPerson.entferneInMFInteraktion(wo: tMFInteraktion);
+var
+ i,j: longint;
+begin
+ for i:=length(inMFInteraktion)-1 downto 0 do
+ if inMFInteraktion[i]=wo then begin
+ for j:=i+1 to length(inMFInteraktion)-1 do
+ inMFInteraktion[j-1]:=inMFInteraktion[j];
+ setlength(inMFInteraktion,length(inMFInteraktion)-1);
+ end;
+end;
+
+procedure tPerson.init(p: tGenerikum);
+begin
+ inherited init(p);
+ if not (p is tPerson) then begin
+ writeln('Person kann nicht mit nicht-Person initialisiert werden!');
+ halt;
+ end;
+ Vorname:=(p as tPerson).Vorname;
+ Nachname:=(p as tPerson).Nachname;
+ P1:=(p as tPerson).P1;
+ P2:=(p as tPerson).P2;
+ P3:=(p as tPerson).P3;
+end;
+
+procedure tPerson.init(p: tGenerikum; var es: tEreignisArray);
+var
+ ea: tEreignisArt;
+begin
+ init(p);
+ Anfang:=FindeEreignis(es,pEreignisToStr((p as tPerson).Anfang));
+ Ende:=FindeEreignis(es,pEreignisToStr((p as tPerson).Ende));
+ for ea:=low(tEreignisArt) to high(tEreignisArt) do
+ Ereignisse[ea]:=FindeEreignis(es,pEreignisToStr((p as tPerson).Ereignisse[ea]));
+end;
+
+procedure tPerson.init(p: tGenerikum; var es: tEreignisArray; var fs: tFamilieArray);
+begin
+ init(p,es,fs,true);
+end;
+
+procedure tPerson.init(p: tGenerikum; var es: tEreignisArray; var fs: tFamilieArray; darfErzeugen: boolean);
+var
+ i,j: longint;
+begin
+ init(p,es);
+ KindIn:=findeFamilie(fs,pFamilieToStr((p as tPerson).KindIn),darfErzeugen);
+ if assigned(KindIn) and
+ not KindIn.hatKind(self) then begin
+ setlength(KindIn.Kinder,length(KindIn.Kinder)+1);
+ KindIn.Kinder[length(KindIn.Kinder)-1]:=self;
+ end;
+ setlength(ElterIn,length((p as tPerson).ElterIn));
+ for i:=length(ElterIn)-1 downto 0 do begin
+ ElterIn[i]:=findeFamilie(fs,pFamilieToStr((p as tPerson).ElterIn[i]),darfErzeugen);
+ if assigned(ElterIn[i]) and
+ not ElterIn[i].hatElter(self) then
+ ElterIn[i].Eltern[byte((p as tPerson).ElterIn[i].Eltern[1]=p)]:=self
+ else begin
+ for j:=i+1 to length(ElterIn)-1 do
+ ElterIn[j-1]:=ElterIn[j];
+ setlength(ElterIn,length(ElterIn)-1);
+ end;
+ end;
+end;
+
+function tPerson.anzahlVerbindungen: longint;
+begin
+ result:=length(ElterIn)+byte(assigned(KindIn));
+end;
+
+function tPerson.istGleich(p: tGenerikum): boolean;
+var
+ ea: tEreignisart;
+ i,j,cnt: longint;
+begin
+ result:=inherited istGleich(p);
+ if not (p is tPerson) then begin
+ writeln('Person kann nicht mit nicht-Person verglichen werden!');
+ halt;
+ end;
+ result:=
+ result and
+ (Vorname=(p as tPerson).Vorname) and
+ (Nachname=(p as tPerson).Nachname) and
+ Anfang.istGleich((p as tPerson).Anfang) and
+ Ende.istGleich((p as tPerson).Ende);
+ for ea:=low(tEreignisArt) to high(tEreignisArt) do
+ result:=
+ result and ((Ereignisse[ea]=(p as tPerson).Ereignisse[ea]) or Ereignisse[ea].istGleich((p as tPerson).Ereignisse[ea]));
+ result:=result and (pFamilieToStr(KindIn)=pFamilieToStr((p as tPerson).KindIn));
+ result:=result and (length(ElterIn)=length((p as tPerson).ElterIn));
+ if result then
+ for i:=0 to length(ElterIn)-1 do begin
+ cnt:=0;
+ for j:=0 to length(ElterIn)-1 do
+ if pFamilieToStr(ElterIn[i])=pFamilieToStr((p as tPerson).ElterIn[j]) then
+ inc(cnt);
+ result:=result and (cnt=1);
+ end;
+end;
+
+function tPerson.elterVonFamilie(eNum: longint): tFamilie;
+var
+ i: longint;
+begin
+ result:=nil;
+ for i:=0 to length(elterIn)-1 do
+ if elterIn[i].Eltern[eNum]=self then begin
+ if result<>nil then begin
+ writeln('*** Warnung ***');
+ writeln('Rückgabewert nicht eindeutig, Person '+pPersonToStr(self)+' ist Elter '+inttostr(eNum)+' in mehreren Familien!');
+ exit;
+ end;
+ result:=elterIn[i];
+ end;
+end;
+
+function tPerson.istElterIn(f: tFamilie): boolean;
+var
+ i: longint;
+begin
+ result:=false;
+ for i:=0 to length(elterIn)-1 do
+ result:=result or (elterIn[i]=f);
+end;
+
+// tFamilie ********************************************************************
+
+constructor tFamilie.create;
+begin
+ inherited create;
+ Anfang:=nil;
+ Verheiratet:=false;
+ Eltern[0]:=nil;
+ Eltern[1]:=nil;
+ fillchar(Kinder,sizeof(Kinder),#0);
+ fillchar(inMFInteraktion,sizeof(inMFInteraktion),#0);
+ fillchar(inFFInteraktion,sizeof(inFFInteraktion),#0);
+end;
+
+destructor tFamilie.destroy;
+var
+ i: longint;
+begin
+ for i:=0 to length(Kinder)-1 do
+ if assigned(Kinder[i]) then
+ Kinder[i].entferneKindIn(self);
+ for i:=0 to length(Eltern)-1 do
+ if assigned(Eltern[i]) then
+ Eltern[i].entferneElterIn(self);
+ setlength(Kinder,0);
+ if length(inMFInteraktion)<>0 then
+ raise Exception.create('Diese Familie ist noch in einer MFInteraktion verzeichnet!');
+ setlength(inMFInteraktion,0);
+ if length(inFFInteraktion)<>0 then
+ raise Exception.create('Diese Familie ist noch in einer FFInteraktion verzeichnet!');
+ setlength(inFFInteraktion,0);
+ inherited destroy;
+end;
+
+procedure tFamilie.entferneElter(wen: tPerson);
+var
+ i,anz: longint;
+begin
+ anz:=0;
+ for i:=0 to length(Eltern)-1 do
+ if Eltern[i]=wen then begin
+ inc(anz);
+ Eltern[i]:=nil;
+ end;
+ if anz=0 then begin
+ writeln('Ich habe den Elter '''+wen.ID+''' nicht in Familie '''+ID+''' gefunden!');
+ halt;
+ end;
+ if anz>1 then begin
+ writeln('Ich habe den Elter '''+wen.ID+''' mehrmals in Familie '''+ID+''' gefunden!');
+ halt;
+ end;
+end;
+
+procedure tFamilie.entferneKind(wen: tPerson);
+var
+ i,j,anz: longint;
+begin
+ anz:=0;
+ for i:=length(Kinder)-1 downto 0 do
+ if Kinder[i]=wen then begin
+ inc(Anz);
+ Kinder[i]:=nil;
+ for j:=i+1 to length(Kinder)-1 do
+ Kinder[j-1]:=Kinder[j];
+ setlength(Kinder,length(Kinder)-1);
+ end;
+ if anz=0 then begin
+ writeln('Ich habe das Kind '''+wen.ID+''' nicht in Familie '''+ID+''' gefunden!');
+ halt;
+ end;
+ if anz>1 then begin
+ writeln('Ich habe das Kind '''+wen.ID+''' mehrmals in Familie '''+ID+''' gefunden!');
+ halt;
+ end;
+end;
+
+procedure tFamilie.fuegeInMFInteraktionHinzu(wo: tMFInteraktion);
+begin
+ setlength(inMFInteraktion,length(inMFInteraktion)+1);
+ inMFInteraktion[length(inMFInteraktion)-1]:=wo;
+end;
+
+procedure tFamilie.entferneInMFInteraktion(wo: tMFInteraktion);
+var
+ i,j: longint;
+begin
+ for i:=length(inMFInteraktion)-1 downto 0 do
+ if inMFInteraktion[i]=wo then begin
+ for j:=i+1 to length(inMFInteraktion)-1 do
+ inMFInteraktion[j-1]:=inMFInteraktion[j];
+ setlength(inMFInteraktion,length(inMFInteraktion)-1);
+ end;
+end;
+
+procedure tFamilie.fuegeInFFInteraktionHinzu(wo: tFFInteraktion);
+begin
+ setlength(inFFInteraktion,length(inFFInteraktion)+1);
+ inFFInteraktion[length(inFFInteraktion)-1]:=wo;
+end;
+
+procedure tFamilie.entferneInFFInteraktion(wo: tFFInteraktion);
+var
+ i,j: longint;
+begin
+ for i:=length(inFFInteraktion)-1 downto 0 do
+ if inFFInteraktion[i]=wo then begin
+ for j:=i+1 to length(inFFInteraktion)-1 do
+ inFFInteraktion[j-1]:=inFFInteraktion[j];
+ setlength(inFFInteraktion,length(inFFInteraktion)-1);
+ end;
+end;
+
+procedure tFamilie.init(f: tGenerikum);
+begin
+ inherited init(f);
+ if not (f is tFamilie) then begin
+ writeln('Familie kann nicht mit nicht-Familie initialisiert werden!');
+ halt;
+ end;
+ Verheiratet:=(f as tFamilie).Verheiratet;
+end;
+
+procedure tFamilie.init(f: tGenerikum; var Es: tEreignisArray; var Ps: tPersonArray);
+begin
+ init(f,Es,Ps,true);
+end;
+
+procedure tFamilie.init(f: tGenerikum; var Es: tEreignisArray; var Ps: tPersonArray; darfErzeugen: boolean);
+var
+ i,j: longint;
+begin
+ init(f);
+ Anfang:=findeEreignis(Es,pEreignisToStr((f as tFamilie).Anfang));
+ for i:=0 to 1 do begin
+ Eltern[i]:=findePerson(Ps,pPersonToStr((f as tFamilie).Eltern[i]),darfErzeugen);
+ if assigned(Eltern[i]) and
+ not Eltern[i].istElterIn(self) then begin
+ setlength(Eltern[i].ElterIn,length(Eltern[i].ElterIn)+1);
+ Eltern[i].ElterIn[length(Eltern[i].ElterIn)-1]:=self;
+ end;
+ end;
+ setlength(Kinder,length((f as tFamilie).Kinder));
+ for i:=length(Kinder)-1 downto 0 do begin
+ Kinder[i]:=findePerson(Ps,pPersonToStr((f as tFamilie).Kinder[i]),darfErzeugen);
+ if assigned(Kinder[i]) then
+ Kinder[i].KindIn:=self
+ else begin
+ for j:=i+1 to length(Kinder)-1 do
+ Kinder[j-1]:=Kinder[j];
+ setlength(Kinder,length(Kinder)-1);
+ end;
+ end;
+end;
+
+function tFamilie.anzahlVerbindungen: longint;
+var
+ i: longint;
+begin
+ result:=length(Kinder);
+ for i:=0 to 1 do
+ result:=result+byte(assigned(Eltern[i]));
+end;
+
+function tFamilie.istGleich(f: tGenerikum): boolean;
+var
+ i,j,cnt: longint;
+begin
+ result:=inherited istGleich(f);
+ if not (f is tFamilie) then begin
+ writeln('Familie kann nicht mit nicht-Familie verglichen werden!');
+ halt;
+ end;
+ result:=
+ result and
+ (Verheiratet=(f as tFamilie).Verheiratet) and
+ (Anfang.istGleich((f as tFamilie).Anfang));
+ for i:=0 to 1 do
+ result:=
+ result and
+ (pPersonToStr(Eltern[i])=pPersonToStr((f as tFamilie).Eltern[i]));
+ result:=result and (length(Kinder)=length((f as tFamilie).Kinder));
+ if result then
+ for i:=0 to length(Kinder)-1 do begin
+ cnt:=0;
+ for j:=0 to length(Kinder)-1 do
+ if pPersonToStr(Kinder[i])=pPersonToStr((f as tFamilie).Kinder[j]) then
+ inc(cnt);
+ result:=result and (cnt=1);
+ end;
+end;
+
+function tFamilie.hatKind(p: tPerson): boolean;
+var
+ i: longint;
+begin
+ result:=false;
+ for i:=0 to length(Kinder)-1 do
+ result:=result or (Kinder[i]=p);
+end;
+
+function tFamilie.hatElter(p: tPerson): boolean;
+begin
+ result:=(Eltern[0]=p) or (Eltern[1]=p);
+end;
+
+// tVerknuepfung ***************************************************************
+
+procedure tVerknuepfung.wOutP(p: tPerson);
+begin
+ if assigned(outP) then begin
+ if assigned(outP.KindIn) then begin
+ if assigned(outP.KindIn.Eltern[0]) then
+ outP.KindIn.Eltern[0].entferneInputIn(self);
+ if assigned(outP.KindIn.Eltern[1]) then
+ outP.KindIn.Eltern[1].entferneInputIn(self);
+ outP.entferneOutputIn(self);
+ end;
+ end;
+ _outP:=p;
+ if assigned(outP) then begin
+ if assigned(outP.KindIn) then begin
+ if assigned(outP.KindIn.Eltern[0]) then
+ outP.KindIn.Eltern[0].fuegeInputInHinzu(self);
+ if assigned(outP.KindIn.Eltern[1]) then
+ outP.KindIn.Eltern[1].fuegeInputInHinzu(self);
+ outP.fuegeOutputInHinzu(self);
+ end;
+ end;
+end;
+
+destructor tVerknuepfung.destroy;
+begin
+ if assigned(outP) then begin
+ if assigned(outP.KindIn) then begin
+ if assigned(outP.KindIn.Eltern[0]) then
+ outP.KindIn.Eltern[0].entferneInputIn(self);
+ if assigned(outP.KindIn.Eltern[1]) then
+ outP.KindIn.Eltern[1].entferneInputIn(self);
+ end;
+ outP.entferneOutputIn(self);
+ end;
+ inherited destroy;
+end;
+
+function tVerknuepfung.istGleich(v: tVerknuepfung; p2p: tIntArray): boolean;
+var
+ i: longint;
+ c: char;
+begin
+ result:=
+ (pPersonToStr(outP)=pPersonToStr(v.outP)) and
+ paramsGleich(Lambda,v.Lambda,p2p);
+ for c:='x' to 'y' do begin
+ result:=result and paramsGleich(Output[c],v.Output[c],p2p);
+ for i:=0 to 1 do
+ result:=result and paramsGleich(Input[i,c],v.Input[i,c],p2p);
+ end;
+end;
+
+// tMMInteraktion **************************************************************
+
+function tMMInteraktion.r_Ps(i: longint): tPerson;
+begin
+ result:=__Ps[i];
+end;
+
+procedure tMMInteraktion.w_Ps(i: longint; p: tPerson);
+begin
+ if assigned(_Ps[i]) then
+ _Ps[i].entferneInMMInteraktion(self);
+ __Ps[i]:=p;
+ if assigned(_Ps[i]) then
+ _Ps[i].fuegeInMMInteraktionHinzu(self);
+end;
+
+function tMMInteraktion.istGleich(ia: tMMInteraktion): boolean;
+var
+ i: longint;
+begin
+ result:=Laenge=ia.Laenge;
+ for i:=0 to 1 do
+ result:=result and (pPersonToStr(_Ps[i])=pPersonToStr(ia._Ps[i]));
+end;
+
+destructor tMMInteraktion.destroy;
+begin
+ if assigned(_Ps[0]) then
+ _Ps[0].entferneInMMInteraktion(self);
+ if assigned(_Ps[1]) then
+ _Ps[1].entferneInMMInteraktion(self);
+ inherited destroy;
+end;
+
+// tMFInteraktion **************************************************************
+
+procedure tMFInteraktion.w_P(p: tPerson);
+begin
+ if assigned(_P) then
+ _P.entferneInMFInteraktion(self);
+ __P:=p;
+ if assigned(_P) then
+ _P.fuegeInMFInteraktionHinzu(self);
+end;
+
+procedure tMFInteraktion.w_F(f: tFamilie);
+begin
+ if assigned(_F) then
+ _F.entferneInMFInteraktion(self);
+ __F:=f;
+ if assigned(_F) then
+ _F.fuegeInMFInteraktionHinzu(self);
+end;
+
+function tMFInteraktion.istGleich(ia: tMFInteraktion): boolean;
+begin
+ result:=
+ (Laenge=ia.Laenge) and
+ (pPersonToStr(_P)=pPersonToStr(ia._P)) and
+ (pFamilieToStr(_F)=pFamilieToStr(ia._F));
+end;
+
+destructor tMFInteraktion.destroy;
+begin
+ if assigned(_P) then
+ _P.entferneInMFInteraktion(self);
+ if assigned(_F) then
+ _F.entferneInMFInteraktion(self);
+ inherited destroy;
+end;
+
+// tFFInteraktion **************************************************************
+
+function tFFInteraktion.r_Fs(i: longint): tFamilie;
+begin
+ result:=__Fs[i];
+end;
+
+procedure tFFInteraktion.w_Fs(i: longint; f: tFamilie);
+begin
+ if assigned(_Fs[i]) then
+ _Fs[i].entferneInFFInteraktion(self);
+ __Fs[i]:=f;
+ if assigned(_Fs[i]) then
+ _Fs[i].fuegeInFFInteraktionHinzu(self);
+end;
+
+function tFFInteraktion.istGleich(ia: tFFInteraktion): boolean;
+var
+ i: longint;
+begin
+ result:=true;
+ for i:=0 to 1 do
+ result:=result and (pFamilieToStr(_Fs[i])=pFamilieToStr(ia._Fs[i]));
+end;
+
+destructor tFFInteraktion.destroy;
+begin
+ if assigned(_Fs[0]) then
+ _Fs[0].entferneInFFInteraktion(self);
+ if assigned(_Fs[1]) then
+ _Fs[1].entferneInFFInteraktion(self);
+ inherited destroy;
+end;
+
+// tZusammenhangskomponente ****************************************************
+constructor tZusammenhangskomponente.create;
+begin
+ inherited create;
+ fillchar(Familien,sizeof(Familien),#0);
+ setlength(Familien,0);
+end;
+
+destructor tZusammenhangskomponente.destroy;
+begin
+ setlength(Familien,0);
+ inherited destroy;
+end;
+
+function tZusammenhangskomponente.grenztAn(p: tPerson): boolean;
+var i,j: longint;
+begin
+ result:=false;
+ for i:=0 to length(Familien)-1 do begin
+ for j:=0 to 1 do
+ result:=result or (assigned(Familien[i].Eltern[j]) and (p.ID=Familien[i].Eltern[j].ID));
+ for j:=0 to length(Familien[i].Kinder)-1 do
+ result:=result or (p.ID=Familien[i].Kinder[j].ID);
+ end;
+end;
+
+procedure tZusammenhangskomponente.verschmelzeMit(zhk: tZusammenhangskomponente);
+var i,j: longint;
+ gefunden: boolean;
+begin
+ for i:=0 to length(zhk.Familien)-1 do begin
+ gefunden:=false;
+ for j:=0 to length(Familien)-1 do
+ gefunden:=gefunden or (zhk.Familien[i].ID=Familien[j].ID);
+ if not gefunden then begin
+ setlength(Familien,length(Familien)+1);
+ Familien[length(Familien)-1]:=zhk.Familien[i];
+ end;
+ end;
+end;
+
+procedure tZusammenhangskomponente.UmfeldEinfuegen(Fs: tFamilieArray; p: tPerson);
+var i,j: longint;
+ gefunden: boolean;
+begin
+ for i:=0 to length(Fs)-1 do begin
+ gefunden:=false;
+ for j:=0 to 1 do
+ gefunden:=gefunden or (assigned(Fs[i].Eltern[j]) and (p.ID=Fs[i].Eltern[j].ID));
+ for j:=0 to length(Fs[i].Kinder)-1 do
+ gefunden:=gefunden or (p.ID=Fs[i].Kinder[j].ID);
+ if gefunden then begin
+ for j:=0 to length(Familien)-1 do
+ gefunden:=gefunden and (Familien[j].ID <> Fs[i].ID);
+ if gefunden then begin
+ setlength(Familien,length(Familien)+1);
+ Familien[length(Familien)-1]:=Fs[i];
+ end;
+ end;
+ end;
+end;
+
+// tGraph **********************************************************************
+
+constructor tGraph.create;
+begin
+ inherited create;
+ fillchar(Ecken,sizeof(Ecken),#0);
+ setlength(Ecken,0);
+ fillchar(Kanten,sizeof(Kanten),#0);
+ setlength(Kanten,0);
+end;
+
+destructor tGraph.destroy;
+begin
+ setlength(Ecken,0);
+ setlength(Kanten,0);
+end;
+
+function tGraph.entferneBlaetter(var f: tIntArray): tIntArray;
+var i,j,n1,n2,anz: longint;
+ gefunden: boolean;
+begin
+ setlength(result,0);
+ anz:=0;
+ repeat
+ gefunden:=false;
+ for i:=length(f)-1 downto 0 do begin // nur Kanten, die noch dabei sind, können gelöscht werden
+ n1:=0;
+ n2:=0;
+ for j:=0 to length(f)-1 do begin // angrenzende Kanten, die noch dabei sind, zählen
+ n1:=n1 + byte((Kanten[f[j]].x=Kanten[f[i]].x) or (Kanten[f[j]].y=Kanten[f[i]].x));
+ n2:=n2 + byte((Kanten[f[j]].x=Kanten[f[i]].y) or (Kanten[f[j]].y=Kanten[f[i]].y));
+ end;
+ if (n1<=1) or (n2<=1) then begin // nur die Kante i selbst hängt an einer ihrer Ecken
+ gefunden:=true;
+ if anz>=length(result) then
+ setlength(result,anz+1024);
+ result[anz]:=f[i];
+ inc(anz);
+ for j:=i+1 to length(f)-1 do // aus dem Rennen
+ f[j-1]:=f[j];
+ setlength(f,length(f)-1);
+ end;
+ end;
+ until not gefunden;
+ setlength(result,anz);
+end;
+
+function tGraph.Pfadigkeit(Ks: tIntArray; a,b: longint): longint; // 0 -> zu wenig; 1 -> ein Pfad; 2-> zu viel
+var i,j,k,ich,letzter: longint;
+begin
+ ich:=a;
+ letzter:=-1;
+ repeat
+ j:=-1;
+ k:=0;
+ for i:=0 to length(Ks)-1 do begin
+ if (Kanten[Ks[i]].x=ich) and (Kanten[Ks[i]].y<>letzter) then begin // vorwärts immer, rückwärts nimmer
+ j:=Ks[i];
+ inc(k);
+ end;
+ if (Kanten[Ks[i]].y=ich) and (Kanten[Ks[i]].x<>letzter) then begin // vorwärts immer, rückwärts nimmer
+ j:=Ks[i];
+ inc(k);
+ end;
+ end;
+ if k=0 then begin // hier geht es nicht weiter
+ result:=0;
+ exit;
+ end;
+ if k>1+byte((letzter=-1) and (a=b)) then begin // hier gibt es eine Weggabelung
+ result:=2;
+ exit;
+ end;
+ if Kanten[j].x=ich then begin
+ letzter:=ich;
+ ich:=Kanten[j].y;
+ end
+ else begin
+ letzter:=ich;
+ ich:=Kanten[j].x;
+ end;
+ until ich=b;
+ result:=1;
+end;
+
+function tGraph.etwasDoppelt: boolean;
+var Ks: tIntArray;
+ i: longint;
+begin
+ setlength(Ks,length(Kanten));
+ for i:=0 to length(Ks)-1 do
+ Ks[i]:=i;
+ result:=etwasDoppelt(Ks);
+end;
+
+function tGraph.etwasDoppelt(Ks: tIntArray): boolean;
+var i,j: longint;
+begin
+ result:=false;
+ for i:=0 to length(Ks)-2 do
+ for j:=i+1 to length(Ks)-1 do
+ result:=
+ result or
+ ((Kanten[Ks[i]].x = Kanten[Ks[j]].x) and (Kanten[Ks[i]].y = Kanten[Ks[j]].y)) or
+ ((Kanten[Ks[i]].x = Kanten[Ks[j]].y) and (Kanten[Ks[i]].y = Kanten[Ks[j]].x));
+end;
+
+function tGraph.etwasRedundant(Ks1,Ks2: tIntArray): boolean;
+var i,j: longint;
+begin
+ result:=false;
+ for i:=0 to length(Ks1)-1 do
+ for j:=0 to length(Ks2)-1 do
+ result:=
+ result or
+ ((Kanten[Ks1[i]].x = Kanten[Ks2[j]].x) and (Kanten[Ks1[i]].y = Kanten[Ks2[j]].y)) or
+ ((Kanten[Ks1[i]].x = Kanten[Ks2[j]].y) and (Kanten[Ks1[i]].y = Kanten[Ks2[j]].x));
+end;
+
+procedure tGraph.dumpKantenArray(Ks: tIntArray);
+var
+ i: longint;
+begin
+ writeln(length(Ks));
+ for i:=0 to length(Ks)-1 do
+ writeln(' '+inttostr(Kanten[Ks[i]].x)+' -- '+inttostr(Kanten[Ks[i]].y));
+end;
+
+function tGraph.findeKreise: tIntArrayArray;
+var Farben: tIntArray;
+ i: longint;
+begin
+ setlength(result,0);
+ setlength(Farben,length(Kanten));
+ for i:=0 to length(Farben)-1 do // alles noch dabei
+ Farben[i]:=i;
+ entferneBlaetter(Farben);
+ if length(Farben)>0 then begin
+ result:=findeKreise(Farben);
+ exit;
+ end;
+end;
+
+function tGraph.findeKreise(f: tIntArray): tIntArrayArray;
+var j,k,l,m: longint;
+ loeschung,
+ sicherung: tIntArray;
+begin
+ setlength(result,0);
+ setlength(sicherung,length(f)-1);
+ for j:=0 to length(sicherung)-1 do
+ sicherung[j]:=f[j];
+ loeschung:=entferneBlaetter(sicherung);
+ if length(sicherung)>0 then begin // es sind noch Kanten da, also auch noch Kreise!
+ result:=findeKreise(sicherung); // alle bisher gefundenen Kreise
+ setlength(sicherung,length(sicherung)+length(loeschung)+1);
+ for j:=0 to length(loeschung)-1 do // alle gelöschten Kanten wieder einfügen ...
+ sicherung[length(sicherung)-j-2]:=loeschung[j];
+ sicherung[length(sicherung)-1]:=f[length(f)-1]; // ... wirklich alle!
+ for j:=0 to length(result)-1 do begin // jedem Kreis, der noch in sicherung ist ...
+ m:=-1;
+ for k:=0 to length(result[j])-1 do
+ if m=-1 then
+ for l:=0 to length(sicherung)-1 do
+ if sicherung[l]=result[j,k] then begin // die l-te Kante der Sicherung ist im j-ten Kreis (die k-te Kante)
+ m:=l;
+ break;
+ end;
+ if m=-1 then begin
+ writeln('interessanter Weise habe ich keine Kanten gefunden ...');
+ halt(1);
+ end;
+ for k:=m+1 to length(sicherung)-1 do // ... wird eine noch vorhandene Kante gelöscht ...
+ sicherung[k-1]:=sicherung[k];
+ setlength(sicherung,length(sicherung)-1);
+ entferneBlaetter(sicherung); // ... und dann die Blätter entfernt
+ end;
+ // jetzt sollte ein einziger, "neuer", Kreis verblieben sein
+ if pfadigkeit(sicherung,Kanten[sicherung[0]].x,Kanten[sicherung[0]].x)<>1 then begin
+ writeln('Die Pfadigkeit ist '+inttostr(pfadigkeit(sicherung,Kanten[sicherung[0]].x,Kanten[sicherung[0]].x))+' und nicht 1!');
+ writeln('Der Programmierer hat sich geirrt.'); // offenbar ist es kein einfacher Kreis :-/
+ halt(1);
+ end;
+ setlength(result,length(result)+1);
+ setlength(result[length(result)-1],length(sicherung));
+ for j:=0 to length(sicherung)-1 do
+ result[length(result)-1,j]:=sicherung[j];
+ exit;
+ end;
+
+ setlength(result,1); // es war der letzte Kreis
+ setlength(result[0],length(loeschung)+1);
+ for j:=0 to length(loeschung)-1 do
+ result[0,j]:=loeschung[j];
+ result[0,length(loeschung)]:=f[length(f)-1];
+
+ if pfadigkeit(result[0],Kanten[result[0,0]].x,Kanten[result[0,0]].x)<>1 then begin
+ writeln('Die Pfadigkeit ist '+inttostr(pfadigkeit(result[0],Kanten[result[0,0]].x,Kanten[result[0,0]].x))+' und nicht 1!');
+ writeln('Der Programmierer hat sich geirrt.'); // offenbar ist es kein einfacher Kreis :-/
+ writeln('f:');
+ dumpKantenArray(f);
+ writeln('result[0]:');
+ dumpKantenArray(result[0]);
+ writeln('loeschung:');
+ dumpKantenArray(loeschung);
+ halt(1);
+ end;
+end;
+
+// tSortObject *****************************************************************
+
+constructor tSortObject.create;
+begin
+ inherited create;
+ oG:=nil;
+ oMM:=nil;
+ oMF:=nil;
+ oFF:=nil;
+ oV:=nil;
+ fillchar(ID,sizeof(ID),#0);
+ ID:='';
+end;
+
+procedure tSortObject.assign(g: tGenerikum);
+begin
+ oG:=g;
+ oMM:=nil;
+ oMF:=nil;
+ oFF:=nil;
+ oV:=nil;
+ ID:=sortStringFromObject(g);
+end;
+
+procedure tSortObject.assign(i: tMMInteraktion);
+begin
+ oG:=nil;
+ oMM:=i;
+ oMF:=nil;
+ oFF:=nil;
+ oV:=nil;
+ ID:=sortStringFromObject(oMM);
+end;
+
+procedure tSortObject.assign(i: tMFInteraktion);
+begin
+ oG:=nil;
+ oMM:=nil;
+ oMF:=i;
+ oFF:=nil;
+ oV:=nil;
+ ID:=sortStringFromObject(oMF);
+end;
+
+procedure tSortObject.assign(i: tFFInteraktion);
+begin
+ oG:=nil;
+ oMM:=nil;
+ oMF:=nil;
+ oFF:=i;
+ oV:=nil;
+ ID:=sortStringFromObject(oFF);
+end;
+
+procedure tSortObject.assign(v: tVerknuepfung);
+begin
+ oG:=nil;
+ oMM:=nil;
+ oMF:=nil;
+ oFF:=nil;
+ oV:=v;
+ ID:=sortStringFromObject(oV);
+end;
+
+// allgemeine Funktionen *******************************************************
+
+function sortStringFromObject(g: tGenerikum): string;
+begin
+ result:=g.ID;
+end;
+
+function sortStringFromObject(i: tMMInteraktion): string;
+begin
+ result:=pPersonToStr(i._Ps[0])+','+pPersonToStr(i._Ps[1]);
+end;
+
+function sortStringFromObject(i: tMFInteraktion): string;
+begin
+ result:=pPersonToStr(i._P)+','+pFamilieToStr(i._F);;
+end;
+
+function sortStringFromObject(i: tFFInteraktion): string;
+begin
+ result:=pFamilieToStr(i._Fs[0])+','+pFamilieToStr(i._Fs[1]);
+end;
+
+function sortStringFromObject(v: tVerknuepfung): string;
+begin
+ result:=pPersonToStr(v.outP);
+end;
+
+function sortiere(arr: tGenerikumArray): tGenerikumArray; overload; inline;
+var
+ saIn,saOut: tSortObjectArray;
+ i: longint;
+begin
+ setlength(saIn,length(arr));
+ for i:=0 to length(saIn)-1 do begin
+ saIn[i]:=tSortObject.create;
+ saIn[i].assign(arr[i]);
+ end;
+ saOut:=sortiere(saIn);
+ setlength(result,length(saOut));
+ for i:=0 to length(result)-1 do begin
+ result[i]:=saOut[i].oG;
+ saOut[i].free;
+ end;
+ setlength(saIn,0);
+ setlength(saOut,0);
+end;
+
+function sortiere(arr: tMMInteraktionArray): tMMInteraktionArray; overload; inline;
+var
+ saIn,saOut: tSortObjectArray;
+ i: longint;
+begin
+ setlength(saIn,length(arr));
+ for i:=0 to length(saIn)-1 do begin
+ saIn[i]:=tSortObject.create;
+ saIn[i].assign(arr[i]);
+ end;
+ saOut:=sortiere(saIn);
+ setlength(result,length(saOut));
+ for i:=0 to length(result)-1 do begin
+ result[i]:=saOut[i].oMM;
+ saOut[i].free;
+ end;
+ setlength(saIn,0);
+ setlength(saOut,0);
+end;
+
+function sortiere(arr: tMFInteraktionArray): tMFInteraktionArray; overload; inline;
+var
+ saIn,saOut: tSortObjectArray;
+ i: longint;
+begin
+ setlength(saIn,length(arr));
+ for i:=0 to length(saIn)-1 do begin
+ saIn[i]:=tSortObject.create;
+ saIn[i].assign(arr[i]);
+ end;
+ saOut:=sortiere(saIn);
+ setlength(result,length(saOut));
+ for i:=0 to length(result)-1 do begin
+ result[i]:=saOut[i].oMF;
+ saOut[i].free;
+ end;
+ setlength(saIn,0);
+ setlength(saOut,0);
+end;
+
+function sortiere(arr: tFFInteraktionArray): tFFInteraktionArray; overload; inline;
+var
+ saIn,saOut: tSortObjectArray;
+ i: longint;
+begin
+ setlength(saIn,length(arr));
+ for i:=0 to length(saIn)-1 do begin
+ saIn[i]:=tSortObject.create;
+ saIn[i].assign(arr[i]);
+ end;
+ saOut:=sortiere(saIn);
+ setlength(result,length(saOut));
+ for i:=0 to length(result)-1 do begin
+ result[i]:=saOut[i].oFF;
+ saOut[i].free;
+ end;
+ setlength(saIn,0);
+ setlength(saOut,0);
+end;
+
+function sortiere(arr: tVerknuepfungArray): tVerknuepfungArray; overload; inline;
+var
+ saIn,saOut: tSortObjectArray;
+ i: longint;
+begin
+ setlength(saIn,length(arr));
+ for i:=0 to length(saIn)-1 do begin
+ saIn[i]:=tSortObject.create;
+ saIn[i].assign(arr[i]);
+ end;
+ saOut:=sortiere(saIn);
+ setlength(result,length(saOut));
+ for i:=0 to length(result)-1 do begin
+ result[i]:=saOut[i].oV;
+ saOut[i].free;
+ end;
+ setlength(saIn,0);
+ setlength(saOut,0);
+end;
+
+function sortiere(arr: tSortObjectArray): tSortObjectArray;
+var
+ i: longint;
+ mi,ma: string;
+begin
+ setlength(result,length(arr));
+ if length(arr)=0 then exit;
+ mi:=arr[0].ID;
+ ma:=arr[0].ID;
+ for i:=0 to length(result)-1 do begin
+ result[i]:=arr[i];
+ if cmpStr(mi,arr[i].ID)>0 then
+ mi:=arr[i].ID;
+ if cmpStr(ma,arr[i].ID)<0 then
+ ma:=arr[i].ID;
+ end;
+ sortiere(result,0,length(result)-1,mi,ma);
+end;
+
+procedure sortiere(var arr: tSortObjectArray; von,bis: longint; mi,ma: string);
+var
+ li,re: longint;
+ pivot: string;
+ tmp: tSortObject;
+begin
+ if (von>=bis) or (mi=ma) then exit;
+ li:=von;
+ re:=bis;
+ pivot:=mitte(mi,ma);
+
+ while li<=re do begin
+ while (li<=re) and
+ (cmpStr(arr[li].ID,pivot)<=0) do
+ inc(li);
+ while (li<=re) and
+ (cmpStr(arr[re].ID,pivot)>=0) do
+ dec(re);
+ if li>=re then continue;
+ tmp:=arr[li];
+ arr[li]:=arr[re];
+ arr[re]:=tmp;
+ tmp:=nil;
+ inc(li);
+ dec(re);
+ end;
+ if li<>re+1 then begin
+ writeln('Fehler bei der Pivotisierung: li='+inttostr(li)+' und re='+inttostr(re));
+ halt;
+ end;
+ sortiere(arr,von,li-1,mi,pivot);
+ sortiere(arr,re+1,bis,pivot,ma);
+end;
+
+end.
diff --git a/grampsunit.pas b/grampsunit.pas
new file mode 100644
index 0000000..566c394
--- /dev/null
+++ b/grampsunit.pas
@@ -0,0 +1,4674 @@
+unit grampsunit;
+
+interface
+
+{ $DEFINE detaillierteZeitanalyse}
+
+uses cthreads, grampstypen, sysutils, classes, gmp, grampsmath, randomunit, mystringlistunit, matheunit, systemunit;
+
+const
+ aktuellesJahr = 2015;
+ Standardhochzeitsalter = 25;
+ StandardLebensdauer = 80;
+ Jahrestoleranz = 2;
+ Zusatzueberlapp = 2*Jahrestoleranz;
+ Ueberlappcutoff = 20;
+ Entkreuzungsbelohnungsskalierung = 1e9;
+ OptimaleEhelaenge = 0.03;
+ Laengengewicht = 2*Ueberlappcutoff/(8*sqr(OptimaleEhelaenge*sqr(sqr(OptimaleEhelaenge))));
+ sollABAnteil = 1/20;
+ Schrittweitenmultiplikator = 1.2;
+ epsilon = 1e-100;
+ minSchrittweite = 1e-13;
+ SchrittweitenSchwelle = 1e-10;
+
+ WenTauschen: array[0..3,0..1] of Byte = ((0,0),(0,1),(1,1),(1,0));
+
+type
+ tTimer = class
+ Zeit: extended;
+ stStCnt: int64;
+ running: boolean;
+ constructor create;
+ procedure start;
+ procedure stop;
+ function gibZeit: extended;
+ function gibZeitMittel: extended;
+ end;
+ tNotAus = class(TObject)
+ private
+ bitteBeenden: boolean;
+ public
+ Stati: array[0..9] of boolean;
+ lastKey: char;
+ function istZuende: boolean;
+ constructor create;
+ end;
+
+ tMetaData = class(TObject)
+ private
+ {$IFDEF detaillierteZeitanalyse}
+ abvTimer,ffTimer,mmTimer,mfTimer,famTimer: tTimer;
+ {$ENDIF}
+ Sicherung: tMetaData;
+ Laubhaufen: tGenerikumArray;
+ personAuchDrueber,
+ familieAuchDrueber: tBooleanArray; // ist die Person/Familie auch im darüberliegenden tMetaData vorhanden? (hat nur Bedeutung, wenn es sich um tMetaData.Sicherung handelt)
+ procedure loescheVerknuepfungenZu(p: tPerson);
+ procedure loescheAlleVerbindungenZu(p: tPerson; f: tFamilie);
+ procedure arraysAufraeumen;
+ public
+ ParameterLaenge: longint;
+
+ Ereignisse: tEreignisArray;
+ Personen: tPersonArray;
+ Familien: tFamilieArray;
+
+ Verknuepfungen: tVerknuepfungArray;
+ MMInteraktionen: tMMInteraktionArray;
+ MFInteraktionen: tMFInteraktionArray;
+ FFInteraktionen: tFFInteraktionArray;
+ Parameterattribute: tParameterAttributArray;
+ UnabIndizes: tIntArray;
+ Tauschfamilien: tFamilieArray;
+ constructor create;
+ destructor destroy; override;
+ procedure init(md: tMetaData);
+ procedure printStatus(Level: longint);
+ {$IFDEF detaillierteZeitanalyse}
+ procedure printTimer(prefix: string);
+ {$ENDIF}
+ procedure berechneAbhaengigeVariable(var P: tExtendedArray{$IFDEF detaillierteZeitanalyse}; mainThread: boolean{$ENDIF});
+ procedure GradientenRueckPropagation(P: tExtendedArray{$IFDEF detaillierteZeitanalyse}; mainThread: boolean{$ENDIF}; var grad: tExtendedArray);
+ function Energie(P: tExtendedArray; out Kreuzungen, Kreuzung: longint{$IFDEF detaillierteZeitanalyse}; mainThread: boolean{$ENDIF}): extended;
+ procedure Gradient(P: TExtendedArray{$IFDEF detaillierteZeitanalyse}; mainThread: boolean{$ENDIF}; var grad: tExtendedArray);
+// function findeNaechstesAbhaengiges(Fam: tFamilie; out wo: longint; out Pers: tPerson): boolean;
+ function ladeXML(Datei: String): boolean;
+ procedure generiereFehlendeInfos;
+ function analysiereInteraktionen: boolean;
+ function findeKreise: tPointArrayArray; // x: Person, y: Familie
+ procedure blaetterAbschneiden;
+ procedure letztesBlattWiederAnkleben(out vkn: tVerknuepfung; out p: tPerson);
+ // gibt neue Verknüpfung zurück (oder nil, falls neue Familie eingefügt wurde) und neue Person (oder nil, falls beide Eltern neu sind)
+ procedure nurGroeszteZusammenhangskomponente;
+ procedure konsistenzTest(mitIndizes: boolean);
+ procedure pruefeAufGleichheit(vgl: tMetaData);
+ procedure habePersonGeloescht(p: tPerson);
+ procedure habeFamilieGeloescht(f: tFamilie);
+ procedure habePersonHinzugefuegt(p: tPerson);
+ procedure habeFamilieHinzugefuegt(f: tFamilie);
+ function istPersonAuchDrueber(p: tPerson): boolean;
+ function istFamilieAuchDrueber(f: tFamilie): boolean;
+ procedure indizesErzeugen;
+ function anzUnabhaengig: longint;
+ function anzUnbenutzt: longint;
+ end;
+
+ tParameterSimplex = class
+ private
+ dim,pdim: longint;
+ Ecken: array of tExtendedArray;
+ Schwerpunkt,Energien: tExtendedArray;
+ Kreuzungens,Kreuzungs,Reihenfolge: tIntArray;
+ letzteSchwerpunktberechnung: longint;
+ letzteSchwerpunktabweichung: extended;
+ function besserAls(a,b: longint): longint; overload; // -1: a schlechter als b; 0: gleich gut; 1: a besser als b
+ function besserAls(aKrz: longint; aEnerg: extended; b: longint): longint; overload; // -1: a schlechter als b; 0: gleich gut; 1: a besser als b
+ function besserAls(a,b: longint; hart: boolean): longint; overload; // -1: a schlechter als b; 0: gleich gut (nur, wenn hart=false); 1: a besser als b
+ procedure ordnen;
+ function einsortieren(wen,Luecke: longint): longint;
+ function normalisiere(i: longint): boolean; overload;
+ function normalisiere(ps: tExtendedArray): boolean; overload;
+ procedure berechneEnergien(mt: longint); overload;
+ procedure berechneEnergien(mt: longint; ParameterBerechnen: boolean); overload;
+ function berechneSchwerpunkt: extended;
+ public
+ md: tMetaData;
+ constructor create;
+ destructor destroy; override;
+ procedure init(ps: tExtendedArray; mt: longint);
+ procedure outit(var ps: tExtendedArray);
+ function simplexSchritt(f,f1,f2,f3: extended; offset: longint): tSchrittErgebnis; overload;
+ function simplexSchritt(var np: tExtendedArray; f,f1,f2,f3: extended; offset: longint): tSchrittErgebnis; overload; // ohne Speicher-Alloziierung
+ // f ... erster Versuch
+ // f1 ... wenn schlechtester
+ // f2 ... sonst
+ // f3 ... wenn bester
+ procedure berechneEnergie(i: longint{$IFDEF detaillierteZeitanalyse}; mainThread: boolean{$ENDIF});
+ procedure berechneAbhaengigeVariable(i: longint{$IFDEF detaillierteZeitanalyse}; mainThread: boolean{$ENDIF});
+ function minKreuzungen: longint;
+ function maxKreuzungen: longint;
+ function minEnergie: extended;
+ function maxEnergie: extended;
+ procedure printHistogramm;
+ function mittlereKantenlaenge: extended;
+ procedure printSpur(nam: string; von,nach: longint);
+ end;
+
+ tStabile = class(TObject)
+ private
+ NotAus: tNotAus;
+ MD: tMetaData;
+ Parameter: tExtendedArray;
+ Kreuzungen,Schritte: longint;
+ Energie,stepsize,laufzeit: extended;
+ procedure setzeFamilie(Fam: tFamilie; x,y,dist,lambda: extended; var P: tExtendedArray);
+ public
+ property Zeit: extended read laufzeit;
+ constructor create; overload;
+ constructor create(MetaData: TMetaData); overload;
+ destructor destroy; override;
+ procedure assignMetaData(MetaData: TMetaData);
+ procedure printStatus(Level: Longint);
+ function ladeXML(Datei: String): boolean;
+ procedure generiereFehlendeInfos;
+ procedure nurGroeszteZusammenhangskomponente;
+ procedure blaetterAbschneiden;
+ function analysiereInteraktionen: boolean;
+ function LadeVonDatei(Datei: String): boolean;
+ function SpeichereInDatei(Datei: String): boolean;
+ procedure Initialisiere(Anzahl: Longint; Art: string);
+ procedure optimiere;
+ procedure downHillSimplex;
+ procedure gradientenOptimierung;
+ end;
+
+ tEnergieThread = class(tThread)
+ _s: tParameterSimplex;
+ _von,_bis: longint;
+ fertig,bp: boolean;
+ constructor create(s: tParameterSimplex; von,bis: longint; psBerechnen: boolean);
+ destructor destroy; override;
+ procedure execute; override;
+ end;
+
+ tStabileInitThread = class(tThread)
+ private
+ _s: tStabile;
+ _werDran,_extraZufall: tIntArray; // werDran[wannDran[i].x] = i und
+ // wannDran[werDran[j]].x = j
+ _wannDran: t4DPointArray; // 2 ^ -wannDran[i].y ist die eigene Sollbeziehungslänge;
+ _anzahl: longint;
+ _Art: char;
+ _mt: tMersenneTwister;
+ public
+ fertig: boolean;
+ Kreuzungen: longint;
+ Energie: extended;
+ Parameter: tExtendedArray;
+ constructor create(s: tStabile; werDran,extraZufall: tIntArray; wannDran: t4DPointArray; art: char; anzahl: longint);
+ destructor destroy; override;
+ procedure execute; override;
+ end;
+
+implementation
+
+uses crt, math;
+
+constructor tTimer.create;
+begin
+ inherited create;
+ running:=false;
+ Zeit:=0;
+ stStCnt:=0;
+end;
+
+procedure tTimer.start;
+begin
+ if running then exit;
+ running:=true;
+ inc(stStCnt);
+ Zeit:=Zeit-now;
+end;
+
+procedure tTimer.stop;
+begin
+ if not running then exit;
+ running:=false;
+ Zeit:=Zeit+now;
+end;
+
+function tTimer.gibZeit: extended;
+begin
+ if running then
+ result:=Zeit+now
+ else
+ result:=Zeit;
+end;
+
+function tTimer.gibZeitMittel: extended;
+begin
+ if stStCnt=0 then
+ result:=0
+ else if running then
+ result:=(Zeit+now)/stStCnt
+ else
+ result:=Zeit/stStCnt;
+end;
+
+// ********************************* TNotAus ********************************************************
+
+function TNotAus.istZuende: boolean;
+var c: char;
+begin
+ if keyPressed then begin
+ c:=readkey;
+ case c of
+ #27,'q': bitteBeenden:=true;
+ ' ','p': readkey;
+ '0'..'9': Stati[ord(c)-ord('0')]:=not Stati[ord(c)-ord('0')];
+ else lastKey:=c;
+ end{of case};
+ end;
+ result:=bitteBeenden;
+end;
+
+constructor TNotAus.create;
+var i: longint;
+begin
+ inherited create;
+ bitteBeenden:=false;
+ for i:=0 to 9 do
+ stati[i]:=i<>6;
+ lastKey:=#0;
+end;
+
+// ************************************** TMetaData **********************************************
+
+constructor TMetaData.create;
+begin
+ inherited create;
+ fillchar(Ereignisse,sizeof(Ereignisse),#0);
+ setlength(Ereignisse,0);
+ fillchar(Personen,sizeof(Personen),#0);
+ setlength(Personen,0);
+ fillchar(Familien,sizeof(Familien),#0);
+ setlength(Familien,0);
+ fillchar(Verknuepfungen,sizeof(Verknuepfungen),#0);
+ setlength(Verknuepfungen,0);
+ fillchar(MMInteraktionen,sizeof(MMInteraktionen),#0);
+ setlength(MMInteraktionen,0);
+ fillchar(MFInteraktionen,sizeof(MFInteraktionen),#0);
+ setlength(MFInteraktionen,0);
+ fillchar(FFInteraktionen,sizeof(FFInteraktionen),#0);
+ setlength(FFInteraktionen,0);
+ fillchar(Tauschfamilien,sizeof(Tauschfamilien),#0);
+ setlength(Tauschfamilien,0);
+ fillchar(ParameterAttribute,sizeof(ParameterAttribute),#0);
+ setlength(ParameterAttribute,0);
+ Sicherung:=nil;
+ fillchar(Laubhaufen,sizeof(Laubhaufen),#0);
+ setlength(Laubhaufen,0);
+ fillchar(personAuchDrueber,sizeof(personAuchDrueber),#0);
+ setlength(personAuchDrueber,0);
+ fillchar(familieAuchDrueber,sizeof(familieAuchDrueber),#0);
+ setlength(familieAuchDrueber,0);
+ {$IFDEF detaillierteZeitanalyse}
+ abvTimer:=tTimer.create;
+ ffTimer:=tTimer.create;
+ mfTimer:=tTimer.create;
+ mmTimer:=tTimer.create;
+ famTimer:=tTimer.create;
+ {$ENDIF}
+ ParameterLaenge:=0;
+end;
+
+destructor TMetaData.destroy;
+var
+ i: longint;
+begin
+ for i:=0 to length(MMInteraktionen)-1 do
+ MMInteraktionen[i].free;
+ setlength(MMInteraktionen,0);
+ for i:=0 to length(MFInteraktionen)-1 do
+ MFInteraktionen[i].free;
+ setlength(MFInteraktionen,0);
+ for i:=0 to length(FFInteraktionen)-1 do
+ FFInteraktionen[i].free;
+ setlength(FFInteraktionen,0);
+ for i:=0 to length(Verknuepfungen)-1 do
+ Verknuepfungen[i].free;
+ setlength(Verknuepfungen,0);
+ for i:=0 to length(Ereignisse)-1 do
+ Ereignisse[i].free;
+ setlength(Ereignisse,0);
+ for i:=0 to length(Personen)-1 do
+ Personen[i].free;
+ setlength(Personen,0);
+ for i:=0 to length(Familien)-1 do
+ Familien[i].free;
+ setlength(Familien,0);
+ setlength(Tauschfamilien,0);
+ setlength(ParameterAttribute,0);
+ Sicherung.free;
+ setlength(Laubhaufen,0);
+ setlength(personAuchDrueber,0);
+ setlength(familieAuchDrueber,0);
+ {$IFDEF detaillierteZeitanalyse}
+ abvTimer.free;
+ ffTimer.free;
+ mfTimer.free;
+ mmTimer.free;
+ famTimer.free;
+ {$ENDIF}
+ inherited destroy;
+end;
+
+procedure TMetaData.init(md: tMetaData);
+var
+ i,j: longint;
+ c: char;
+begin
+ md.konsistenzTest(true);
+
+ ParameterLaenge:=md.ParameterLaenge;
+ setlength(ParameterAttribute,length(md.ParameterAttribute));
+ for i:=0 to length(ParameterAttribute)-1 do
+ ParameterAttribute[i]:=md.ParameterAttribute[i];
+
+ setlength(Ereignisse,length(md.Ereignisse));
+ for i:=0 to length(Ereignisse)-1 do begin
+ Ereignisse[i]:=tEreignis.create;
+ Ereignisse[i].init(md.Ereignisse[i]);
+ end;
+
+ setlength(Personen,length(md.Personen));
+ setlength(personAuchDrueber,length(Personen));
+ for i:=0 to length(Personen)-1 do begin
+ Personen[i]:=tPerson.create;
+ Personen[i].init(md.Personen[i],Ereignisse,Familien,false);
+ personAuchDrueber[i]:=true;
+ end;
+
+ setlength(Familien,length(md.Familien));
+ setlength(familieAuchDrueber,length(Familien));
+ for i:=0 to length(Familien)-1 do begin
+ Familien[i]:=tFamilie.create;
+ Familien[i].init(md.Familien[i],Ereignisse,Personen,false);
+ familieAuchDrueber[i]:=true;
+ end;
+
+ setlength(Verknuepfungen,length(md.Verknuepfungen));
+ for i:=0 to length(Verknuepfungen)-1 do begin
+ Verknuepfungen[i]:=tVerknuepfung.create;
+ Verknuepfungen[i].outP:=Personen[md.Verknuepfungen[i].outP.index];
+ Verknuepfungen[i].Lambda:=md.Verknuepfungen[i].Lambda;
+ for c:='x' to 'y' do begin
+ Verknuepfungen[i].Output[c]:=md.Verknuepfungen[i].Output[c];
+ for j:=0 to 1 do
+ Verknuepfungen[i].Input[j,c]:=md.Verknuepfungen[i].Input[j,c];
+ end;
+ Verknuepfungen[i].index:=i;
+ end;
+
+ setlength(MMInteraktionen,length(md.MMInteraktionen));
+ for i:=0 to length(MMInteraktionen)-1 do begin
+ MMInteraktionen[i]:=tMMInteraktion.create;
+ MMInteraktionen[i].Laenge:=md.MMInteraktionen[i].Laenge;
+ for j:=0 to 1 do
+ MMInteraktionen[i]._Ps[j]:=Personen[md.MMInteraktionen[i]._Ps[j].index];
+ MMInteraktionen[i].index:=i;
+ end;
+
+ setlength(MFInteraktionen,length(md.MFInteraktionen));
+ for i:=0 to length(MFInteraktionen)-1 do begin
+ MFInteraktionen[i]:=tMFInteraktion.create;
+ MFInteraktionen[i].Laenge:=md.MFInteraktionen[i].Laenge;
+ MFInteraktionen[i]._F:=Familien[md.MFInteraktionen[i]._F.index];
+ MFInteraktionen[i]._P:=Personen[md.MFInteraktionen[i]._P.index];
+ MFInteraktionen[i].index:=i;
+ end;
+
+ setlength(FFInteraktionen,length(md.FFInteraktionen));
+ for i:=0 to length(FFInteraktionen)-1 do begin
+ FFInteraktionen[i]:=tFFInteraktion.create;
+ for j:=0 to 1 do
+ FFInteraktionen[i]._Fs[j]:=Familien[md.FFInteraktionen[i]._Fs[j].index];
+ FFInteraktionen[i].index:=i;
+ end;
+
+ setlength(Tauschfamilien,length(md.Tauschfamilien));
+ for i:=0 to length(Tauschfamilien)-1 do
+ Tauschfamilien[i]:=Familien[md.Tauschfamilien[i].index];
+
+ konsistenzTest(true);
+end;
+
+procedure TMetaData.printStatus(Level: Longint);
+var
+ I,J,K,L,M: Longint;
+ ea: TEreignisart;
+begin writeln('printstatus('+inttostr(level)+')');
+ case Level of
+ 0: begin
+ J:=0;
+ K:=0;
+ L:=0;
+ M:=0;
+ for I:=0 to length(Personen)-1 do
+ for ea:=low(TEreignisart) to high(TEreignisart) do begin
+ J:=J+Byte(assigned(Personen[I].Ereignisse[ea]));
+ K:=K+Byte(assigned(Personen[I].Ereignisse[ea]) and not Personen[I].Ereignisse[ea].istDummy);
+ end;
+ for I:=0 to length(Familien)-1 do begin
+ L:=L+Byte(assigned(Familien[I].Anfang));
+ M:=M+Byte(assigned(Familien[I].Anfang) and not Familien[I].Anfang.istDummy);
+ end;
+ writeln(inttostr(Level)+') '+inttostr(length(Ereignisse))+' Ereignisse');
+ writeln(inttostr(Level)+') '+inttostr(K)+'/'+inttostr(J)+'<-'+inttostr(length(Personen))+' Personen');
+ writeln(inttostr(Level)+') '+inttostr(M)+'/'+inttostr(L)+'<-'+inttostr(length(Familien))+' Familien');
+ end;
+ 1: begin
+ J:=0;
+ K:=0;
+ L:=0;
+ for I:=0 to length(Personen)-1 do begin
+ J:=J+Byte(not Personen[I].Anfang.istDummy);
+ K:=K+Byte(not Personen[I].Ende.istDummy);
+ end;
+ for I:=0 to length(Familien)-1 do
+ L:=L+Byte(not Familien[I].Anfang.istDummy);
+ writeln(inttostr(Level)+') '+inttostr(J)+'/'+inttostr(K)+'/'+inttostr(length(Personen))+' Personen');
+ writeln(inttostr(Level)+') '+inttostr(L)+'/'+inttostr(length(Familien))+' Familien');
+ end;
+ 2,3: begin
+ K:=4096;//Familien[0].Anfang.Jahr-Familien[0].Eltern[0].Anfang.Jahr;
+ L:=-K;
+ for i:=0 to length(Familien)-1 do
+ if not Familien[i].Anfang.istDummy then
+ for j:=0 to 1 do
+ if assigned(Familien[I].Eltern[J]) and
+ not Familien[I].Eltern[J].Anfang.istDummy then begin
+ K:=min(K,Familien[I].Anfang.Jahr-Familien[I].Eltern[J].Anfang.Jahr);
+ L:=max(L,Familien[I].Anfang.Jahr-Familien[I].Eltern[J].Anfang.Jahr);
+ end;
+ writeln(inttostr(Level)+') '+inttostr(K)+' <= Hochzeitsalter <= '+inttostr(L));
+ if Level=2 then exit;
+ for i:=0 to length(Familien)-1 do
+ if not Familien[i].Anfang.istDummy then
+ for j:=0 to 1 do
+ if assigned(Familien[I].Eltern[J]) and
+ not Familien[I].Eltern[J].Anfang.istDummy then begin
+ if K=Familien[I].Anfang.Jahr-Familien[I].Eltern[J].Anfang.Jahr then begin
+ writeln(
+ inttostr(Level)+') Minimalist:');
+ writeln(
+ ' '+Familien[I].Eltern[J].Vorname+' '+
+ Familien[I].Eltern[J].Nachname+' (G:'+
+ inttostr(Familien[I].Eltern[J].Anfang.Jahr)+' H:'+
+ inttostr(Familien[I].Anfang.Jahr)+' ['+
+ inttostr(byte(Familien[I].Anfang.Art))+']) in Familie '+inttostr(I));
+ if assigned(Familien[i].Eltern[1-j]) then
+ writeln(
+ ' mit '+Familien[I].Eltern[1-j].Vorname+' '+
+ Familien[I].Eltern[1-j].Nachname+' (G:'+
+ inttostr(Familien[I].Eltern[1-j].Anfang.Jahr)+' H:'+
+ inttostr(Familien[I].Anfang.Jahr)+' ['+
+ inttostr(byte(Familien[I].Anfang.Art))+']) in Familie '+inttostr(I));
+// writeln(' '+(Familien[I].Eltern[J])+' in Familie '+tFamilieToStr(Familien[I]));
+ end;
+ if L=Familien[I].Anfang.Jahr-Familien[I].Eltern[J].Anfang.Jahr then begin
+ writeln(
+ inttostr(Level)+') Maximalist:');
+ writeln(
+ ' '+Familien[I].Eltern[J].Vorname+' '+
+ Familien[I].Eltern[J].Nachname+' (G:'+
+ inttostr(Familien[I].Eltern[J].Anfang.Jahr)+' H:'+
+ inttostr(Familien[I].Anfang.Jahr)+' ['+
+ inttostr(byte(Familien[I].Anfang.Art))+']) in Familie '+inttostr(I));
+ if assigned(Familien[i].Eltern[1-j]) then
+ writeln(
+ ' mit '+Familien[I].Eltern[1-j].Vorname+' '+
+ Familien[I].Eltern[1-j].Nachname+' (G:'+
+ inttostr(Familien[I].Eltern[1-j].Anfang.Jahr)+' H:'+
+ inttostr(Familien[I].Anfang.Jahr)+' ['+
+ inttostr(byte(Familien[I].Anfang.Art))+']) in Familie '+inttostr(I));
+// writeln(' '+tPersonToStr(Familien[I].Eltern[J])+' in Familie '+tFamilieToStr(Familien[I]));
+ end;
+ end;
+ end;
+ 4: begin
+ writeln(inttostr(Level)+') '+inttostr(anzUnabhaengig)+' unabhängige Variable');
+ writeln(inttostr(Level)+') '+inttostr(ParameterLaenge)+' Variable insgesamt');
+ writeln(inttostr(Level)+') '+inttostr(length(Verknuepfungen))+' Verknuepfungen');
+ writeln(inttostr(Level)+') '+inttostr(length(MMInteraktionen))+' Mensch-Mensch-Wechselwirkungen');
+ writeln(inttostr(Level)+') '+inttostr(length(MFInteraktionen))+' Mensch-Familie-Wechselwirkungen');
+ writeln(inttostr(Level)+') '+inttostr(length(FFInteraktionen))+' Familie-Familie-Wechselwirkungen');
+ writeln(inttostr(Level)+') '+inttostr(length(Tauschfamilien))+' Familien mit >= 2 Kindern');
+ end;
+ else
+ writeln('Illegales Argument für Funktionsaufruf von TMetaData.printStatus!');
+ end{of case};
+end;
+
+{$IFDEF detaillierteZeitanalyse}
+procedure TMetaData.printTimer(prefix: string);
+begin
+ writeln(prefix+'Abv: '+mytimetostr(abvTimer.gibZeit)+' (avg. '+myfloattostr(abvTimer.gibZeitMittel*24*60*60)+' s)');
+ writeln(prefix+'MM: '+mytimetostr(mmTimer.gibZeit)+' (avg. '+myfloattostr(mmTimer.gibZeitMittel*24*60*60)+' s)');
+ writeln(prefix+'MF: '+mytimetostr(mfTimer.gibZeit)+' (avg. '+myfloattostr(mfTimer.gibZeitMittel*24*60*60)+' s)');
+ writeln(prefix+'FF: '+mytimetostr(ffTimer.gibZeit)+' (avg. '+myfloattostr(ffTimer.gibZeitMittel*24*60*60)+' s)');
+ writeln(prefix+'Fam: '+mytimetostr(famTimer.gibZeit)+' (avg. '+myfloattostr(famTimer.gibZeitMittel*24*60*60)+' s)');
+end;
+{$ENDIF}
+
+procedure TMetaData.berechneAbhaengigeVariable(var P: TExtendedArray{$IFDEF detaillierteZeitanalyse}; mainThread: boolean{$ENDIF});
+var
+ i: Longint;
+ c: Char;
+begin
+ {$IFDEF detaillierteZeitanalyse}
+ if mainThread then abvTimer.start;
+ {$ENDIF}
+ for i:=0 to length(Verknuepfungen)-1 do
+ for c:='x' to 'y' do
+ P[Verknuepfungen[i].Output[c]]:=
+ P[Verknuepfungen[i].Input[0,c]]*(1-P[Verknuepfungen[i].Lambda]) +
+ P[Verknuepfungen[i].Input[1,c]]*P[Verknuepfungen[i].Lambda];
+ {$IFDEF detaillierteZeitanalyse}
+ if mainThread then abvTimer.stop;
+ {$ENDIF}
+end;
+
+procedure TMetaData.GradientenRueckPropagation(P: tExtendedArray{$IFDEF detaillierteZeitanalyse}; mainThread: boolean{$ENDIF}; var grad: tExtendedArray);
+var
+ i: Longint;
+ c: Char;
+begin
+ {$IFDEF detaillierteZeitanalyse}
+ if mainThread then abvTimer.start;
+ {$ENDIF}
+ for i:=length(Verknuepfungen)-1 downto 0 do
+ for c:='x' to 'y' do begin
+ grad[Verknuepfungen[i].Input[0,c]]:=
+ grad[Verknuepfungen[i].Input[0,c]] + (1-P[Verknuepfungen[i].Lambda])*grad[Verknuepfungen[i].Output[c]];
+ grad[Verknuepfungen[i].Input[1,c]]:=
+ grad[Verknuepfungen[i].Input[1,c]] + P[Verknuepfungen[i].Lambda]*grad[Verknuepfungen[i].Output[c]];
+ grad[Verknuepfungen[i].Lambda]:=
+ grad[Verknuepfungen[i].Lambda]
+ + (P[Verknuepfungen[i].Input[1,c]] - P[Verknuepfungen[i].Input[0,c]])*grad[Verknuepfungen[i].Output[c]];
+
+// P[Verknuepfungen[i].Output[c]]:=
+// P[Verknuepfungen[i].Input[0,c]]*(1-P[Verknuepfungen[i].Lambda]) +
+// P[Verknuepfungen[i].Input[1,c]]*P[Verknuepfungen[i].Lambda];
+ end;
+ {$IFDEF detaillierteZeitanalyse}
+ if mainThread then abvTimer.stop;
+ {$ENDIF}
+end;
+
+function TMetaData.Energie(P: TExtendedArray; out Kreuzungen, Kreuzung: Longint{$IFDEF detaillierteZeitanalyse}; mainThread: boolean{$ENDIF}): extended;
+{$DEFINE Energie}
+{$I energiefunktion.inc}
+{$UNDEF Energie}
+
+procedure TMetaData.Gradient(P: TExtendedArray{$IFDEF detaillierteZeitanalyse}; mainThread: boolean{$ENDIF}; var Grad: tExtendedArray);
+{$DEFINE Gradient}
+{$I energiefunktion.inc}
+{$UNDEF Gradient}
+
+(*
+function TMetaData.findeNaechstesAbhaengiges(Fam: tFamilie; out wo: longint; out Pers: tPerson): Boolean;
+var
+ I,J,W: Longint;
+ P: tPerson;
+begin
+ if not assigned(Fam) then begin
+ result:=false;
+ wo:=-1;
+ Pers:=nil;
+ exit;
+ end;
+ for I:=0 to 1 do
+ if assigned(Fam.Eltern[I].KindIn) and
+ Fam.Eltern[I].KindIn.abhaengig then begin
+ Pers:=Fam.Eltern[I];
+ wo:=0;
+ result:=true;
+ exit;
+ end;
+ result:=false;
+ wo:=-1;
+ W:=-1;
+ Pers:=nil;
+ for I:=0 to length(Fam.Kinder)-1 do
+ for J:=0 to length(Fam.Kinder[I].ElterIn)-1 do
+ if findeNaechstesAbhaengiges(Fam.Kinder[I].ElterIn[J],W,P) then begin
+ result:=true;
+ if (wo=-1) or (W+1<wo) or ((W+1=wo) and (random<0.5)) then begin
+ Pers:=P;
+ wo:=W+1;
+ end;
+ end;
+end;
+*)
+function TMetaData.ladeXML(Datei: string): boolean;
+var
+ f: tMyStringlist;
+ s: ansistring;
+ Ebene,UEbene,i,j,k,l: longint;
+ Speichern,gefunden: boolean;
+ neuEreignis: tEreignis;
+ neuPerson: tPerson;
+ neuFamilie: tFamilie;
+ duplikatKind: array of tPerson;
+ duplikatFamilie: array of tFamilie;
+begin
+ result:=false;
+ writeln(Datei+' einlesen ...');
+ f:=tMyStringlist.create;
+ if rightStr(Datei,4)='.xml' then
+ f.loadFromFile(Datei)
+ else if rightStr(Datei,7)='.gramps' then
+ f.loadFromGz(Datei)
+ else begin
+ f.free;
+ exit;
+ end;
+
+ neuEreignis:=nil;
+ neuPerson:=nil;
+ neuFamilie:=nil;
+
+ Setlength(Ereignisse,0);
+ Setlength(Personen,0);
+ Setlength(Familien,0);
+
+ writeln('... verarbeiten ...');
+
+ setlength(duplikatKind,0);
+ setlength(duplikatFamilie,0);
+
+ Ebene:=0;
+ for i:=0 to f.count-1 do begin
+ s:=f[i];
+ case Ebene of
+ 0: begin
+ if leftStr(S,9)='<database' then
+ inc(Ebene);
+ continue;
+ end;
+ 1: begin
+ if S='</database>' then begin
+ dec(Ebene);
+ break;
+ end;
+ if S='<events>' then begin
+ inc(Ebene);
+ UEbene:=0;
+ continue;
+ end;
+ if leftStr(S,7)='<people' then begin
+ inc(Ebene);
+ UEbene:=1;
+ continue;
+ end;
+ if S='<families>' then begin
+ inc(Ebene);
+ UEbene:=2;
+ continue;
+ end;
+ end;
+ 2: begin
+ case UEbene of
+ 0: begin
+ if S='</events>' then begin
+ dec(Ebene);
+ continue;
+ end;
+ if leftStr(S,6)='<event' then begin
+ delete(S,1,pos('handle="',S)+7);
+ neuEreignis:=findeEreignis(Ereignisse,leftStr(S,pos('"',S)-1));
+ Speichern:=true;
+ inc(Ebene);
+ end;
+ end;
+ 1: begin
+ if S='</people>' then begin
+ dec(Ebene);
+ continue;
+ end;
+ if leftStr(S,7)='<person' then begin
+ delete(S,1,pos('handle="',S)+7);
+ neuPerson:=findePerson(Personen,leftStr(S,pos('"',S)-1));
+ Speichern:=true;
+ inc(Ebene);
+ end;
+ end;
+ 2: begin
+ if S='</families>' then begin
+ dec(Ebene);
+ continue;
+ end;
+ if leftStr(S,7)='<family' then begin
+ delete(S,1,pos('handle="',S)+7);
+ neufamilie:=findeFamilie(Familien,leftStr(S,pos('"',S)-1));
+ Speichern:=true;
+ inc(Ebene);
+ end;
+ end;
+ end{of Case};
+ end;
+ 3: begin
+ if (leftStr(s,11)='<attribute ') or (s='</attribute>') or
+ (leftStr(s,8)='<objref ') or (leftStr(s,13)='<citationref ') or
+ (s='</objref>') or (leftStr(s,9)='<noteref ') or
+ (leftStr(s,7)='<place ') or (leftStr(s,12)='<description') then
+ continue;
+ case UEbene of
+ 0: begin
+ if S='</event>' then begin
+ if not (Speichern and ((neuEreignis.Jahr<>0) or (neuEreignis.Art=eaHochzeit))) then
+ loescheEreignis(Ereignisse,neuEreignis.ID);
+ neuEreignis:=nil;
+ dec(Ebene);
+ continue;
+ end;
+ if leftStr(S,6)='<type>' then begin
+ delete(S,1,6);
+ S:=leftStr(S,pos('</type>',S)-1);
+ if (S='Jugendweihe') or (S='Confirmation') or (S='Engagement') or
+ (S='Flucht') or (S='Divorce') or (S='Military Service') or
+ (S='Medical Information') or (S='Education') or (S='Unknown') or
+ (S='Cremation') or (S='Residence') or (S='Graduation') or (S='Emigration') then begin
+ Speichern:=false;
+ Continue;
+ end;
+ if (S='Birth') or (S='Geburt') then begin
+ neuEreignis.Art:=eaGeburt;
+ Continue;
+ end;
+ if S='Christening' then begin
+ neuEreignis.Art:=eaTaufe;
+ Continue;
+ end;
+ if S='Marriage' then begin
+ neuEreignis.Art:=eaHochzeit;
+ Continue;
+ end;
+ if S='Death' then begin
+ neuEreignis.Art:=eaTod;
+ Continue;
+ end;
+ if (S='Burial') or (S='Vermißt') then begin
+ neuEreignis.Art:=eaBeerdigung;
+ Continue;
+ end;
+ writeln('Eventtyp: '+s);
+ continue;
+ end;
+ if leftStr(S,9)='<dateval ' then begin
+ delete(S,1,pos('val="',S)+4);
+ if (S[1] in ['0'..'9']) and
+ (S[2] in ['0'..'9']) and
+ (S[3] in ['0'..'9']) and
+ (S[4] in ['0'..'9']) then
+ neuEreignis.Jahr:=strtoint(copy(S,1,4))
+ else
+ neuEreignis.Jahr:=0;
+ continue;
+ end;
+ if leftStr(s,9)='<datestr ' then
+ continue;
+ writeln('Event: '+s);
+ end;
+ 1: begin
+ if S='</person>' then begin
+ if not Speichern then
+ loeschePerson(Personen,neuPerson.ID);
+ neuPerson:=nil;
+ dec(Ebene);
+ continue;
+ end;
+ if leftStr(S,10)='<eventref ' then begin
+ delete(S,1,pos('hlink="',S)+6);
+ S:=leftStr(S,pos('"',S)-1);
+ neuEreignis:=findeEreignis(Ereignisse,S);
+ neuPerson.Ereignisse[neuEreignis.Art]:=neuEreignis;
+ neuEreignis:=nil;
+ continue;
+ end;
+ if leftstr(S,7)='<first>' then begin
+ delete(S,1,pos('>',S));
+ NeuPerson.Vorname:=copy(S,1,pos('</first>',S)-1);
+ continue;
+ end;
+ if leftstr(S,9)='<surname>' then begin
+ delete(S,1,pos('>',S));
+ NeuPerson.Nachname:=copy(S,1,pos('</surname>',S)-1);
+ continue;
+ end;
+ if leftstr(S,17)='<parentin hlink="' then begin
+ delete(S,1,pos('"',S));
+ neuFamilie:=findeFamilie(Familien,leftStr(s,pos('"',s)-1));
+ mergeFamilie(neuPerson.elterIn,neuFamilie);
+ neuFamilie:=nil;
+ continue;
+ end;
+ if (leftStr(s,16)='<childof hlink="') then begin
+ delete(S,1,pos('"',S));
+ if assigned(neuPerson.KindIn) then begin
+ setlength(duplikatKind,length(duplikatKind)+1);
+ duplikatKind[length(duplikatKind)-1]:=neuPerson;
+ setlength(duplikatFamilie,length(duplikatFamilie)+1);
+ duplikatFamilie[length(duplikatFamilie)-1]:=neuPerson.KindIn;
+ end;
+ neuPerson.KindIn:=findeFamilie(Familien,leftStr(s,pos('"',s)-1));
+ continue;
+ end;
+ if (leftStr(s,9)='<country>') or (leftStr(s,8)='<gender>') or
+ (leftStr(s,6)='<name ') or (s='</name>') or (leftStr(s,8)='<region ') or
+ (leftStr(s,6)='<nick>') or (s='<address>') or (s='</address>') or
+ (leftStr(s,6)='<city>') or (leftStr(s,12)='<familynick>') or
+ (leftStr(s,8)='<street>') or (leftStr(s,7)='<title>') or
+ (leftStr(s,6)='<call>') or (leftStr(s,9)='<dateval ') or
+ (leftStr(s,8)='<postal>') or (leftStr(s,7)='<state>') then
+ continue;
+ writeln('Person: '+s);
+ end;
+ 2: begin
+ if S='</family>' then begin
+ if not Speichern then
+ loescheFamilie(Familien,neuFamilie.ID);
+ neuFamilie:=nil;
+ dec(Ebene);
+ continue;
+ end;
+ if leftStr(S,5)='<rel ' then begin
+ delete(S,1,pos('type="',S)+5);
+ S:=leftStr(S,pos('"',S)-1);
+ if S='Married' then begin
+ NeuFamilie.verheiratet:=true;
+ continue;
+ end;
+ if (S='Unmarried') or (S='Unknown') then begin
+ neuFamilie.verheiratet:=false;
+ continue;
+ end;
+ writeln('Familienrelation: '+s);
+ continue;
+ end;
+ if leftStr(S,8)='<father ' then begin
+ delete(S,1,pos('hlink="',S)+6);
+ S:=leftstr(S,pos('"',S)-1);
+ neuFamilie.Eltern[0]:=findePerson(Personen,S);
+ continue;
+ end;
+ if leftStr(S,8)='<mother ' then begin
+ delete(S,1,pos('hlink="',S)+6);
+ S:=leftstr(S,pos('"',S)-1);
+ neuFamilie.Eltern[1]:=findePerson(Personen,S);
+ continue;
+ end;
+ if leftStr(S,10)='<eventref ' then begin
+ delete(S,1,pos('hlink="',S)+6);
+ S:=leftstr(S,pos('"',S)-1);
+ neuEreignis:=findeEreignis(Ereignisse,S);
+ if (neuEreignis.Art=eaHochzeit) and
+ ((not assigned(NeuFamilie.Anfang)) or
+ (NeuFamilie.Anfang.Jahr > neuEreignis.Jahr)) then
+ neuFamilie.Anfang:=neuEreignis;
+ neuEreignis:=nil;
+ continue;
+ end;
+ if leftStr(S,10)='<childref ' then begin
+ delete(S,1,pos('hlink="',S)+6);
+ S:=leftstr(S,pos('"',S)-1);
+ Setlength(NeuFamilie.Kinder,length(NeuFamilie.Kinder)+1);
+ NeuFamilie.Kinder[length(NeuFamilie.Kinder)-1]:=findePerson(Personen,S);
+ continue;
+ end;
+ if (s='</childref>') then
+ continue;
+ writeln('Familie: '+s);
+ end;
+ end{of Case};
+ end;
+ end{of case};
+ end;
+ f.free;
+ result:=Ebene=0;
+ if not result then begin
+ writeln('Korrupte .xml-Datei!');
+ exit;
+ end;
+
+ if length(duplikatKind)>0 then begin
+ writeln('*** Warnung ***');
+ writeln(inttostr(length(duplikatKind)),' Kind-Familien-Beziehungen waren redundant, ich suche mir jetzt die zu den größten Familien aus!');
+ for i:=0 to length(duplikatKind)-1 do begin
+ gefunden:=false;
+ for j:=0 to i-1 do
+ if duplikatKind[i]=duplikatKind[j] then begin
+ gefunden:=true;
+ break;
+ end;
+ if gefunden then continue;
+
+ k:=-1;
+ l:=length(duplikatKind[i].KindIn.Kinder);
+ for j:=0 to length(duplikatKind)-1 do
+ if duplikatKind[j]=duplikatKind[i] then begin
+ if length(duplikatFamilie[j].Kinder)>l then begin
+ k:=j;
+ l:=length(duplikatFamilie[j].Kinder);
+ end;
+ end;
+ if l>=0 then begin
+ duplikatKind[i].KindIn.entferneKind(duplikatKind[i]);
+ duplikatKind[i].KindIn:=duplikatFamilie[k];
+ end;
+ end;
+ setlength(duplikatKind,0);
+ setlength(duplikatFamilie,0);
+ end;
+
+ konsistenzTest(false);
+ writeln('... fertig:');
+end;
+
+procedure TMetaData.generiereFehlendeInfos;
+var
+ i,j: Longint;
+ dummyEreignis: tEreignis;
+ timeout: extended;
+ gefunden: boolean;
+begin
+ writeln('aufhübschen ...');
+ for i:=0 to length(Familien)-1 do
+ for j:=0 to 1 do
+ if not assigned(Familien[i].Eltern[j]) then begin
+ Familien[i].Eltern[j]:=tPerson.create;
+ Familien[i].Eltern[j].ID:=Familien[i].ID+'_automatischer_Elter'+inttostr(j);
+ setlength(Familien[i].Eltern[j].ElterIn,1);
+ Familien[i].Eltern[j].ElterIn[0]:=Familien[i];
+ setlength(Personen,length(Personen)+1);
+ Personen[length(Personen)-1]:=Familien[i].Eltern[j];
+ end;
+ dummyEreignis:=tEreignis.create;
+ dummyEreignis.ID:='<<42-DUMMY-42>>';
+ dummyEreignis.Jahr:=0;
+ dummyEreignis.Art:=eaDummy;
+ setlength(Ereignisse,length(Ereignisse)+1);
+ Ereignisse[length(Ereignisse)-1]:=dummyEreignis;
+ for I:=0 to length(Familien)-1 do
+ if not assigned(Familien[I].Anfang) then
+ Familien[I].Anfang:=dummyEreignis;
+ for I:=0 to length(Personen)-1 do begin
+ if assigned(Personen[I].Ereignisse[eaGeburt]) and not Personen[I].Ereignisse[eaGeburt].istDummy then
+ Personen[I].Anfang:=Personen[I].Ereignisse[eaGeburt]
+ else if assigned(Personen[I].Ereignisse[eaTaufe]) and not Personen[I].Ereignisse[eaTaufe].istDummy then
+ Personen[I].Anfang:=Personen[I].Ereignisse[eaTaufe]
+ else
+ Personen[I].Anfang:=dummyEreignis;
+ if assigned(Personen[I].Ereignisse[eaTod]) and not Personen[I].Ereignisse[eaTod].istDummy then
+ Personen[I].Ende:=Personen[I].Ereignisse[eaTod]
+ else if assigned(Personen[I].Ereignisse[eaBeerdigung]) and not Personen[I].Ereignisse[eaBeerdigung].istDummy then
+ Personen[I].Ende:=Personen[I].Ereignisse[eaBeerdigung]
+ else Personen[I].Ende:=dummyEreignis;
+ Personen[I].P1:=-1;
+ Personen[I].P2:=-1;
+ Personen[I].P3:=-1;
+ end;
+ printStatus(1);
+ timeout:=now+1/24/60/60*3;
+ repeat
+ gefunden:=false;
+ for I:=0 to length(Personen)-1 do // Todesdatum aus Geburtsdatum
+ if Personen[i].Ende.istDummy and
+ not Personen[i].Anfang.istDummy then begin
+ setlength(Ereignisse,length(Ereignisse)+1);
+ Ereignisse[length(Ereignisse)-1]:=tEreignis.create;
+ Ereignisse[length(Ereignisse)-1].Art:=eaSonstiges;
+ Ereignisse[length(Ereignisse)-1].Jahr:=min(Personen[I].Anfang.Jahr+StandardLebensdauer,aktuellesJahr);
+ Ereignisse[length(Ereignisse)-1].ID:=Personen[I].ID+'_automatischer_Tod';
+ Personen[I].Ende:=Ereignisse[length(Ereignisse)-1];
+ gefunden:=true;
+ end;
+ if gefunden then continue;
+ for I:=0 to length(Familien)-1 do // Hochzeitsdatum aus Geburtsdatum der Kinder
+ if Familien[I].Anfang.istDummy and (not gefunden) and
+ (length(Familien[I].Kinder)>0) then
+ for J:=0 to length(Familien[I].Kinder)-1 do
+ if (not Familien[I].Kinder[J].Anfang.istDummy) and
+ (Familien[I].Anfang.istDummy or
+ (Familien[I].Kinder[J].Anfang.Jahr<=Familien[I].Anfang.Jahr)) then begin
+ Familien[I].Anfang:=Familien[I].Kinder[J].Anfang;
+ gefunden:=true;
+ end;
+ if gefunden then continue;
+ for I:=0 to length(Familien)-1 do // Hochzeitsdatum aus Geburtsdatum der Eltern
+ if Familien[I].Anfang.istDummy and not gefunden then begin
+ for J:=0 to 1 do
+ if assigned(Familien[I].Eltern[J]) and (not Familien[I].Eltern[J].Anfang.istDummy) and
+ (Familien[I].Anfang.istDummy or (Familien[I].Eltern[J].Anfang.Jahr>=Familien[I].Anfang.Jahr)) then begin
+ Familien[I].Anfang:=Familien[I].Eltern[J].Anfang;
+ gefunden:=true;
+ end;
+ if gefunden then begin
+ setlength(Ereignisse,length(Ereignisse)+1);
+ Ereignisse[length(Ereignisse)-1]:=tEreignis.create;
+ Ereignisse[length(Ereignisse)-1].ID:=Familien[i].ID+'_automatische_Hochzeit';
+ Ereignisse[length(Ereignisse)-1].Jahr:=min(Familien[i].Anfang.Jahr+StandardHochzeitsalter,aktuellesJahr);
+ Ereignisse[length(Ereignisse)-1].Art:=eaSonstiges;
+ Familien[i].Anfang:=Ereignisse[length(Ereignisse)-1];
+ break;
+ end;
+ end;
+ if gefunden then continue;
+ for I:=0 to length(Personen)-1 do // Geburtsdatum aus Hochzeitsdatum der Eltern
+ if Personen[I].Anfang.istDummy and
+ assigned(Personen[I].KindIn) and
+ not Personen[I].KindIn.Anfang.istDummy then begin
+ Personen[I].Anfang:=Personen[I].KindIn.Anfang;
+ gefunden:=true;
+ break;
+ end;
+ if gefunden then continue;
+ for I:=0 to length(Personen)-1 do // Geburtsdatum aus eigenen Hochzeitsdaten
+ if Personen[I].Anfang.istDummy then begin
+ for J:=0 to length(Personen[I].ElterIn)-1 do
+ if (not Personen[I].ElterIn[J].Anfang.istDummy) and
+ (Personen[I].Anfang.istDummy or
+ (Personen[I].Anfang.Jahr > Personen[I].ElterIn[J].Anfang.Jahr)) then
+ Personen[I].Anfang:=Personen[I].ElterIn[J].Anfang;
+ if not Personen[I].Anfang.istDummy then begin
+ setlength(Ereignisse,length(Ereignisse)+1);
+ Ereignisse[length(Ereignisse)-1]:=TEreignis.create;
+ Ereignisse[length(Ereignisse)-1].Art:=eaSonstiges;
+ Ereignisse[length(Ereignisse)-1].Jahr:=Personen[I].Anfang.Jahr-Standardhochzeitsalter;
+ Ereignisse[length(Ereignisse)-1].ID:=Personen[I].ID+'_automatische_Geburt';
+ Personen[I].Anfang:=Ereignisse[length(Ereignisse)-1];
+ gefunden:=true;
+ break;
+ end;
+ end;
+ if gefunden then continue;
+ for I:=0 to length(Personen)-1 do // Geburtsdatum aus Todesdatum
+ if Personen[I].Anfang.istDummy and
+ not Personen[I].Ende.istDummy then begin
+ setlength(Ereignisse,length(Ereignisse)+1);
+ Ereignisse[length(Ereignisse)-1]:=tEreignis.create;
+ Ereignisse[length(Ereignisse)-1].Art:=eaSonstiges;
+ Ereignisse[length(Ereignisse)-1].Jahr:=Personen[I].Ende.Jahr-StandardLebensdauer;
+ Ereignisse[length(Ereignisse)-1].ID:=Personen[I].ID+'_automatische_Geburt';
+ Personen[I].Anfang:=Ereignisse[length(Ereignisse)-1];
+ gefunden:=true;
+ break;
+ end;
+ until (not gefunden) or (now>=timeout);
+ if gefunden then begin
+ writeln('Zeitüberschreitung erreicht!');
+ halt(1);
+ end;
+
+ gefunden:=false;
+ for i:=0 to length(Personen)-1 do
+ if Personen[i].Anfang.istDummy or Personen[i].Ende.istDummy then begin
+ gefunden:=true;
+ write('*** Warnung *** Dummy gefunden! (');
+ if Personen[i].Anfang.istDummy then write('Geburt');
+ if Personen[i].Ende.istDummy then begin
+ if Personen[i].Anfang.istDummy then write(', ');
+ write('Tod');
+ end;
+ writeln(') '+Personen[i].ID+' '+Personen[i].Vorname+' '+Personen[i].Nachname);
+ if assigned(Personen[i].KindIn) then
+ writeln(' '+inttostr(byte(Personen[i].KindIn.Anfang.istDummy))+' '+inttostr(integer(Personen[i].KindIn.Anfang.Art))+' '+inttostr(Personen[i].KindIn.Anfang.Jahr));
+ writeln(' '+inttostr(length(Personen[i].ElterIn)));
+ for j:=0 to length(Personen[i].ElterIn)-1 do
+ writeln(' '+inttostr(byte(Personen[i].ElterIn[j].Anfang.istDummy))+' '+inttostr(integer(Personen[i].ElterIn[j].Anfang.Art))+' '+inttostr(Personen[i].ElterIn[j].Anfang.Jahr));
+ end;
+ for i:=0 to length(Familien)-1 do
+ if Familien[i].Anfang.istDummy then begin
+ gefunden:=true;
+ writeln('*** Warnung *** Dummy gefunden! (Hochzeit) '+Familien[i].ID);
+ if assigned(Familien[i].Eltern[0]) then writeln(' E '+inttostr(byte(Familien[i].Eltern[0].Anfang.istDummy))+' '+Familien[i].Eltern[0].Vorname+' '+Familien[i].Eltern[0].Nachname);
+ if assigned(Familien[i].Eltern[1]) then writeln(' E '+inttostr(byte(Familien[i].Eltern[0].Anfang.istDummy))+' '+Familien[i].Eltern[1].Vorname+' "'+Familien[i].Eltern[1].Nachname+'"');
+ for j:=0 to length(Familien[i].Kinder)-1 do
+ writeln(' '+inttostr(byte(Familien[i].Kinder[j].Anfang.istDummy))+' '+Familien[i].Kinder[j].Vorname+' '+Familien[i].Kinder[j].Nachname);
+ end;
+
+ if gefunden then halt(1);
+
+ for I:=0 to length(Personen)-1 do
+ if assigned(Personen[I].KindIn) and
+ (Personen[I].KindIn.Anfang.Jahr > Personen[I].Anfang.Jahr) then
+ Personen[I].KindIn.Anfang:=Personen[I].Anfang;
+
+ indizesErzeugen;
+ writeln('... fertig');
+end;
+
+function TMetaData.analysiereInteraktionen: boolean;
+var
+ i,j,k,l: longint;
+ speichern,
+ gefunden: boolean;
+ c: char;
+ Ps: tIntArray;
+ p: tPerson;
+begin
+ writeln('Verknüpfungen und Interaktionen analysieren ...');
+ ParameterLaenge:=0;
+ setlength(Verknuepfungen,0);
+ setlength(MMInteraktionen,0);
+ Setlength(MFInteraktionen,0);
+ setlength(FFInteraktionen,0);
+ setlength(ParameterAttribute,0);
+ for I:=0 to length(Personen)-1 do begin
+ if assigned(Personen[I].KindIn) then begin
+ Personen[I].P3:=ParameterLaenge;
+ if ParameterLaenge>=length(ParameterAttribute) then
+ setlength(ParameterAttribute,ParameterLaenge+1024);
+ ParameterAttribute[ParameterLaenge].istKoordinate:=false;
+ ParameterAttribute[ParameterLaenge].istUnabhaengig:=true;
+ inc(ParameterLaenge);
+ end
+ else begin
+ Personen[I].P1:=ParameterLaenge;
+ Personen[I].P2:=ParameterLaenge+1;
+ if ParameterLaenge>=length(ParameterAttribute)-1 then
+ setlength(ParameterAttribute,ParameterLaenge+1024);
+ ParameterAttribute[ParameterLaenge].istKoordinate:=true;
+ ParameterAttribute[ParameterLaenge].istUnabhaengig:=true;
+ ParameterAttribute[ParameterLaenge+1].istKoordinate:=true;
+ ParameterAttribute[ParameterLaenge+1].istUnabhaengig:=true;
+ ParameterLaenge:=ParameterLaenge+2;
+ end;
+ end;
+
+ repeat
+ gefunden:=false;
+ for I:=0 to length(Personen)-1 do
+ if (Personen[i].P1=-1) and
+ (Personen[i].KindIn.Eltern[0].P1<>-1) and
+ (Personen[i].KindIn.Eltern[1].P1<>-1) then begin
+ Setlength(Verknuepfungen,length(Verknuepfungen)+1);
+ Verknuepfungen[length(Verknuepfungen)-1]:=tVerknuepfung.create;
+ Verknuepfungen[length(Verknuepfungen)-1].outP:=Personen[I];
+ Verknuepfungen[length(Verknuepfungen)-1].Lambda:=Personen[I].P3;
+ for J:=0 to 1 do begin
+ Verknuepfungen[length(Verknuepfungen)-1].Input[J,'x']:=
+ Personen[I].KindIn.Eltern[J].P1;
+ Verknuepfungen[length(Verknuepfungen)-1].Input[J,'y']:=
+ Personen[I].KindIn.Eltern[J].P2;
+ end;
+ if ParameterLaenge>=length(ParameterAttribute)-1 then
+ setlength(ParameterAttribute,ParameterLaenge+1024);
+ ParameterAttribute[ParameterLaenge].istKoordinate:=true;
+ ParameterAttribute[ParameterLaenge].istUnabhaengig:=false;
+ ParameterAttribute[ParameterLaenge+1].istKoordinate:=true;
+ ParameterAttribute[ParameterLaenge+1].istUnabhaengig:=false;
+ Personen[i].P1:=ParameterLaenge;
+ Personen[i].P2:=ParameterLaenge+1;
+ ParameterLaenge:=ParameterLaenge+2;
+ Verknuepfungen[length(Verknuepfungen)-1].Output['x']:=Personen[I].P1;
+ Verknuepfungen[length(Verknuepfungen)-1].Output['y']:=Personen[I].P2;
+ gefunden:=true;
+ end;
+ until not gefunden;
+
+ setlength(ParameterAttribute,ParameterLaenge);
+
+ gefunden:=false;
+ for i:=0 to length(Personen)-1 do
+ if Personen[i].P1=-1 then begin
+ writeln(inttostr(i)+' '+Personen[i].Vorname+' '+Personen[i].Nachname);
+ gefunden:=true;
+ end;
+ if gefunden then begin
+ result:=false;
+ exit;
+ end;
+
+ setlength(Ps,ParameterLaenge);
+ for J:=0 to length(Ps)-1 do begin
+ ParameterAttribute[j].wirdBenutzt:=true;
+ Ps[J]:=Byte(ParameterAttribute[j].istUnabhaengig);
+ end;
+ for I:=0 to length(Verknuepfungen)-1 do begin
+ for J:=I to length(Verknuepfungen)-1 do begin
+ speichern:=Ps[Verknuepfungen[J].Lambda]=1;
+ for K:=0 to 1 do
+ for C:='x' to 'y' do
+ speichern:=speichern and
+ (Ps[Verknuepfungen[J].Input[K,C]]=1);
+ for C:='x' to 'y' do
+ speichern:=speichern and
+ (Ps[Verknuepfungen[J].Output[C]]=0);
+ if speichern then begin
+ for K:=0 to 1 do begin
+ for C:='x' to 'y' do begin
+ L:=Verknuepfungen[J].Input[K,C];
+ Verknuepfungen[J].Input[K,C]:=Verknuepfungen[I].Input[K,C];
+ Verknuepfungen[I].Input[K,C]:=L;
+ end;
+ end;
+ p:=Verknuepfungen[J].outP;
+ Verknuepfungen[J].outP:=Verknuepfungen[I].outP;
+ Verknuepfungen[I].outP:=p;
+ for C:='x' to 'y' do begin
+ L:=Verknuepfungen[J].Output[C];
+ Verknuepfungen[J].Output[C]:=Verknuepfungen[I].Output[C];
+ Verknuepfungen[I].Output[C]:=L;
+ end;
+ L:=Verknuepfungen[J].Lambda;
+ Verknuepfungen[J].Lambda:=Verknuepfungen[I].Lambda;
+ Verknuepfungen[I].Lambda:=L;
+ for C:='x' to 'y' do
+ Ps[Verknuepfungen[I].Output[C]]:=1;
+ break;
+ end;
+ end;
+ if not speichern then begin
+ writeln('Warnung: Keine berechenbare Verknüpfung gefunden!: I=',I);
+ result:=false;
+ exit;
+ end;
+ end;
+ for I:=0 to length(Ps)-1 do
+ if Ps[I]<>1 then
+ begin
+ writeln('Warnung: Nicht alle Parameter wurden berechnet! ',I);
+ result:=false;
+ exit;
+ end;
+ setlength(Ps,0);
+ for I:=0 to length(Personen)-1 do
+ for J:=0 to I-1 do begin
+ K:=min(
+ Personen[I].Ende.Jahr-Personen[J].Anfang.Jahr,
+ Personen[J].Ende.Jahr-Personen[I].Anfang.Jahr)+1+Zusatzueberlapp;
+ if K>0 then begin
+ setlength(MMInteraktionen,length(MMInteraktionen)+1);
+ MMInteraktionen[length(MMInteraktionen)-1]:=tMMInteraktion.create;
+ MMInteraktionen[length(MMInteraktionen)-1].Laenge:=min(K,Ueberlappcutoff);
+ MMInteraktionen[length(MMInteraktionen)-1]._Ps[0]:=Personen[I];
+ MMInteraktionen[length(MMInteraktionen)-1]._Ps[1]:=Personen[J];
+ MMInteraktionen[length(MMInteraktionen)-1].index:=length(MMInteraktionen)-1;
+ end;
+ end;
+ for I:=0 to length(Personen)-1 do
+ for J:=0 to length(Familien)-1 do begin
+ speichern:=Personen[I].KindIn<>Familien[J];
+ for K:=0 to length(Personen[I].ElterIn)-1 do
+ speichern:=speichern and (Personen[I].ElterIn[K]<>Familien[J]);
+ if speichern then begin
+ K:=min(
+ Familien[J].Anfang.Jahr-Personen[I].Anfang.Jahr,
+ Personen[I].Ende.Jahr-Familien[J].Anfang.Jahr)+1+Jahrestoleranz;
+ if K>0 then begin
+ setlength(MFInteraktionen,length(MFInteraktionen)+1);
+ MFInteraktionen[length(MFInteraktionen)-1]:=tMFInteraktion.create;
+ MFInteraktionen[length(MFInteraktionen)-1].Laenge:=min(K,Ueberlappcutoff);
+ MFInteraktionen[length(MFInteraktionen)-1]._P:=Personen[I];
+ MFInteraktionen[length(MFInteraktionen)-1]._F:=Familien[J];
+ MFInteraktionen[length(MFInteraktionen)-1].index:=length(MFInteraktionen)-1;
+ end;
+ end;
+ end;
+ for I:=0 to length(Familien)-1 do
+ for J:=0 to I-1 do begin
+ speichern:=true;
+ for K:=0 to 1 do
+ for L:=0 to 1 do
+ speichern:=speichern and
+ (Familien[I].Eltern[K]<>Familien[J].Eltern[L]);
+ K:=Jahrestoleranz+1-abs(Familien[I].Anfang.Jahr-Familien[J].Anfang.Jahr);
+ if (K>0) and speichern then begin
+ setlength(FFInteraktionen,length(FFInteraktionen)+1);
+ FFInteraktionen[length(FFInteraktionen)-1]:=tFFInteraktion.create;
+ FFInteraktionen[length(FFInteraktionen)-1]._Fs[0]:=Familien[I];
+ FFInteraktionen[length(FFInteraktionen)-1]._Fs[1]:=Familien[J];
+ FFInteraktionen[length(FFInteraktionen)-1].index:=length(FFInteraktionen)-1;
+ end;
+ end;
+ setlength(Tauschfamilien,0);
+ for I:=0 to length(Familien)-1 do
+ if length(Familien[I].Kinder)>=2 then begin
+ setlength(Tauschfamilien,length(Tauschfamilien)+1);
+ Tauschfamilien[length(Tauschfamilien)-1]:=Familien[I];
+ end;
+ if assigned(Sicherung) then begin
+ writeln('... und noch die der Sicherung');
+ result:=Sicherung.analysiereInteraktionen;
+ end
+ else begin
+ writeln('... fertig');
+ result:=true;
+ end;
+end;
+
+function tMetaData.findeKreise: tPointArrayArray; // x: Person, y: Familie
+var Graph: tGraph; // Ecke.x=0 ... Person; Ecke.x=1 ... Familie; Ecke.y=Index;
+ i,j,n: longint;
+ Kreise: tIntArrayArray;
+begin
+ setlength(result,0);
+ Graph:=tGraph.create;
+ setlength(Graph.Ecken,length(Personen)+length(Familien));
+ n:=0;
+ for i:=0 to length(Personen)-1 do begin
+ Graph.Ecken[i].x:=0;
+ Graph.Ecken[i].y:=i;
+ end;
+ for i:=0 to length(Familien)-1 do begin
+ Graph.Ecken[i+length(Personen)].x:=1;
+ Graph.Ecken[i+length(Personen)].y:=i;
+ n:=n+2+length(Familien[i].Kinder);
+ end;
+ setlength(Graph.Kanten,n);
+ n:=0;
+ for i:=0 to length(Familien)-1 do begin
+ for j:=0 to 1 do begin
+ Graph.Kanten[n].x:=i+length(Personen); // die Familie
+ Graph.Kanten[n].y:=Familien[i].Eltern[j].Index; // der Elter
+ inc(n);
+ end;
+ for j:=0 to length(Familien[i].Kinder)-1 do begin
+ Graph.Kanten[n].x:=i+length(Personen); // die Familie
+ Graph.Kanten[n].y:=Familien[i].Kinder[j].Index; // das Kind
+ inc(n);
+ end;
+ end;
+ Kreise:=Graph.findeKreise;
+ setlength(result,length(Kreise));
+ for i:=0 to length(result)-1 do begin
+ setlength(result[i],length(Kreise[i]));
+ for j:=0 to length(Kreise[i])-1 do
+ if Graph.Ecken[Graph.Kanten[Kreise[i,j]].x].x = 0 then begin
+ result[i,j].x:=Graph.Ecken[Graph.Kanten[Kreise[i,j]].x].y;
+ result[i,j].y:=Graph.Ecken[Graph.Kanten[Kreise[i,j]].y].y;
+ end
+ else if Graph.Ecken[Graph.Kanten[Kreise[i,j]].y].x = 0 then begin
+ result[i,j].x:=Graph.Ecken[Graph.Kanten[Kreise[i,j]].y].y;
+ result[i,j].y:=Graph.Ecken[Graph.Kanten[Kreise[i,j]].x].y;
+ end
+ else writeln('Kein Ende der Kante ist eine Person!');
+ end;
+end;
+
+procedure tMetaData.blaetterAbschneiden;
+var
+ i,j,k,cnt: longint;
+ gefunden: boolean;
+begin
+ if assigned(sicherung) or (length(Laubhaufen)<>0) then begin
+ writeln('*** Warnung ***');
+ writeln('Hier waren schon Blätter gesichert, die ich jetzt vernichte.');
+ sicherung.free;
+ setlength(Laubhaufen,0);
+ end;
+
+ sicherung:=tMetaData.create;
+ sicherung.init(self);
+ sicherung.indizesErzeugen;
+
+ for i:=0 to length(ParameterAttribute)-1 do
+ ParameterAttribute[i].wirdBenutzt:=true;
+
+ cnt:=0;
+
+ konsistenzTest(true);
+
+ repeat
+ gefunden:=false;
+ for i:=length(Personen)-1 downto 0 do // Personen entfernen, die keine Eltern (mehr) sind
+ if length(Personen[i].elterIn) = 0 then begin
+ if cnt>=length(Laubhaufen) then
+ setlength(Laubhaufen,length(Laubhaufen)+1024);
+ Laubhaufen[cnt]:=findePerson(sicherung.Personen,pPersonToStr(Personen[i])); // Person sichern
+ sicherung.habePersonGeloescht(Laubhaufen[cnt] as tPerson);
+ inc(cnt);
+
+ loescheAlleVerbindungenZu(Personen[i],nil);
+
+ ParameterAttribute[Personen[i].p1].setzeBenutzt(false); // x,
+ ParameterAttribute[Personen[i].p2].setzeBenutzt(false); // y
+ if assigned(Personen[i].KindIn) then // und ggf.
+ ParameterAttribute[Personen[i].p3].setzeBenutzt(false); // Lambda unbenutzen
+
+ loeschePerson(Personen,pPersonToStr(Personen[i])); // Person löschen
+ gefunden:=true;
+ end;
+
+ for i:=length(Familien)-1 downto 0 do // Familien entfernen, die nur noch höchstens ein relevantes Mitglied haben
+ if byte(assigned(Familien[i].Eltern[0]) and (Familien[i].Eltern[0].anzahlVerbindungen>1)) + // Eltern brauchen mehr als die Verbindung zu
+ byte(assigned(Familien[i].Eltern[1]) and (Familien[i].Eltern[1].anzahlVerbindungen>1)) + // dieser Familie um relevant zu sein,
+ length(Familien[i].Kinder) <= 1 then begin // Kinder müssen dagegen lediglich vorhanden sein
+ if cnt>=length(Laubhaufen) then
+ setlength(Laubhaufen,length(Laubhaufen)+1024);
+ Laubhaufen[cnt]:=findeFamilie(sicherung.Familien,pFamilieToStr(Familien[i])); // Familie sichern
+ sicherung.habeFamilieGeloescht(Laubhaufen[cnt] as tFamilie);
+ inc(cnt);
+
+ for j:=length(Tauschfamilien)-1 downto 0 do
+ if Tauschfamilien[j]=Familien[i] then begin // Familie aus Tauschfamilien löschen
+ for k:=j+1 to length(Tauschfamilien)-1 do
+ Tauschfamilien[k-1]:=Tauschfamilien[k];
+ setlength(Tauschfamilien,length(Tauschfamilien)-1);
+ end;
+
+ for j:=0 to 1 do
+ if assigned(Familien[i].Eltern[j]) and
+ (Familien[i].Eltern[j].anzahlVerbindungen<=1) then begin // irrelevanter Elter
+ sicherung.habePersonGeloescht(findePerson(sicherung.Personen,pPersonToStr(Familien[i].Eltern[j]),false));
+ ParameterAttribute[Familien[i].Eltern[j].p1].setzeBenutzt(false); // x,
+ ParameterAttribute[Familien[i].Eltern[j].p2].setzeBenutzt(false); // y unbenutzen
+
+ loescheAlleVerbindungenZu(Familien[i].Eltern[j],nil);
+ loeschePerson(Personen,pPersonToStr(Familien[i].Eltern[j])); // Elter löschen
+ end;
+
+ // Kinder können per definitionem nicht irrelevant sein, daher muss man auch keine löschen
+
+ if length(Familien[i].Kinder)=1 then begin
+ loescheVerknuepfungenZu(Familien[i].Kinder[0]);
+ ParameterAttribute[Familien[i].Kinder[0].p3].setzeBenutzt(false); // Lambda unbenutzen
+ ParameterAttribute[Familien[i].Kinder[0].p1].setzeUnabhaengig(true); // x,
+ ParameterAttribute[Familien[i].Kinder[0].p2].setzeUnabhaengig(true); // y befreien
+ end;
+
+ loescheAlleVerbindungenZu(nil,Familien[i]);
+
+ loescheFamilie(Familien,pFamilieToStr(Familien[i])); // Familie löschen
+ gefunden:=true;
+ end;
+ until not gefunden;
+ setlength(Laubhaufen,cnt);
+ arraysAufraeumen;
+end;
+
+procedure tMetaData.letztesBlattWiederAnkleben(out vkn: tVerknuepfung; out p: tPerson);
+var
+ i,j: longint;
+ gefunden: boolean;
+ sp1,sp2: tPerson;
+ sf: tFamilie;
+begin
+ if (not assigned(sicherung)) or (length(Laubhaufen)=0) then begin
+ writeln('*** Fehler ***');
+ writeln('Ich habe keine Blätter mehr übrig.');
+ halt;
+ end;
+
+ p:=nil;
+ sp1:=nil;
+ sp2:=nil;
+ sf:=nil;
+ vkn:=nil;
+
+ if Laubhaufen[length(Laubhaufen)-1] is tPerson then begin // diese Person ist (zur Zeit) nur ein Kind und kann einfach eingefügt werden
+ write('k');
+ setlength(Personen,length(Personen)+1);
+ Personen[length(Personen)-1]:=tPerson.create;
+ Personen[length(Personen)-1].init(Laubhaufen[length(Laubhaufen)-1],Ereignisse,Familien,false); // Person wird kopiert, aber zugehörige Familien werden nicht auch noch erzeugt!
+ sicherung.habePersonHinzugefuegt(Laubhaufen[length(Laubhaufen)-1] as tPerson);
+ sp1:=Laubhaufen[length(Laubhaufen)-1] as tPerson;
+ Personen[length(Personen)-1].index:=length(Personen)-1;
+ p:=Personen[length(Personen)-1];
+ Parameterattribute[p.p1].setzeBenutzt(true);
+ Parameterattribute[p.p2].setzeBenutzt(true);
+
+ if not (assigned(p.KindIn) and assigned(p.KindIn.Eltern[0]) and assigned(p.KindIn.Eltern[1])) then begin
+ writeln('*** Fehler ***');
+ writeln('Als Kind einzufügende Person hat hier nicht beide Eltern!');
+ halt;
+ end;
+
+ gefunden:=false;
+ for i:=0 to length(sicherung.Verknuepfungen)-1 do
+ if sicherung.Verknuepfungen[i].outP=Laubhaufen[length(Laubhaufen)-1] then begin
+ if gefunden then begin
+ writeln('*** Fehler ***');
+ writeln('Als Kind einzufügende Person wird durch mehr als eine Verknüpfung berechnet!');
+ halt;
+ end;
+ setlength(Verknuepfungen,length(Verknuepfungen)+1); // die neue Verknuepfung wird einfach hinten angestellt
+ Verknuepfungen[length(Verknuepfungen)-1]:=strToTVerknuepfung(Personen,tVerknuepfungToStr(sicherung.Verknuepfungen[i]));
+ Verknuepfungen[length(Verknuepfungen)-1].index:=length(Verknuepfungen)-1;
+ vkn:=Verknuepfungen[length(Verknuepfungen)-1];
+ Parameterattribute[vkn.Lambda].setzeBenutzt(true);
+ gefunden:=true;
+ end;
+ if not gefunden then begin
+ writeln('*** Fehler ***');
+ writeln('Als Kind einzufügende Person wird durch keine Verknüpfung berechnet!');
+ halt;
+ end;
+ setlength(Laubhaufen,length(Laubhaufen)-1);
+ end
+ else if Laubhaufen[length(Laubhaufen)-1] is tFamilie then begin // Familie inkl. Elter(n) einfügen (keine neuen Kinder!)
+ write('f');
+ j:=-1;
+ for i:=0 to 1 do
+ if findePerson(Personen,pPersonToStr((Laubhaufen[length(Laubhaufen)-1] as tFamilie).Eltern[i]),false)<>nil then begin
+ if j<>-1 then begin
+ writeln('*** Fehler ***');
+ writeln('Beide Eltern der neuen Familie waren schon vorhanden!');
+ halt;
+ end;
+ j:=i;
+ end;
+ for i:=0 to 1 do
+ if i<>j then begin
+ setlength(Personen,length(Personen)+1);
+ Personen[length(Personen)-1]:=tPerson.create;
+ Personen[length(Personen)-1].init((Laubhaufen[length(Laubhaufen)-1] as tFamilie).Eltern[i],Ereignisse,Familien,false); // neuer Elter wird kopiert, aber zugehörige Familien werden nicht auch noch erzeugt!
+ Personen[length(Personen)-1].index:=length(Personen)-1;
+ sicherung.habePersonHinzugefuegt((Laubhaufen[length(Laubhaufen)-1] as tFamilie).Eltern[i]);
+ sp2:=sp1;
+ p:=Personen[length(Personen)-1];
+ sp1:=(Laubhaufen[length(Laubhaufen)-1] as tFamilie).Eltern[i];
+ Parameterattribute[p.p1].setzeBenutzt(true);
+ Parameterattribute[p.p2].setzeBenutzt(true);
+ end;
+
+ setlength(Familien,length(Familien)+1);
+ Familien[length(Familien)-1]:=tFamilie.create;
+ Familien[length(Familien)-1].init(Laubhaufen[length(Laubhaufen)-1],Ereignisse,Personen,false); // Familie wird kopiert, aber Angehörige (insbesondere die Kinder) werden nicht auch noch erzeugt!
+ Familien[length(Familien)-1].index:=length(Familien)-1;
+ sf:=Laubhaufen[length(Laubhaufen)-1] as tFamilie;
+ sicherung.habeFamilieHinzugefuegt(sf);
+
+ if (j<>-1) and (length(Familien[length(Familien)-1].Kinder)<>0) then begin
+ writeln('*** Fehler ***');
+ writeln('Die neu eingefügte Familie hat schon ein Elter und ein Kind!');
+ halt;
+ end;
+ if (j=-1) and (length(Familien[length(Familien)-1].Kinder)<>1) then begin
+ writeln('*** Fehler ***');
+ writeln('Die neu eingefügte Familie hat noch kein Kind obwohl beide Eltern neu sind!');
+ halt;
+ end;
+
+ for i:=0 to length(sicherung.Tauschfamilien)-1 do
+ if sicherung.Tauschfamilien[i]=Laubhaufen[length(Laubhaufen)-1] then begin // Tauschfamilie rücksichern
+ setlength(Tauschfamilien,length(Tauschfamilien)+1);
+ Tauschfamilien[length(Tauschfamilien)-1]:=Familien[length(Familien)-1];
+ end;
+
+ if j=-1 then begin // beide Eltern sind neu, dann wird auch die Verknüpfung zurückgesichert!
+ write('E');
+ gefunden:=false;
+ for i:=0 to length(sicherung.Verknuepfungen)-1 do
+ if (sicherung.Verknuepfungen[i].outP.KindIn=Laubhaufen[length(Laubhaufen)-1]) and // die Verknüpfung bezieht sich auf die Familie
+ sicherung.istPersonAuchDrueber(sicherung.Verknuepfungen[i].outP) then begin // und das berechnete Kind ist schon zurückgesichert
+ if gefunden then begin
+ writeln('*** Fehler ***');
+ writeln('Die neue Familie bringt mehr als eine Verknüpfung mit!');
+ halt;
+ end;
+
+ setlength(Verknuepfungen,length(Verknuepfungen)+1); // die neue Verknuepfung wird einfach vorne angestellt
+ for j:=length(Verknuepfungen)-1 downto 1 do begin
+ Verknuepfungen[j]:=Verknuepfungen[j-1];
+ Verknuepfungen[j].index:=j;
+ end;
+ Verknuepfungen[0]:=strToTVerknuepfung(Personen,tVerknuepfungToStr(sicherung.Verknuepfungen[i]));
+ Verknuepfungen[0].index:=0;
+ vkn:=Verknuepfungen[0];
+ Parameterattribute[vkn.Lambda].setzeBenutzt(true);
+ ParameterAttribute[vkn.Output['x']].setzeUnabhaengig(false); // x,
+ ParameterAttribute[vkn.Output['y']].setzeUnabhaengig(false); // y abhängig machen
+ // Die restlichen Parameter werden als benutzt markiert, wenn die entsprechenden Personen eingefügt werden.
+
+ gefunden:=true;
+ end;
+ if not gefunden then begin
+ writeln('*** Fehler ***');
+ writeln('Beide Eltern sind neu, aber es gibt keine passende Verknüpfung!');
+ halt;
+ end;
+ p:=nil;
+
+ j:=-1;
+ end;
+
+ setlength(Laubhaufen,length(Laubhaufen)-1);
+ end
+ else begin
+ writeln('*** Fehler ***');
+ writeln('Das wieder einzufügende Blatt ist weder eine Person noch eine Familie!');
+ halt;
+ end;
+
+ if assigned(sp1) then begin
+ for i:=0 to length(sp1.inMMInteraktion)-1 do
+ if sicherung.istPersonAuchDrueber(sp1.inMMInteraktion[i]._Ps[0]) and // beide Personen sind
+ sicherung.istPersonAuchDrueber(sp1.inMMInteraktion[i]._Ps[1]) then begin // auch hier vorhanden
+ setlength(MMInteraktionen,length(MMInteraktionen)+1);
+ MMInteraktionen[length(MMInteraktionen)-1]:=ImportMMInteraktion(Personen,tMMInteraktionToStr(sp1.inMMInteraktion[i])); // Interaktion erzeugen
+ end;
+ for i:=0 to length(sp1.inMFInteraktion)-1 do
+ if sicherung.istFamilieAuchDrueber(sp1.inMFInteraktion[i]._F) then begin // Familie hier vorhanden
+ setlength(MFInteraktionen,length(MFInteraktionen)+1);
+ MFInteraktionen[length(MFInteraktionen)-1]:=ImportMFInteraktion(Personen,Familien,tMFInteraktionToStr(sp1.inMFInteraktion[i]));
+ end;
+ end;
+
+ if assigned(sp2) and (sp1<>sp2) then begin
+ for i:=0 to length(sp2.inMMInteraktion)-1 do
+ if sicherung.istPersonAuchDrueber(sp2.inMMInteraktion[i]._Ps[0]) and // beide Personen sind
+ sicherung.istPersonAuchDrueber(sp2.inMMInteraktion[i]._Ps[1]) and // auch hier vorhanden und
+ (sp2.inMMInteraktion[i]._Ps[0]<>sp1) and // beide Personen sind
+ (sp2.inMMInteraktion[i]._Ps[1]<>sp1) then begin // nicht sp1 (sonst wurde die MMInteraktion oben schon rückgesichert)
+ setlength(MMInteraktionen,length(MMInteraktionen)+1);
+ MMInteraktionen[length(MMInteraktionen)-1]:=ImportMMInteraktion(Personen,tMMInteraktionToStr(sp2.inMMInteraktion[i])); // Interaktion erzeugen
+ end;
+ for i:=0 to length(sp2.inMFInteraktion)-1 do
+ if sicherung.istFamilieAuchDrueber(sp2.inMFInteraktion[i]._F) then begin // Familie hier vorhanden
+ setlength(MFInteraktionen,length(MFInteraktionen)+1);
+ MFInteraktionen[length(MFInteraktionen)-1]:=ImportMFInteraktion(Personen,Familien,tMFInteraktionToStr(sp2.inMFInteraktion[i]));
+ end;
+ end;
+
+ if assigned(sf) then begin
+ for i:=0 to length(sf.inMFInteraktion)-1 do
+ if sicherung.istPersonAuchDrueber(sf.inMFInteraktion[i]._P) and // Familie hier vorhanden
+ (sf.inMFInteraktion[i]._P<>sp1) and // und Person weder sp1
+ (sf.inMFInteraktion[i]._P<>sp2) then begin // noch sp2 (sonst wurde die MFInteraktion oben schon rückgesichert)
+ setlength(MFInteraktionen,length(MFInteraktionen)+1);
+ MFInteraktionen[length(MFInteraktionen)-1]:=ImportMFInteraktion(Personen,Familien,tMFInteraktionToStr(sf.inMFInteraktion[i]));
+ end;
+ for i:=0 to length(sf.inFFInteraktion)-1 do
+ if sicherung.istFamilieAuchDrueber(sf.inFFInteraktion[i]._Fs[0]) and // beide Familienda sind
+ sicherung.istFamilieAuchDrueber(sf.inFFInteraktion[i]._Fs[1]) then begin // auch hier vorhanden
+ setlength(FFInteraktionen,length(FFInteraktionen)+1);
+ FFInteraktionen[length(FFInteraktionen)-1]:=ImportFFInteraktion(Familien,tFFInteraktionToStr(sf.inFFInteraktion[i]));
+ end;
+ end;
+
+ if length(Laubhaufen)=0 then begin
+ pruefeAufGleichheit(sicherung);
+ sicherung.free;
+ sicherung:=nil;
+ end;
+end;
+
+procedure tMetaData.nurGroeszteZusammenhangskomponente;
+var
+ i,j,k,l: longint;
+ zhks: array of tZusammenhangskomponente;
+ gefunden: boolean;
+begin
+ setlength(Zhks,0);
+ for i:=0 to length(Personen)-1 do begin
+ k:=-1;
+ j:=0;
+ while j<length(Zhks) do begin
+ if Zhks[j].grenztAn(Personen[i]) then begin
+ if k=-1 then begin
+ k:=j;
+ inc(j);
+ continue;
+ end;
+ Zhks[k].verschmelzeMit(Zhks[j]);
+ Zhks[j].free;
+ for l:=j+1 to length(Zhks)-1 do
+ Zhks[l-1]:=Zhks[l];
+ setlength(Zhks,length(Zhks)-1);
+ end;
+ inc(j);
+ end;
+ if k=-1 then begin
+ setlength(Zhks,length(Zhks)+1);
+ Zhks[length(Zhks)-1]:=tZusammenhangskomponente.create;
+ k:=length(Zhks)-1;
+ end;
+ Zhks[k].UmfeldEinfuegen(Familien,Personen[i]);
+ end;
+ if length(Zhks)=1 then begin
+ Zhks[0].free;
+ setlength(Zhks,0);
+ exit;
+ end;
+ writeln('*** Warnung ***');
+ writeln(inttostr(length(Zhks))+' Zusammenhangskomponenten gefunden. ('+inttostr(length(Familien))+' Familien und '+inttostr(length(Personen))+' Personen)');
+ j:=0;
+ k:=-1;
+ for i:=0 to length(Zhks)-1 do begin
+ write(' '+inttostr(length(Zhks[i].Familien)));
+ if length(Zhks[i].Familien)>j then begin
+ j:=length(Zhks[i].Familien);
+ k:=i;
+ end;
+ end;
+ writeln;
+ writeln('Da nehme ich doch die '+inttostr(k+1)+'. mit '+inttostr(j)+' Familien!');
+ for i:=length(Personen)-1 downto 0 do begin // überflüssige Personen löschen
+ if not Zhks[k].grenztAn(Personen[i]) then begin
+ Personen[i].free;
+ for j:=i+1 to length(Personen)-1 do
+ Personen[j-1]:=Personen[j];
+ setlength(Personen,length(Personen)-1);
+ end;
+ end;
+ for i:=length(Familien)-1 downto 0 do begin
+ gefunden:=false;
+ for j:=0 to length(Zhks[k].Familien)-1 do
+ gefunden:=gefunden or (Zhks[k].Familien[j]=Familien[i]);
+ if not gefunden then begin
+ Familien[i].free;
+ for j:=i+1 to length(Familien)-1 do
+ Familien[j-1]:=Familien[j];
+ setlength(Familien,length(Familien)-1);
+ end;
+ end;
+ writeln(inttostr(length(Personen))+' Personen und '+inttostr(length(Familien))+' Familien sind übrig.');
+ writeln('***');
+ for i:=0 to length(Zhks)-1 do
+ Zhks[i].free;
+ setlength(Zhks,0);
+end;
+
+procedure tMetaData.konsistenzTest(mitIndizes: boolean);
+var
+ i,j,k,anz: longint;
+begin
+ if assigned(sicherung) then begin
+ for i:=0 to length(sicherung.Personen)-1 do
+ if sicherung.istPersonAuchDrueber(sicherung.Personen[i]) xor
+ (findePerson(Personen,pPersonToStr(sicherung.Personen[i]),false)<>nil) then begin
+ write('Person '''+tPersonToStr(sicherung.Personen[i])+''' ist in Sicherung fälschlicherweise als ''');
+ if not sicherung.istPersonAuchDrueber(sicherung.Personen[i]) then
+ write('nicht-');
+ writeln('auchdrüber'' markiert!');
+ halt;
+ end;
+ for i:=0 to length(sicherung.Familien)-1 do
+ if sicherung.istFamilieAuchDrueber(sicherung.Familien[i]) xor
+ (findeFamilie(Familien,pFamilieToStr(sicherung.Familien[i]),false)<>nil) then begin
+ write('Familie '''+tFamilieToStr(sicherung.Familien[i])+''' ist in Sicherung fälschlicherweise als ''');
+ if not sicherung.istFamilieAuchDrueber(sicherung.Familien[i]) then
+ write('nicht-');
+ writeln('auchdrüber'' markiert!');
+ halt;
+ end;
+ end;
+ for i:=0 to length(Verknuepfungen)-1 do begin
+ if mitIndizes and (Verknuepfungen[i].index<>i) then begin
+ writeln('Verknüpfung an Stelle '+inttostr(i)+' hat Index '+inttostr(Verknuepfungen[i].index)+'.');
+ halt;
+ end;
+ if assigned(Verknuepfungen[i].outP) then begin
+ if (Verknuepfungen[i].outP.p1<>Verknuepfungen[i].Output['x']) or
+ (Verknuepfungen[i].outP.p2<>Verknuepfungen[i].Output['y']) or
+ (Verknuepfungen[i].outP.p3<>Verknuepfungen[i].lambda) or
+ (Verknuepfungen[i].outP.KindIn.Eltern[0].p1<>Verknuepfungen[i].Input[0,'x']) or
+ (Verknuepfungen[i].outP.KindIn.Eltern[0].p2<>Verknuepfungen[i].Input[0,'y']) or
+ (Verknuepfungen[i].outP.KindIn.Eltern[1].p1<>Verknuepfungen[i].Input[1,'x']) or
+ (Verknuepfungen[i].outP.KindIn.Eltern[1].p2<>Verknuepfungen[i].Input[1,'y']) then begin
+ writeln('Verknüpfung '''+tVerknuepfungToStr(Verknuepfungen[i])+''' hat inkonsistente Parametereinträge!');
+ halt;
+ end;
+ if (not Parameterattribute[Verknuepfungen[i].outP.p1].wirdBenutzt) or
+ (not Parameterattribute[Verknuepfungen[i].outP.p2].wirdBenutzt) or
+ (not Parameterattribute[Verknuepfungen[i].outP.p3].wirdBenutzt) or
+ (not Parameterattribute[Verknuepfungen[i].outP.p1].istKoordinate) or
+ (not Parameterattribute[Verknuepfungen[i].outP.p2].istKoordinate) or
+ Parameterattribute[Verknuepfungen[i].outP.p3].istKoordinate or
+ Parameterattribute[Verknuepfungen[i].outP.p1].istUnabhaengig or
+ Parameterattribute[Verknuepfungen[i].outP.p2].istUnabhaengig or
+ (not Parameterattribute[Verknuepfungen[i].outP.p3].istUnabhaengig) then begin
+ writeln('Parameter zu Verknüpfung '''+tVerknuepfungToStr(Verknuepfungen[i])+''' haben falsche Attribute: '+
+ Parameterattribute[Verknuepfungen[i].outP.p1].toChar+
+ Parameterattribute[Verknuepfungen[i].outP.p2].toChar+
+ Parameterattribute[Verknuepfungen[i].outP.p3].toChar+'!');
+ halt;
+ end;
+ anz:=0;
+ for j:=0 to length(Verknuepfungen[i].outP.outputIn)-1 do
+ if Verknuepfungen[i].outP.outputIn[j]=Verknuepfungen[i] then
+ inc(anz);
+ if anz=0 then begin
+ writeln('Verknüpfung '''+tVerknuepfungToStr(Verknuepfungen[i])+''' behauptet fälschlicherweise, Person '''+tPersonToStr(Verknuepfungen[i].outP)+''' zu berechnen!');
+ halt;
+ end;
+ if anz>1 then begin
+ writeln('Verknüpfung '''+tVerknuepfungToStr(Verknuepfungen[i])+''' ist mehrfach in Person '''+tPersonToStr(Verknuepfungen[i].outP)+''' als Quelle verzeichnet!');
+ halt;
+ end;
+ for k:=0 to 1 do begin
+ anz:=0;
+ for j:=0 to length(Verknuepfungen[i].outP.KindIn.Eltern[k].inputIn)-1 do
+ if Verknuepfungen[i].outP.KindIn.Eltern[k].inputIn[j]=Verknuepfungen[i] then
+ inc(anz);
+ if anz=0 then begin
+ writeln('Verknüpfung '''+tVerknuepfungToStr(Verknuepfungen[i])+''' behauptet fälschlicherweise, von Person '''+tPersonToStr(Verknuepfungen[i].outP.KindIn.Eltern[k])+''' abzuhängen!');
+ halt;
+ end;
+ if anz>1 then begin
+ writeln('Verknüpfung '''+tVerknuepfungToStr(Verknuepfungen[i])+''' ist mehrfach in Person '''+tPersonToStr(Verknuepfungen[i].outP.KindIn.Eltern[k])+''' als Abhängigkeit verzeichnet!');
+ halt;
+ end;
+ end;
+ end;
+ end;
+ for i:=0 to length(MMInteraktionen)-1 do begin
+ if mitIndizes and (MMInteraktionen[i].Index<>i) then begin
+ writeln('MMInteraktion an Stelle '+inttostr(i)+' hat Index '+inttostr(MMInteraktionen[i].Index)+'.');
+ halt;
+ end;
+ for k:=0 to 1 do begin
+ anz:=0;
+ for j:=0 to length(MMInteraktionen[i]._Ps[k].inMMInteraktion)-1 do
+ if MMInteraktionen[i]._Ps[k].inMMInteraktion[j]=MMInteraktionen[i] then
+ inc(anz);
+ if anz=0 then begin
+ writeln('MMInteraktion '''+tMMInteraktionToStr(MMInteraktionen[i])+''' behauptet fälschlicherweise, von Person '''+MMInteraktionen[i]._Ps[k].ID+''' abzuhängen!');
+ halt;
+ end;
+ if anz>1 then begin
+ writeln('MMInteraktion '''+tMMInteraktionToStr(MMInteraktionen[i])+''' ist mehrfach in Person '''+MMInteraktionen[i]._Ps[k].ID+''' als Abhängigkeit verzeichnet!');
+ halt;
+ end;
+ end;
+ end;
+ for i:=0 to length(MFInteraktionen)-1 do begin
+ if mitIndizes and (MFInteraktionen[i].Index<>i) then begin
+ writeln('MFInteraktion an Stelle '+inttostr(i)+' hat Index '+inttostr(MFInteraktionen[i].Index)+'.');
+ halt;
+ end;
+ anz:=0;
+ for j:=0 to length(MFInteraktionen[i]._P.inMFInteraktion)-1 do
+ if MFInteraktionen[i]._P.inMFInteraktion[j]=MFInteraktionen[i] then
+ inc(anz);
+ if anz=0 then begin
+ writeln('MFInteraktion '''+tMFInteraktionToStr(MFInteraktionen[i])+''' behauptet fälschlicherweise, von Person '''+MFInteraktionen[i]._P.ID+''' abzuhängen!');
+ halt;
+ end;
+ if anz>1 then begin
+ writeln('MFInteraktion '''+tMFInteraktionToStr(MFInteraktionen[i])+''' ist mehrfach in Person '''+MFInteraktionen[i]._P.ID+''' als Abhängigkeit verzeichnet!');
+ halt;
+ end;
+ anz:=0;
+ for j:=0 to length(MFInteraktionen[i]._F.inMFInteraktion)-1 do
+ if MFInteraktionen[i]._F.inMFInteraktion[j]=MFInteraktionen[i] then
+ inc(anz);
+ if anz=0 then begin
+ writeln('MFInteraktion '''+tMFInteraktionToStr(MFInteraktionen[i])+''' behauptet fälschlicherweise, von Familie '''+MFInteraktionen[i]._F.ID+''' abzuhängen!');
+ halt;
+ end;
+ if anz>1 then begin
+ writeln('MFInteraktion '''+tMFInteraktionToStr(MFInteraktionen[i])+''' ist mehrfach in Familie '''+MFInteraktionen[i]._F.ID+''' als Abhängigkeit verzeichnet!');
+ halt;
+ end;
+ end;
+ for i:=0 to length(FFInteraktionen)-1 do begin
+ if mitIndizes and (FFInteraktionen[i].Index<>i) then begin
+ writeln('FFInteraktion an Stelle '+inttostr(i)+' hat Index '+inttostr(FFInteraktionen[i].Index)+'.');
+ halt;
+ end;
+ for k:=0 to 1 do begin
+ anz:=0;
+ for j:=0 to length(FFInteraktionen[i]._Fs[k].inFFInteraktion)-1 do
+ if FFInteraktionen[i]._Fs[k].inFFInteraktion[j]=FFInteraktionen[i] then
+ inc(anz);
+ if anz=0 then begin
+ writeln('FFInteraktion '''+tFFInteraktionToStr(FFInteraktionen[i])+''' behauptet fälschlicherweise, von Familie '''+FFInteraktionen[i]._Fs[k].ID+''' abzuhängen!');
+ halt;
+ end;
+ if anz>1 then begin
+ writeln('FFInteraktion '''+tFFInteraktionToStr(FFInteraktionen[i])+''' ist mehrfach in Familie '''+FFInteraktionen[i]._Fs[k].ID+''' als Abhängigkeit verzeichnet!');
+ halt;
+ end;
+ end;
+ end;
+ for i:=0 to length(Personen)-1 do begin
+ for j:=i+1 to length(Personen)-1 do
+ if Personen[i].id=Personen[j].id then begin
+ writeln('Ich habe zwei Personen mit gleicher ID gefungen: '''+tPersonToStr(Personen[i])+''' und '''+tPersonToStr(Personen[j])+'''!');
+ halt;
+ end;
+ if mitIndizes and (Personen[i].Index<>i) then begin
+ writeln('Person an Stelle '+inttostr(i)+' hat Index '+inttostr(Personen[i].Index)+'.');
+ halt;
+ end;
+ if assigned(Personen[i].KindIn) then begin
+ anz:=0;
+ for j:=0 to length(Personen[i].KindIn.Kinder)-1 do
+ if Personen[i].KindIn.Kinder[j]=Personen[i] then
+ inc(anz);
+ if anz=0 then begin
+ writeln('Kind '''+Personen[i].ID+''' behauptet fälschlicherweise, zu Familie '''+Personen[i].KindIn.ID+''' zu gehören!');
+ halt;
+ end;
+ if anz>1 then begin
+ writeln('Kind '''+Personen[i].ID+''' ist mehrfach in Familie '''+Personen[i].KindIn.ID+'''!');
+ halt;
+ end;
+ end;
+ for j:=0 to length(Personen[i].ElterIn)-1 do begin
+ anz:=0;
+ for k:=0 to 1 do
+ if Personen[i].ElterIn[j].Eltern[k]=Personen[i] then
+ inc(anz);
+ if anz=0 then begin
+ writeln('Elter '''+Personen[i].ID+''' behauptet fälschlicherweise, zu Familie '''+Personen[i].ElterIn[j].ID+''' zu gehören!');
+ halt;
+ end;
+ if anz>1 then begin
+ writeln('Elter '''+Personen[i].ID+''' ist mehrfach Elter in Familie '''+Personen[i].ElterIn[j].ID+'''!');
+ halt;
+ end;
+ end;
+ for j:=0 to length(Personen[i].inputIn)-1 do begin
+ anz:=0;
+ for k:=0 to 1 do
+ if Personen[i].inputIn[j].outP.kindIn.Eltern[k]=Personen[i] then
+ inc(anz);
+ if anz=0 then begin
+ writeln('Person '''+Personen[i].ID+''' behauptet fälschlicherweise, Input zu Verknüpfung '''+tVerknuepfungToStr(Personen[i].inputIn[j])+''' zu sein!');
+ halt;
+ end;
+ if anz>1 then begin
+ writeln('Person '''+Personen[i].ID+''' ist mehrfach als Input zu Verknüpfung '''+tVerknuepfungToStr(Personen[i].inputIn[j])+''' verzeichnet!');
+ halt;
+ end;
+ end;
+ for j:=0 to length(Personen[i].outputIn)-1 do begin
+ if Personen[i].outputIn[j].outP<>Personen[i] then begin
+ writeln('Person '''+Personen[i].ID+''' behauptet fälschlicherweise, Output von Verknüpfung '''+tVerknuepfungToStr(Personen[i].outputIn[j])+''' zu sein!');
+ halt;
+ end;
+ end;
+ for j:=0 to length(Personen[i].inMMInteraktion)-1 do begin
+ anz:=0;
+ for k:=0 to 1 do
+ if Personen[i].inMMInteraktion[j]._Ps[k]=Personen[i] then
+ inc(anz);
+ if anz=0 then begin
+ writeln('Person '''+Personen[i].ID+''' behauptet fälschlicherweise, in MMInteraktion '''+tMMInteraktionToStr(Personen[i].inMMInteraktion[j])+''' zu sein!');
+ halt;
+ end;
+ if anz>1 then begin
+ writeln('Person '''+Personen[i].ID+''' ist mehrfach in MMInteraktion '''+tMMInteraktionToStr(Personen[i].inMMInteraktion[j])+''' verzeichnet!');
+ halt;
+ end;
+ end;
+ for j:=0 to length(Personen[i].inMFInteraktion)-1 do begin
+ if Personen[i].inMFInteraktion[j]._P<>Personen[i] then begin
+ writeln('Person '''+Personen[i].ID+''' behauptet fälschlicherweise, in MFInteraktion '''+tMFInteraktionToStr(Personen[i].inMFInteraktion[j])+''' zu sein!');
+ halt;
+ end;
+ end;
+ end;
+ for i:=0 to length(Familien)-1 do begin
+ for j:=i+1 to length(Familien)-1 do
+ if Familien[i].id=Familien[j].id then begin
+ writeln('Ich habe zwei Familien mit gleicher ID gefungen: '''+tFamilieToStr(Familien[i])+''' und '''+tFamilieToStr(Familien[j])+'''!');
+ halt;
+ end;
+ if mitIndizes and (Familien[i].Index<>i) then begin
+ writeln('Familie an Stelle '+inttostr(i)+' hat Index '+inttostr(Familien[i].Index)+'.');
+ halt;
+ end;
+ for j:=0 to length(Familien[i].Kinder)-1 do
+ if Familien[i].Kinder[j].KindIn<>Familien[i] then begin
+ writeln('Kind '''+Familien[i].Kinder[j].ID+''' behauptet fälschlicherweise, nicht zu Familie '''+Familien[i].ID+''' zu gehören!');
+ halt;
+ end;
+ for j:=0 to length(Familien[i].Eltern)-1 do
+ if assigned(Familien[i].Eltern[j]) then begin
+ anz:=0;
+ for k:=0 to length(Familien[i].Eltern[j].ElterIn)-1 do
+ if Familien[i].Eltern[j].ElterIn[k]=Familien[i] then
+ inc(anz);
+ if anz=0 then begin
+ writeln('Elter '''+Familien[i].Eltern[j].ID+''' behauptet fälschlicherweise, nicht zu Familie '''+Familien[i].ID+''' zu gehören!');
+ halt;
+ end;
+ if anz>1 then begin
+ writeln('Elter '''+Familien[i].Eltern[j].ID+''' ist mehrfach in Familie '''+Familien[i].ID+'''!');
+ halt;
+ end;
+ end;
+ for j:=0 to length(Familien[i].inMFInteraktion)-1 do begin
+ if Familien[i].inMFInteraktion[j]._F<>Familien[i] then begin
+ writeln('Familie '''+Familien[i].ID+''' behauptet fälschlicherweise, in MFInteraktion '''+tMFInteraktionToStr(Familien[i].inMFInteraktion[j])+''' zu sein!');
+ halt;
+ end;
+ end;
+ for j:=0 to length(Familien[i].inFFInteraktion)-1 do begin
+ anz:=0;
+ for k:=0 to 1 do
+ if Familien[i].inFFInteraktion[j]._Fs[k]=Familien[i] then
+ inc(anz);
+ if anz=0 then begin
+ writeln('Familie '''+Familien[i].ID+''' behauptet fälschlicherweise, in FFInteraktion '''+tFFInteraktionToStr(Familien[i].inFFInteraktion[j])+''' zu sein!');
+ halt;
+ end;
+ if anz>1 then begin
+ writeln('Familie '''+Familien[i].ID+''' ist mehrfach in FFInteraktion '''+tFFInteraktionToStr(Familien[i].inFFInteraktion[j])+''' verzeichnet!');
+ halt;
+ end;
+ end;
+ if assigned(Familien[i].Eltern[0]) and assigned(Familien[i].Eltern[1]) then
+ for j:=i+1 to length(Familien)-1 do
+ if ((Familien[i].Eltern[0]=Familien[j].Eltern[0]) and (Familien[i].Eltern[1]=Familien[j].Eltern[1])) or
+ ((Familien[i].Eltern[0]=Familien[j].Eltern[1]) and (Familien[i].Eltern[1]=Familien[j].Eltern[0])) then begin
+ writeln('Es gibt hier zwei Familien zwischen jeweils den gleichen Eltern:');
+ writeln(' '+Familien[i].ID+' und '+Familien[j].ID);
+ writeln(' zwischen '+Familien[i].Eltern[0].ID+' und '+Familien[i].Eltern[1].ID);
+ halt;
+ end;
+ end;
+end;
+
+procedure tMetaData.pruefeAufGleichheit(vgl: tMetaData);
+var
+ i,j,cnt: longint;
+ p2p: tIntArray;
+ fehler: boolean;
+ MMarr,vMMarr: tMMInteraktionArray;
+ MFarr,vMFarr: tMFInteraktionArray;
+ FFarr,vFFarr: tFFInteraktionArray;
+ Vkarr,vVkarr: tVerknuepfungArray;
+begin
+ fehler:=false;
+ if ParameterLaenge<>vgl.ParameterLaenge then begin
+ writeln('*** Fehler ***');
+ writeln('''ParameterLaenge'' ist unterschiedlich ('+inttostr(ParameterLaenge)+' vs. '+inttostr(vgl.ParameterLaenge)+')');
+ fehler:=true;
+ end;
+
+ setlength(p2p,ParameterLaenge);
+ for i:=0 to length(p2p)-1 do
+ p2p[i]:=-1;
+
+ if length(Ereignisse)<>length(vgl.Ereignisse) then begin
+ writeln('*** Fehler ***');
+ writeln('Unterschiedlich viele Ereignisse ('+inttostr(length(Ereignisse))+' vs. '+inttostr(length(vgl.Ereignisse))+')');
+ fehler:=true;
+ end
+ else
+ for i:=0 to length(Ereignisse)-1 do begin
+ cnt:=0;
+ for j:=0 to length(vgl.Ereignisse)-1 do
+ if Ereignisse[i].istGleich(vgl.Ereignisse[j]) then
+ inc(cnt);
+ if cnt<>1 then begin
+ writeln('*** Fehler ***');
+ write('Ereignis '''+tEreignisToStr(Ereignisse[i])+''' gibt es ');
+ if cnt=0 then writeln('nicht.')
+ else writeln('mehrfach.');
+ fehler:=true;
+ end;
+ end;
+
+ write('.');
+
+ if length(Personen)<>length(vgl.Personen) then begin
+ writeln('*** Fehler ***');
+ writeln('Unterschiedlich viele Personen ('+inttostr(length(Personen))+' vs. '+inttostr(length(vgl.Personen))+')');
+ fehler:=true;
+ end
+ else
+ for i:=0 to length(Personen)-1 do begin
+ if ((Personen[i].p1<>-1) and (p2p[Personen[i].p1]<>-1)) or
+ ((Personen[i].p2<>-1) and (p2p[Personen[i].p2]<>-1)) or
+ ((Personen[i].p3<>-1) and (p2p[Personen[i].p3]<>-1)) then begin
+ writeln('*** Fehler ***');
+ writeln('Parameter doppelt referenziert!');
+ fehler:=true;
+ continue;
+ end;
+ cnt:=0;
+ for j:=0 to length(vgl.Personen)-1 do
+ if Personen[i].istGleich(vgl.Personen[j]) then begin
+ if vgl.Personen[j].p1<>-1 then
+ p2p[vgl.Personen[j].p1]:=Personen[i].p1;
+ if vgl.Personen[j].p2<>-1 then
+ p2p[vgl.Personen[j].p2]:=Personen[i].p2;
+ if vgl.Personen[j].p3<>-1 then
+ p2p[vgl.Personen[j].p3]:=Personen[i].p3;
+ inc(cnt);
+ end;
+ if cnt<>1 then begin
+ writeln('*** Fehler ***');
+ write('Person '''+tPersonToStr(Personen[i])+''' gibt es ');
+ if cnt=0 then writeln('nicht.')
+ else writeln('mehrfach.');
+ fehler:=true;
+ end;
+ end;
+
+ write('.');
+
+ if length(Familien)<>length(vgl.Familien) then begin
+ writeln('*** Fehler ***');
+ writeln('Unterschiedlich viele Familien ('+inttostr(length(Familien))+' vs. '+inttostr(length(vgl.Familien))+')');
+ fehler:=true;
+ end
+ else
+ for i:=0 to length(Familien)-1 do begin
+ cnt:=0;
+ for j:=0 to length(vgl.Familien)-1 do
+ if Familien[i].istGleich(vgl.Familien[j]) then
+ inc(cnt);
+ if cnt<>1 then begin
+ writeln('*** Fehler ***');
+ write('Familie '''+tFamilieToStr(Familien[i])+''' gibt es ');
+ if cnt=0 then writeln('nicht.')
+ else writeln('mehrfach.');
+ fehler:=true;
+ end;
+ end;
+
+ write('.');
+
+ if length(Verknuepfungen)<>length(vgl.Verknuepfungen) then begin
+ writeln('*** Fehler ***');
+ writeln('Unterschiedlich viele Verknuepfungen ('+inttostr(length(Verknuepfungen))+' vs. '+inttostr(length(vgl.Verknuepfungen))+')');
+ fehler:=true;
+ end
+ else begin
+ Vkarr:=sortiere(Verknuepfungen);
+ vVkarr:=sortiere(vgl.Verknuepfungen);
+ for i:=0 to length(Vkarr)-1 do
+ if not Vkarr[i].istGleich(vVkarr[i],p2p) then begin
+ writeln('*** Fehler ***');
+ write('Verknuepfungen unterscheiden sich ('+inttostr(cmpstr(sortstringfromobject(Vkarr[i]),sortstringfromobject(vVkarr[i])))+')!');
+ break;
+ end;
+ end;
+
+ write('.');
+
+ if length(MMInteraktionen)<>length(vgl.MMInteraktionen) then begin
+ writeln('*** Fehler ***');
+ writeln('Unterschiedlich viele MMInteraktionen ('+inttostr(length(MMInteraktionen))+' vs. '+inttostr(length(vgl.MMInteraktionen))+')');
+ fehler:=true;
+ end
+ else begin
+ MMarr:=sortiere(MMInteraktionen);
+ vMMarr:=sortiere(vgl.MMInteraktionen);
+ for i:=0 to length(MMarr)-1 do
+ if not MMarr[i].istGleich(vMMarr[i]) then begin
+ writeln('*** Fehler ***');
+ write('MMInteraktionen unterscheiden sich ('+inttostr(cmpstr(sortstringfromobject(MMarr[i]),sortstringfromobject(vMMarr[i])))+')!');
+ break;
+ end;
+ end;
+
+ write('.');
+
+ if length(MFInteraktionen)<>length(vgl.MFInteraktionen) then begin
+ writeln('*** Fehler ***');
+ writeln('Unterschiedlich viele MFInteraktionen ('+inttostr(length(MFInteraktionen))+' vs. '+inttostr(length(vgl.MFInteraktionen))+')');
+ fehler:=true;
+ end
+ else begin
+ MFarr:=sortiere(MFInteraktionen);
+ vMFarr:=sortiere(vgl.MFInteraktionen);
+ for i:=0 to length(MFarr)-1 do
+ if not MFarr[i].istGleich(vMFarr[i]) then begin
+ writeln('*** Fehler ***');
+ write('MFInteraktionen unterscheiden sich ('+inttostr(cmpstr(sortstringfromobject(MFarr[i]),sortstringfromobject(vMFarr[i])))+')!');
+ break;
+ end;
+ end;
+
+ write('.');
+
+ if length(FFInteraktionen)<>length(vgl.FFInteraktionen) then begin
+ writeln('*** Fehler ***');
+ writeln('Unterschiedlich viele FFInteraktionen ('+inttostr(length(FFInteraktionen))+' vs. '+inttostr(length(vgl.FFInteraktionen))+')');
+ fehler:=true;
+ end
+ else begin
+ FFarr:=sortiere(FFInteraktionen);
+ vFFarr:=sortiere(vgl.FFInteraktionen);
+ for i:=0 to length(FFarr)-1 do
+ if not FFarr[i].istGleich(vFFarr[i]) then begin
+ writeln('*** Fehler ***');
+ write('FFInteraktionen unterscheiden sich ('+inttostr(cmpstr(sortstringfromobject(FFarr[i]),sortstringfromobject(vFFarr[i])))+')!');
+ break;
+ end;
+ end;
+
+ write('.');
+
+ if length(ParameterAttribute)<>length(vgl.ParameterAttribute) then begin
+ writeln('*** Fehler ***');
+ writeln('''ParameterAttribute'' ist unterschiedlich lang ('+inttostr(length(ParameterAttribute))+' vs. '+inttostr(length(vgl.ParameterAttribute))+')');
+ fehler:=true;
+ end
+ else
+ for i:=0 to length(ParameterAttribute)-1 do begin
+ if p2p[i]=-1 then begin
+ writeln('*** Fehler ***');
+ write('Parameterübersetzung unvollständig!');
+ fehler:=true;
+ continue;
+ end;
+ if ParameterAttribute[p2p[i]].istUnabhaengig<>vgl.ParameterAttribute[i].istUnabhaengig then begin
+ writeln('*** Fehler ***');
+ writeln('Parameter '+inttostr(p2p[i])+' bzw. '+inttostr(i)+' ist ein Mal unabhängig und ein Mal nicht!');
+ fehler:=true;
+ end;
+ if ParameterAttribute[p2p[i]].istKoordinate<>vgl.ParameterAttribute[i].istKoordinate then begin
+ writeln('*** Fehler ***');
+ writeln('Parameter '+inttostr(p2p[i])+' bzw. '+inttostr(i)+' ist ein Mal eine Koordinate und ein Mal nicht!');
+ fehler:=true;
+ end;
+ if ParameterAttribute[p2p[i]].wirdBenutzt<>vgl.ParameterAttribute[i].wirdBenutzt then begin
+ writeln('*** Fehler ***');
+ writeln('Parameter '+inttostr(p2p[i])+' bzw. '+inttostr(i)+' wird ein Mal benutzt und ein Mal nicht!');
+ fehler:=true;
+ end;
+ end;
+
+ write('.');
+
+ if length(Tauschfamilien)<>length(vgl.Tauschfamilien) then begin
+ writeln('*** Fehler ***');
+ writeln('Unterschiedlich viele Tauschfamilien ('+inttostr(length(Tauschfamilien))+' vs. '+inttostr(length(vgl.Tauschfamilien))+')');
+ fehler:=true;
+ end
+ else
+ for i:=0 to length(Tauschfamilien)-1 do begin
+ cnt:=0;
+ for j:=0 to length(vgl.Tauschfamilien)-1 do
+ if Tauschfamilien[i].istGleich(vgl.Tauschfamilien[j]) then
+ inc(cnt);
+ if cnt<>1 then begin
+ writeln('*** Fehler ***');
+ write('Tauschfamilien '''+tFamilieToStr(Tauschfamilien[i])+''' gibt es ');
+ if cnt=0 then writeln('nicht.')
+ else writeln('mehrfach.');
+ fehler:=true;
+ end;
+ end;
+ writeln;
+ if fehler then halt;
+end;
+
+procedure tMetaData.habePersonGeloescht(p: tPerson);
+begin
+ if not assigned(p) then begin
+ writeln('*** Fehler ***');
+ writeln('Gelöschte Person ist NIL!');
+ halt;
+ end;
+ if Personen[p.index]<>p then begin
+ writeln('*** Fehler ***');
+ writeln('Gelöschte Person hat falschen Index!');
+ halt;
+ end;
+ if not personAuchDrueber[p.index] then begin
+ writeln('*** Fehler ***');
+ writeln('Gelöschte Person war schon gelöscht!');
+ halt;
+ end;
+ personAuchDrueber[p.index]:=false;
+end;
+
+procedure tMetaData.habeFamilieGeloescht(f: tFamilie);
+begin
+ if not assigned(f) then begin
+ writeln('*** Fehler ***');
+ writeln('Gelöschte Familie ist NIL!');
+ halt;
+ end;
+ if Familien[f.index]<>f then begin
+ writeln('*** Fehler ***');
+ writeln('Gelöschte Familie hat falschen Index!');
+ halt;
+ end;
+ if not familieAuchDrueber[f.index] then begin
+ writeln('*** Fehler ***');
+ writeln('Gelöschte Familie war schon gelöscht!');
+ halt;
+ end;
+ familieAuchDrueber[f.index]:=false;
+end;
+
+procedure tMetaData.habePersonHinzugefuegt(p: tPerson);
+begin
+ if not assigned(p) then begin
+ writeln('*** Fehler ***');
+ writeln('Hinzugefügte Person ist NIL!');
+ halt;
+ end;
+ if Personen[p.index]<>p then begin
+ writeln('*** Fehler ***');
+ writeln('Hinzugefügte Person hat falschen Index!');
+ halt;
+ end;
+ if personAuchDrueber[p.index] then begin
+ writeln('*** Fehler ***');
+ writeln('Hinzugefügte Person war schon hinzugefügt!');
+ halt;
+ end;
+ personAuchDrueber[p.index]:=true;
+end;
+
+procedure tMetaData.habeFamilieHinzugefuegt(f: tFamilie);
+begin
+ if not assigned(f) then begin
+ writeln('*** Fehler ***');
+ writeln('Hinzugefügte Familie ist NIL!');
+ halt;
+ end;
+ if Familien[f.index]<>f then begin
+ writeln('*** Fehler ***');
+ writeln('Hinzugefügte Familie hat falschen Index!');
+ halt;
+ end;
+ if familieAuchDrueber[f.index] then begin
+ writeln('*** Fehler ***');
+ writeln('Hinzugefügte Familie war schon hinzugefügt!');
+ halt;
+ end;
+ familieAuchDrueber[f.index]:=true;
+end;
+
+function tMetaData.istPersonAuchDrueber(p: tPerson): boolean;
+begin
+ if not assigned(p) then begin
+ writeln('*** Fehler ***');
+ writeln('Person ist NIL!');
+ halt;
+ end;
+ if Personen[p.index]<>p then begin
+ writeln('*** Fehler ***');
+ writeln('Person hat falschen Index!');
+ halt;
+ end;
+ result:=personAuchDrueber[p.index];
+end;
+
+function tMetaData.istFamilieAuchDrueber(f: tFamilie): boolean;
+begin
+ if not assigned(f) then begin
+ writeln('*** Fehler ***');
+ writeln('Famlie ist NIL!');
+ halt;
+ end;
+ if Familien[f.index]<>f then begin
+ writeln('*** Fehler ***');
+ writeln('Familie hat falschen Index!');
+ halt;
+ end;
+ result:=familieAuchDrueber[f.index];
+end;
+
+procedure tMetaData.indizesErzeugen;
+var i: longint;
+begin
+ for i:=0 to length(Personen)-1 do
+ Personen[i].index:=i;
+ for i:=0 to length(Familien)-1 do
+ Familien[i].index:=i;
+ for i:=0 to length(Verknuepfungen)-1 do
+ Verknuepfungen[i].index:=i;
+ for i:=0 to length(MMInteraktionen)-1 do
+ MMInteraktionen[i].index:=i;
+ for i:=0 to length(MFInteraktionen)-1 do
+ MFInteraktionen[i].index:=i;
+ for i:=0 to length(FFInteraktionen)-1 do
+ FFInteraktionen[i].index:=i;
+end;
+
+procedure tMetaData.loescheVerknuepfungenZu(p: tPerson);
+var
+ i,ind: longint;
+begin
+ for i:=length(p.outputIn)-1 downto 0 do begin
+ ind:=p.outputIn[i].index;
+ p.outputIn[i].free;
+ Verknuepfungen[ind]:=nil;
+ end;
+end;
+
+procedure tMetaData.loescheAlleVerbindungenZu(p: tPerson; f: tFamilie);
+var
+ i,j,ind: longint;
+begin
+ if assigned(p) then begin
+ loescheVerknuepfungenZu(p);
+ for i:=length(p.inputIn)-1 downto 0 do begin
+ ind:=p.inputIn[i].index;
+ p.inputIn[i].free;
+ Verknuepfungen[ind]:=nil;
+ end;
+ for i:=length(p.inMMInteraktion)-1 downto 0 do begin
+ ind:=p.inMMInteraktion[i].index;
+ p.inMMInteraktion[i].free;
+ MMInteraktionen[ind]:=nil;
+ end;
+ for i:=length(p.inMFInteraktion)-1 downto 0 do begin
+ ind:=p.inMFInteraktion[i].index;
+ p.inMFInteraktion[i].free;
+ MFInteraktionen[ind]:=nil;
+ end;
+ end;
+ if assigned(f) then begin
+ for i:=length(f.inMFInteraktion)-1 downto 0 do begin
+ ind:=f.inMFInteraktion[i].index;
+ f.inMFInteraktion[i].free;
+ MFInteraktionen[ind]:=nil;
+ end;
+ for i:=length(f.inFFInteraktion)-1 downto 0 do begin
+ ind:=f.inFFInteraktion[i].index;
+ f.inFFInteraktion[i].free;
+ FFInteraktionen[ind]:=nil;
+ end;
+ for i:=length(Tauschfamilien)-1 downto 0 do
+ if Tauschfamilien[i]=f then begin
+ for j:=i+1 to length(Tauschfamilien)-1 do
+ Tauschfamilien[j-1]:=Tauschfamilien[j];
+ setlength(Tauschfamilien,length(Tauschfamilien)-1);
+ end;
+ end;
+end;
+
+procedure tMetaData.arraysAufraeumen;
+var
+ i,j: longint;
+begin
+ j:=0;
+ for i:=0 to length(Verknuepfungen)-1 do
+ if Verknuepfungen[i]<>nil then begin
+ Verknuepfungen[j]:=Verknuepfungen[i];
+ Verknuepfungen[j].index:=j;
+ inc(j);
+ end;
+ setlength(Verknuepfungen,j);
+ j:=0;
+ for i:=0 to length(MMInteraktionen)-1 do
+ if MMInteraktionen[i]<>nil then begin
+ MMInteraktionen[j]:=MMInteraktionen[i];
+ MMInteraktionen[j].index:=j;
+ inc(j);
+ end;
+ setlength(MMInteraktionen,j);
+ j:=0;
+ for i:=0 to length(MFInteraktionen)-1 do
+ if MFInteraktionen[i]<>nil then begin
+ MFInteraktionen[j]:=MFInteraktionen[i];
+ MFInteraktionen[j].index:=j;
+ inc(j);
+ end;
+ setlength(MFInteraktionen,j);
+ j:=0;
+ for i:=0 to length(FFInteraktionen)-1 do
+ if FFInteraktionen[i]<>nil then begin
+ FFInteraktionen[j]:=FFInteraktionen[i];
+ FFInteraktionen[j].index:=j;
+ inc(j);
+ end;
+ setlength(FFInteraktionen,j);
+end;
+
+function tMetaData.anzUnabhaengig: longint;
+var
+ i: longint;
+begin
+ result:=0;
+ for i:=0 to length(ParameterAttribute)-1 do
+ result:=result+byte(ParameterAttribute[i].istUnabhaengig);
+end;
+
+function tMetaData.anzUnbenutzt: longint;
+var
+ i: longint;
+begin
+ result:=0;
+ for i:=0 to length(ParameterAttribute)-1 do
+ result:=result+byte(not ParameterAttribute[i].wirdBenutzt);
+end;
+
+// tParameterSimplex ***********************************************************
+constructor tParameterSimplex.create;
+begin
+ inherited create;
+ dim:=0;
+ fillchar(Ecken,sizeof(Ecken),#0);
+ setlength(Ecken,0);
+ fillchar(Energien,sizeof(Energien),#0);
+ setlength(Energien,0);
+ md:=nil;
+ letzteSchwerpunktberechnung:=0;
+ letzteSchwerpunktabweichung:=-1;
+end;
+
+destructor tParameterSimplex.destroy;
+begin
+ setlength(Ecken,0);
+ setlength(Energien,0);
+end;
+
+function tParameterSimplex.besserAls(a,b: longint): longint; // -1: a schlechter als b; 0: gleich gut; 1: a besser als b
+begin
+ result:=besserAls(a,b,false);
+end;
+
+function tParameterSimplex.besserAls(a,b: longint; hart: boolean): longint;
+begin
+ result:=besserAls(Kreuzungens[a],Energien[a],b);
+ if hart and (result=0) then begin
+ if a>b then begin
+ result:=-1;
+ exit;
+ end;
+ if a<b then begin
+ result:=1;
+ exit;
+ end;
+ end;
+end;
+
+function tParameterSimplex.besserAls(aKrz: longint; aEnerg: extended; b: longint): longint;
+begin
+ if aKrz>Kreuzungens[b] then begin
+ result:=-1;
+ exit;
+ end;
+ if aKrz<Kreuzungens[b] then begin
+ result:=1;
+ exit;
+ end;
+ if aEnerg>Energien[b] then begin
+ result:=-1;
+ exit;
+ end;
+ if aEnerg<Energien[b] then begin
+ result:=1;
+ exit;
+ end;
+ result:=0;
+end;
+
+procedure tParameterSimplex.ordnen;
+var i,j,lb,b: longint;
+begin
+ lb:=-1;
+ for i:=0 to dim do begin
+ b:=-1;
+ for j:=0 to dim do
+ if ((lb=-1) or (besserAls(lb,j,true)>0)) and
+ ((b=-1) or (besserAls(b,j,true)<0)) then
+ b:=j;
+ if b=-1 then begin
+ writeln('Nach '+inttostr(i+1)+' von '+inttostr(dim+1)+' Schritten ist kein Element mehr zu finden! ... seltsam!');
+ halt(1);
+ end;
+ Reihenfolge[i]:=b;
+ lb:=b;
+ end;
+end;
+
+function tParameterSimplex.einsortieren(wen,Luecke: longint): longint;
+var i,j,k: longint;
+begin
+ for i:=Luecke to dim-1 do
+ Reihenfolge[i]:=Reihenfolge[i+1];
+ i:=-1;
+ j:=dim;
+ while i<j-1 do begin // Bisektion
+ k:=(i+j) div 2;
+ if besserAls(wen,Reihenfolge[k],true)>0 then
+ j:=k
+ else
+ i:=k;
+ end;
+ if i<>j-1 then begin
+ writeln('Bisektion ist fehlgeschlagen ('+inttostr(i)+','+inttostr(j)+')');
+ halt(1);
+ end;
+ for i:=dim-1 downto j do
+ Reihenfolge[i+1]:=Reihenfolge[i];
+ Reihenfolge[j]:=wen;
+ result:=Luecke-j; // wie viele Plätze wurden gut gemacht?
+ j:=0;
+ for i:=0 to dim-1 do
+ if besserAls(Reihenfolge[i],Reihenfolge[i+1],true)<>1 then begin
+ j:=1;
+ write(i,' ');
+ end;
+ if j=1 then begin
+ writeln;
+ writeln('Fehler beim Einsortieren!');
+ halt;
+ end;
+end;
+
+function tParameterSimplex.normalisiere(i: longint): boolean;
+begin
+ result:=normalisiere(Ecken[i]);
+ if result then
+ berechneSchwerpunkt;
+end;
+
+function tParameterSimplex.normalisiere(ps: tExtendedArray): boolean;
+var
+ i: longint;
+ ma,mi: extended;
+begin
+ ma:=1;
+ mi:=0;
+ for i:=0 to length(ps)-1 do begin
+ ma:=max(ma,ps[i]);
+ mi:=min(mi,ps[i]);
+ end;
+ result:=(ma>1) or (mi<0);
+ if not result then exit;
+(* writeln;
+ writeln(mi,' .. ',ma);
+ for i:=0 to length(ps)-1 do
+ if (ps[i]=mi) or (ps[i]=ma) then
+ writeln(' '+inttostr(i)+' '+inttostr(byte(md.Koordinate[i]))); *)
+ ma:=1/max(epsilon,ma-mi);
+ for i:=0 to length(ps)-1 do
+ ps[i]:=(ps[i]-mi)*ma;
+end;
+
+procedure tParameterSimplex.berechneEnergien(mt: longint);
+begin
+ berechneEnergien(mt,false);
+end;
+
+procedure tParameterSimplex.berechneEnergien(mt: longint; ParameterBerechnen: boolean);
+var i: longint;
+ fertig: boolean;
+ ets: array of tEnergieThread;
+begin
+ setlength(ets,mt);
+ for i:=0 to mt-1 do
+ ets[i]:=
+ tEnergieThread.create(
+ self,
+ round( i /mt*(dim+1)),
+ round((i+1)/mt*(dim+1) - 1),
+ ParameterBerechnen);
+ repeat
+ fertig:=true;
+ for i:=0 to mt-1 do
+ fertig:=fertig and ets[i].fertig;
+ if not fertig then
+ sleep(100);
+ until fertig;
+ for i:=0 to mt-1 do
+ ets[i].free;
+end;
+
+function tParameterSimplex.berechneSchwerpunkt: extended;
+var
+ i,j: longint;
+ sp: tExtendedArray;
+begin
+ if dim<=1 then exit;
+ setlength(sp,dim);
+ for i:=0 to dim-1 do
+ sp[i]:=0;
+ for i:=0 to dim do
+ for j:=0 to dim-1 do
+ sp[j]:=sp[j]+Ecken[i][j];
+ for i:=0 to dim-1 do
+ sp[i]:=sp[i]/dim;
+ if length(Schwerpunkt)<>dim then begin
+ result:=-1;
+ setlength(Schwerpunkt,dim);
+ for i:=0 to dim-1 do
+ Schwerpunkt[i]:=sp[i];
+ end
+ else begin
+ result:=0;
+ for i:=0 to dim-1 do begin
+ result:=result+sqr(sp[i]-Schwerpunkt[i]);
+ Schwerpunkt[i]:=sp[i];
+ end;
+ end;
+ setlength(sp,0);
+ letzteSchwerpunktberechnung:=0;
+ letzteSchwerpunktabweichung:=result;
+end;
+
+procedure tParameterSimplex.init(ps: tExtendedArray; mt: longint);
+var i,j: longint;
+begin
+ if not assigned(md) then exit;
+ if md.ParameterLaenge<>length(ps) then exit;
+
+ for i:=0 to length(Ecken)-1 do
+ setlength(Ecken[i],0);
+ dim:=md.anzUnabhaengig;
+ pdim:=md.ParameterLaenge;
+ writeln('Der Simplex hat '+inttostr(dim+1)+' Ecken mit je '+inttostr(pdim)+' Parametern (davon '+inttostr(dim)+' unabhängige).');
+ setlength(Ecken,dim+1);
+ setlength(Energien,dim+1);
+ setlength(Kreuzungens,dim+1);
+ setlength(Kreuzungs,dim+1);
+ setlength(Reihenfolge,dim+1);
+ for i:=0 to length(Ecken)-1 do begin
+ setlength(Ecken[i],pdim);
+ Energien[i]:=-1;
+ Kreuzungens[i]:=0;
+ Kreuzungs[i]:=-1;
+ Reihenfolge[i]:=i;
+ end;
+
+ for i:=0 to pdim-1 do
+ Ecken[0,i]:=min(1,max(0,ps[i]));
+ for i:=1 to dim do begin
+ for j:=0 to dim-1 do
+ Ecken[i,j]:=Ecken[0,j] + (2*byte(Ecken[0,j]<0.5)-1)*(1e-15 + byte(MD.ParameterAttribute[MD.UnabIndizes[j]].istKoordinate)*1e-6)*byte(i-1 = j);
+ for j:=dim to pdim-1 do
+ Ecken[i,j]:=nan;
+ end;
+ for i:=0 to dim do
+ for j:=0 to dim-1 do
+ if (Ecken[i,j]<0) or (Ecken[i,j]>1) then begin
+ writeln('*** Fehler *** '+inttostr(i)+';'+inttostr(j)+': '+myfloattostr(Ecken[i,j]));
+ halt;
+ end;
+ berechneEnergien(mt,true);
+ berechneSchwerpunkt;
+ ordnen;
+end;
+
+procedure tParameterSimplex.outit(var ps: tExtendedArray);
+var
+ i: longint;
+begin
+ if length(ps)<>pdim then begin
+ writeln('Warnung: Anzahl der Parameter hat nicht gepasst, wurde angepasst!');
+ setlength(ps,pdim);
+ end;
+ for i:=0 to pdim-1 do
+ ps[i]:=Ecken[Reihenfolge[0],i];
+end;
+
+function tParameterSimplex.simplexSchritt(f,f1,f2,f3: extended; offset: longint): tSchrittErgebnis;
+var
+ np: tExtendedArray;
+begin
+ setlength(np,pdim);
+ result:=simplexSchritt(np,f,f1,f2,f3,offset);
+ setlength(np,0);
+end;
+
+function tParameterSimplex.simplexSchritt(var np: tExtendedArray; f,f1,f2,f3: extended; offset: longint): tSchrittErgebnis;
+var i,lu,krzgn,krz,aKrzgn: longint;
+ energ,aEnerg,fx,fs,fak: extended;
+ spBerechnen: byte;
+begin
+ if length(np)<>pdim then begin
+ writeln('Warnung: Arraylange musste angepasst werden!');
+ setlength(np,pdim);
+ for i:=0 to pdim-1 do
+ np[i]:=0;
+ end;
+ lu:=dim-offset;
+ offset:=Reihenfolge[lu];
+ aEnerg:=energien[offset];
+ aKrzgn:=Kreuzungens[offset];
+
+ fx:=(dim*f+1)/(dim-1);
+ fs:=(1+f)*dim/(dim-1);
+ for i:=0 to dim-1 do // X' = S * (1+f) dim / (dim-1) - X * (dim f + 1)/(dim - 1)
+ np[i]:=Schwerpunkt[i]*fs - Ecken[offset,i]*fx;
+
+ spBerechnen:=$3*byte(normalisiere(np)) xor $1;
+
+ md.berechneAbhaengigeVariable(np{$IFDEF detaillierteZeitanalyse}, true{$ENDIF});
+ energ:=md.Energie(np,krzgn,krz{$IFDEF detaillierteZeitanalyse}, true{$ENDIF});
+
+ if besserAls(krzgn,energ,offset)<0 then fak:=f1 // verschlechtert
+ else if besserAls(krzgn,energ,Reihenfolge[0])<0 then fak:=f2 // nicht der beste
+ else fak:=f3; // der beste
+
+ // X' = S (1+f) dim / (dim-1) - X * (dim f + 1)/(dim - 1)
+ fx:=(dim*fak+1)/(dim-1);
+ for i:=0 to dim-1 do
+ Ecken[offset,i]:=Schwerpunkt[i]*fs - Ecken[offset,i]*fx;
+
+ spBerechnen:=(spBerechnen shl 2) or byte(not normalisiere(offset));
+ berechneAbhaengigeVariable(offset{$IFDEF detaillierteZeitanalyse}, true{$ENDIF});
+ berechneEnergie(offset{$IFDEF detaillierteZeitanalyse}, true{$ENDIF});
+ result.faktorNeutralisiert:=besserAls(krzgn,energ,offset)>0; // mit großem Faktor verschlechtert
+ if result.faktorNeutralisiert then begin
+ fak:=f; // wird für die korrekte Schwerpunktverschiebung gebraucht
+ spBerechnen:=spBerechnen shr 1;
+ for i:=0 to pdim-1 do
+ Ecken[offset,i]:=
+ np[i];
+ Energien[offset]:=energ;
+ Kreuzungens[offset]:=krzgn;
+ Kreuzungs[offset]:=krz;
+ end;
+
+ if odd(spBerechnen shr 1) then
+ berechneSchwerpunkt // writeln('('+inttostr(letzteSchwerpunktberechnung)+') .Schwerpunktabweichung: '+myfloattostr(berechneSchwerpunkt))
+ else if odd(spBerechnen) then begin
+ // S' = S + (X'-X)/dim
+ // X'-X = X' * (1 + (dim - 1)/(dim f + 1)) - S * (1+f) dim / (dim f + 1)
+ fx:=1 + (dim-1)/(dim*fak+1);
+ fs:=(1+fak)*dim/(dim*fak+1);
+ for i:=0 to dim-1 do
+ Schwerpunkt[i]:=fs*Schwerpunkt[i] + fx*Ecken[offset,i];
+ inc(letzteSchwerpunktberechnung);
+ if (letzteSchwerpunktabweichung<=0) or
+ (letzteSchwerpunktberechnung*letzteSchwerpunktabweichung>1) or
+ (letzteSchwerpunktberechnung>100) then
+ berechneSchwerpunkt;//writeln('('+inttostr(letzteSchwerpunktberechnung)+') Schwerpunktabweichung: '+myfloattostr(berechneSchwerpunkt));
+ end;
+
+ result.besserAlsVorher:=besserAls(aKrzgn,aEnerg,offset)<0;
+// Energien[offset]:=md.Energie(Ecken[offset],Kreuzungens[offset],Kreuzungs[offset]);
+ result.Platzveraenderung:=einsortieren(offset,lu);
+end;
+
+procedure tParameterSimplex.berechneEnergie(i: longint{$IFDEF detaillierteZeitanalyse}; mainThread: boolean{$ENDIF});
+begin
+ Energien[i]:=md.Energie(Ecken[i],Kreuzungens[i],Kreuzungs[i]{$IFDEF detaillierteZeitanalyse},mainThread{$ENDIF});
+end;
+
+procedure tParameterSimplex.berechneAbhaengigeVariable(i: longint{$IFDEF detaillierteZeitanalyse}; mainThread: boolean{$ENDIF});
+begin
+ md.berechneAbhaengigeVariable(Ecken[i]{$IFDEF detaillierteZeitanalyse},mainThread{$ENDIF});
+end;
+
+function tParameterSimplex.minKreuzungen: longint;
+begin
+ result:=Kreuzungens[Reihenfolge[0]];
+end;
+
+function tParameterSimplex.maxKreuzungen: longint;
+begin
+ result:=Kreuzungens[Reihenfolge[dim]];
+end;
+
+function tParameterSimplex.minEnergie: extended;
+begin
+ result:=Energien[Reihenfolge[0]];
+end;
+
+function tParameterSimplex.maxEnergie: extended;
+begin
+ result:=Energien[Reihenfolge[dim]];
+end;
+
+procedure tParameterSimplex.printHistogramm;
+var i: longint;
+ hist: tIntArray;
+begin
+ setlength(hist,Kreuzungens[Reihenfolge[dim]]-Kreuzungens[Reihenfolge[0]]+1);
+ for i:=0 to length(hist)-1 do
+ hist[i]:=0;
+ for i:=0 to length(Kreuzungens)-1 do
+ inc(hist[Kreuzungens[i]-Kreuzungens[Reihenfolge[0]]]);
+ for i:=0 to length(hist)-1 do
+ writeln(Kreuzungens[Reihenfolge[0]]+i,': ',hist[i]);
+end;
+
+function tParameterSimplex.mittlereKantenlaenge: extended;
+var
+ mat: array of tExtendedArray;
+ i,j: longint;
+begin
+ setlength(mat,dim);
+ for i:=0 to dim-1 do begin
+ setlength(mat[i],dim);
+ for j:=0 to dim-1 do
+ mat[i,j]:=Ecken[i+1,j]-Ecken[0,j];
+ end;
+ result:=rootDet(mat);
+ for i:=0 to length(mat)-1 do
+ setlength(mat[i],0);
+ setlength(mat,0);
+end;
+
+procedure tParameterSimplex.printSpur(nam: string; von,nach: longint);
+var
+ ps,step: tExtendedArray;
+ i,j,krzgn: longint;
+ ener,dx: extended;
+ f: textfile;
+const
+ Schritte = 10000;
+begin
+ if fileexists(nam) then begin
+ writeln('*** Fehler ***');
+ writeln(' Datei '''+nam+''' existiert bereits!');
+ halt;
+ end;
+ setlength(ps,pdim);
+ setlength(step,dim);
+ dx:=0;
+ for i:=0 to dim-1 do begin
+ step[i]:=(Ecken[nach,i]-Ecken[von,i])/(Schritte-1);
+ dx:=dx+sqr(step[i]);
+ end;
+
+ dx:=sqrt(dx);
+
+ for i:=0 to pdim-1 do
+ ps[i]:=0;
+
+ assignfile(f,nam);
+ rewrite(f);
+ for i:=0 to Schritte-1 do begin
+ for j:=0 to dim-1 do
+ ps[j]:=Ecken[von,j]+i*step[j];
+ md.berechneAbhaengigeVariable(ps);
+ ener:=md.Energie(ps,krzgn,j);
+ writeln(f,inttostr(i)+#9+inttostr(krzgn)+#9+myfloattostr(ener)+#9+myfloattostr(i*dx));
+ end;
+ closefile(f);
+end;
+
+// ******************************** TStabile ****************************************************
+
+procedure TStabile.setzeFamilie(Fam: tFamilie; x,y,dist,lambda: extended; var P: tExtendedArray);
+var Rtg,Rx,Ry: extended;
+begin
+ Rtg:=random*2*pi;
+ Rx:=dist*cos(Rtg);
+ Ry:=dist*sin(Rtg);
+ P[Fam.Eltern[0].P1]:=x+Rx*Lambda;
+ P[Fam.Eltern[0].P2]:=y+Ry*Lambda;
+ P[Fam.Eltern[1].P1]:=x+Rx*(1-Lambda);
+ P[Fam.Eltern[1].P2]:=y+Ry*(1-Lambda);
+end;
+
+constructor TStabile.create;
+begin
+ create(nil);
+end;
+
+constructor TStabile.create(MetaData: TMetaData);
+begin
+ inherited create;
+ NotAus:=TNotAus.create;
+ if assigned(MetaData) then
+ MD:=MetaData
+ else
+ MD:=TMetaData.create;
+ setlength(Parameter,MD.ParameterLaenge);
+ Schritte:=0;
+ Laufzeit:=0;
+ stepsize:=minSchrittweite;
+end;
+
+destructor TStabile.destroy;
+begin
+ Setlength(Parameter,0);
+ MD.free;
+ NotAus.destroy;
+ inherited destroy;
+end;
+
+procedure TStabile.printStatus(Level: Longint);
+var
+ I,J,K: Longint;
+ laeng,kuerz,tmp: Extended;
+begin
+ if (Level<0) or (Level>9) then
+ begin
+ writeln('Illegales Argument für Funktionsaufruf von TStabile.printStatus!');
+ exit;
+ end;
+ if not assigned(MD) then
+ begin
+ writeln('Keine Metadaten vorhanden!');
+ exit;
+ end;
+ if (Level=3) and not NotAus.Stati[Level] then dec(Level);
+ if not NotAus.Stati[Level] then exit;
+ case Level of
+ 0..4: MD.printStatus(Level);
+ 5:
+ begin
+ Laeng:=-1;
+ Kuerz:=2;
+ J:=0;
+ K:=0;
+ for I:=0 to length(MD.Familien)-1 do
+ begin
+ tmp:=
+ sqr(
+ Parameter[MD.Familien[I].Eltern[0].P1] -
+ Parameter[MD.Familien[I].Eltern[1].P1]) +
+ sqr(
+ Parameter[MD.Familien[I].Eltern[0].P2] -
+ Parameter[MD.Familien[I].Eltern[1].P2]);
+ if tmp>Laeng then
+ begin
+ Laeng:=tmp;
+ J:=I;
+ end;
+ if tmp<Kuerz then
+ begin
+ Kuerz:=tmp;
+ K:=I;
+ end;
+ end;
+ write(
+ inttostr(Level)+') '+'Längste Beziehung: '+myfloattostr(sqrt(Laeng))+' ');
+ write(MD.Familien[J].Eltern[0].Vorname);
+ write(' und ');
+ write(MD.Familien[J].Eltern[1].Vorname);
+ write(' ');
+ writeln('"'+MD.Familien[J].Eltern[1].Nachname+'"');
+ writeln(MD.Familien[J].Eltern[0].Nachname);
+ write(
+ inttostr(Level)+') '+'Kürzeste Beziehung: '+myfloattostr(sqrt(Kuerz))+' ');
+ write(MD.Familien[K].Eltern[0].Vorname);
+ write(' und ');
+ write(MD.Familien[K].Eltern[1].Vorname);
+ write(' ');
+ writeln('"'+MD.Familien[K].Eltern[1].Nachname+'"');
+ writeln(MD.Familien[K].Eltern[0].Nachname);
+ end;
+ 7:
+ writeln(inttostr(Level)+') '+inttostr(Schritte)+' '+myfloattostr(Energie)+' '+inttostr(Kreuzungen)+' Kreuzungen');
+ end{of case};
+end;
+
+procedure TStabile.assignMetaData(MetaData: TMetaData);
+begin
+ MD:=MetaData;
+ Setlength(Parameter,MD.ParameterLaenge);
+end;
+
+function TStabile.ladeXML(Datei: String): boolean;
+(*var
+ i,j: longint; *)
+begin
+ result:=MD.ladeXML(Datei);
+ md.konsistenzTest(false);
+(*
+ for i:=length(MD.Familien)-1 downto 1 do begin
+ MD.Familien[length(MD.Familien)-1].free;
+ setlength(MD.Familien,length(MD.Familien)-1);
+ MD.konsistenztest;
+ end;
+
+ writeln(inttostr(length(MD.Familien))+' '+inttostr(length(MD.Personen)));
+
+ for i:=length(MD.Personen)-1 downto 0 do
+ if (not assigned(MD.Personen[i].KindIn)) and
+ (length(MD.Personen[i].ElterIn)=0) then begin
+ MD.Personen[i].Free;
+ for j:=i+1 to length(MD.Personen)-1 do
+ MD.Personen[j-1]:=MD.Personen[j];
+ setlength(MD.Personen,length(MD.Personen)-1);
+ end;
+
+ writeln(inttostr(length(MD.Familien))+' '+inttostr(length(MD.Personen))); *)
+
+
+(* writeln(inttostr(length(MD.Familien))+' '+inttostr(length(MD.Personen)));
+ for i:=0 to 39 do begin
+ MD.Familien[length(MD.Familien)-1].free;
+ setlength(MD.Familien,length(MD.Familien)-1);
+ MD.konsistenztest;
+ MD.blaetterAbschneiden;
+ MD.konsistenztest;
+ MD.nurGroeszteZusammenhangskomponente;
+ MD.konsistenztest;
+ writeln(inttostr(length(MD.Familien))+' '+inttostr(length(MD.Personen)));
+ end; *)
+end;
+
+procedure TStabile.generiereFehlendeInfos;
+begin
+ md.generiereFehlendeInfos;
+ md.konsistenzTest(true);
+end;
+
+procedure TStabile.nurGroeszteZusammenhangskomponente;
+begin
+ md.nurGroeszteZusammenhangskomponente;
+ md.konsistenzTest(false);
+end;
+
+procedure TStabile.blaetterAbschneiden;
+begin
+ writeln('Blätter abschneiden ('+inttostr(md.anzUnabhaengig)+' bzw. '+inttostr(md.ParameterLaenge)+') ...');
+ md.indizesErzeugen;
+ md.konsistenzTest(true);
+ md.blaetterAbschneiden;
+ md.konsistenzTest(true);
+ writeln('... fertig ('+inttostr(md.anzUnabhaengig)+' bzw. '+inttostr(md.ParameterLaenge)+')');
+end;
+
+function TStabile.analysiereInteraktionen: boolean;
+begin
+ result:=MD.analysiereInteraktionen;
+ if result then
+ setlength(Parameter,MD.ParameterLaenge);
+end;
+
+function TStabile.LadeVonDatei(Datei: String): boolean;
+var
+ f: tmyStringList;
+ s: String;
+ i,j: longint;
+begin
+ result:=false;
+ writeln('Lade von '''+Datei+''' ...');
+ f:=tMyStringList.create;
+ if copy(Datei,length(Datei)-3,4)='.txt' then
+ f.loadFromFile(Datei)
+ else
+ f.loadFromGz(Datei);
+ if not f.readln(s) then begin
+ writeln('Unerwartetes Dateiende in '''+Datei+'''!');
+ f.free;
+ exit;
+ end;
+ if s<>'Stabile-Zwischenzustand (menschenlesbar, aber nicht unbedingt menschenverstehbar)' then begin
+ writeln('Syntaxfehler in '''+Datei+'''!');
+ f.free;
+ exit;
+ end;
+ if not f.readln(s) then begin
+ writeln('Unerwartetes Dateiende in '''+Datei+'''!');
+ f.free;
+ exit;
+ end;
+ if leftStr(s,9)<>'Schritte ' then begin
+ writeln('Syntaxfehler in '''+Datei+'''!');
+ f.free;
+ exit;
+ end;
+ delete(s,1,9);
+ Schritte:=strtoint(s);
+ if not f.readln(s) then begin
+ writeln('Unerwartetes Dateiende in '''+Datei+'''!');
+ f.free;
+ exit;
+ end;
+ if leftStr(s,9)<>'stepsize ' then begin
+ writeln('Syntaxfehler in '''+Datei+'''!');
+ f.free;
+ exit;
+ end;
+ delete(s,1,9);
+ stepsize:=mystrtofloat(s);
+ for i:=0 to 9 do begin
+ if not f.readln(s) then begin
+ writeln('Unerwartetes Dateiende in '''+Datei+'''!');
+ f.free;
+ exit;
+ end;
+ if leftstr(s,9)<>'Stati['+inttostr(i)+'] ' then begin
+ writeln('Syntaxfehler in '''+Datei+'''!');
+ f.free;
+ exit;
+ end;
+ delete(s,1,9);
+ NotAus.Stati[i]:=s='1';
+ end;
+ if not f.readln(s) then begin
+ writeln('Unerwartetes Dateiende in '''+Datei+'''!');
+ f.free;
+ exit;
+ end;
+ if leftStr(s,9)<>'Laufzeit ' then begin
+ writeln('Syntaxfehler in '''+Datei+'''!');
+ f.free;
+ exit;
+ end;
+ delete(s,1,9);
+ Laufzeit:=mystrtofloat(s);
+ if not f.readln(s) then begin
+ writeln('Unerwartetes Dateiende in '''+Datei+'''!');
+ f.free;
+ exit;
+ end;
+ if leftStr(s,19)<>'length(Ereignisse) ' then begin
+ writeln('Syntaxfehler in '''+Datei+'''!');
+ f.free;
+ exit;
+ end;
+ delete(s,1,19);
+ j:=strtoint(s);
+ for i:=0 to j-1 do begin
+ if not f.readln(s) then begin
+ writeln('Unerwartetes Dateiende in '''+Datei+'''!');
+ f.free;
+ exit;
+ end;
+ if pos('Ereignisse['+inttostr(i)+'] ',s)<>1 then begin
+ writeln('Syntaxfehler in '''+Datei+'''!');
+ f.free;
+ exit;
+ end;
+ delete(s,1,length('Ereignisse['+inttostr(i)+'] '));
+ ImportEreignis(s,MD.Ereignisse);
+ end;
+ if not f.readln(s) then begin
+ writeln('Unerwartetes Dateiende in '''+Datei+'''!');
+ f.free;
+ exit;
+ end;
+ if leftStr(s,17)<>'length(Personen) ' then begin
+ writeln('Syntaxfehler in '''+Datei+'''!');
+ f.free;
+ exit;
+ end;
+ delete(s,1,17);
+ j:=strtoint(s);
+ for i:=0 to j-1 do begin
+ if not f.readln(s) then begin
+ writeln('Unerwartetes Dateiende in '''+Datei+'''!');
+ f.free;
+ exit;
+ end;
+ if pos('Personen['+inttostr(i)+'] ',s)<>1 then begin
+ writeln('Syntaxfehler in '''+Datei+'''!');
+ f.free;
+ exit;
+ end;
+ delete(s,1,length('Personen['+inttostr(i)+'] '));
+ ImportPerson(s,MD.Personen,MD.Ereignisse,MD.Familien);
+ end;
+ if not f.readln(s) then begin
+ writeln('Unerwartetes Dateiende in '''+Datei+'''!');
+ f.free;
+ exit;
+ end;
+ if leftStr(s,17)<>'length(Familien) ' then begin
+ writeln('Syntaxfehler in '''+Datei+'''!');
+ f.free;
+ exit;
+ end;
+ delete(s,1,17);
+ j:=strtoint(s);
+ for i:=0 to j-1 do begin
+ if not f.readln(s) then begin
+ writeln('Unerwartetes Dateiende in '''+Datei+'''!');
+ f.free;
+ exit;
+ end;
+ if pos('Familien['+inttostr(i)+'] ',s)<>1 then begin
+ writeln('Syntaxfehler in '''+Datei+'''!');
+ f.free;
+ exit;
+ end;
+ delete(s,1,length('Familien['+inttostr(i)+'] '));
+ ImportFamilie(s,MD.Personen,MD.Ereignisse,MD.Familien);
+ end;
+ if not f.readln(s) then begin
+ writeln('Unerwartetes Dateiende in '''+Datei+'''!');
+ f.free;
+ exit;
+ end;
+ if leftStr(s,12)<>'Unabhaengig ' then begin
+ writeln('Syntaxfehler in '''+Datei+'''!');
+ f.free;
+ exit;
+ end;
+ delete(s,1,12);
+ MD.ParameterLaenge:=length(s);
+ setlength(MD.ParameterAttribute,MD.ParameterLaenge);
+ for i:=0 to length(MD.ParameterAttribute)-1 do
+ MD.ParameterAttribute[i].fromChar(s[i+1]);
+ if not f.readln(s) then begin
+ writeln('Unerwartetes Dateiende in '''+Datei+'''!');
+ f.free;
+ exit;
+ end;
+ if leftStr(s,18)<>'length(Parameter) ' then begin
+ writeln('Syntaxfehler in '''+Datei+'''!');
+ f.free;
+ exit;
+ end;
+ delete(s,1,18);
+ if length(MD.Parameterattribute)<>strtoint(s) then begin
+ writeln('Inkonsistenz in Datei '''+Datei+''': Parameterlänge ('+s+') unterscheidet sich von Anzahl der Parameterattribute ('+inttostr(length(MD.Parameterattribute))+')!');
+ f.free;
+ exit;
+ end;
+ setlength(Parameter,MD.ParameterLaenge);
+ for i:=0 to length(Parameter)-1 do begin
+ if not f.readln(s) then begin
+ writeln('Unerwartetes Dateiende in '''+Datei+'''!');
+ f.free;
+ exit;
+ end;
+ if pos('Parameter['+inttostr(i)+'] ',s)<>1 then begin
+ writeln('Syntaxfehler in '''+Datei+'''!');
+ f.free;
+ exit;
+ end;
+ delete(s,1,length('Parameter['+inttostr(i)+'] '));
+ Parameter[i]:=mystrtofloat(s);
+ end;
+ if not f.readln(s) then begin
+ writeln('Unerwartetes Dateiende in '''+Datei+'''!');
+ f.free;
+ exit;
+ end;
+ if leftStr(s,23)<>'length(Verknuepfungen) ' then begin
+ writeln('Syntaxfehler in '''+Datei+'''!');
+ f.free;
+ exit;
+ end;
+ delete(s,1,23);
+ setlength(MD.Verknuepfungen,strtoint(s));
+ for i:=0 to length(MD.Verknuepfungen)-1 do begin
+ if not f.readln(s) then begin
+ writeln('Unerwartetes Dateiende in '''+Datei+'''!');
+ f.free;
+ exit;
+ end;
+ if pos('Verknuepfungen['+inttostr(i)+'] ',s)<>1 then begin
+ writeln('Syntaxfehler in '''+Datei+'''!');
+ f.free;
+ exit;
+ end;
+ delete(s,1,length('Verknuepfungen['+inttostr(i)+'] '));
+ MD.Verknuepfungen[i]:=strToTVerknuepfung(MD.Personen,s);
+ end;
+ if not f.readln(s) then begin
+ writeln('Unerwartetes Dateiende in '''+Datei+'''!');
+ f.free;
+ exit;
+ end;
+ if leftStr(s,24)<>'length(MMInteraktionen) ' then begin
+ writeln('Syntaxfehler in '''+Datei+'''!');
+ f.free;
+ exit;
+ end;
+ delete(s,1,24);
+ setlength(MD.MMInteraktionen,strtoint(s));
+ for i:=0 to length(MD.MMInteraktionen)-1 do begin
+ if not f.readln(s) then begin
+ writeln('Unerwartetes Dateiende in '''+Datei+'''!');
+ f.free;
+ exit;
+ end;
+ if pos('MMInteraktionen['+inttostr(i)+'] ',S)<>1 then begin
+ writeln('Syntaxfehler in '''+Datei+'''!');
+ f.free;
+ exit;
+ end;
+ delete(s,1,length('MMInteraktionen['+inttostr(i)+'] '));
+ MD.MMInteraktionen[i]:=importMMInteraktion(MD.Personen,s);
+ end;
+ if not f.readln(s) then begin
+ writeln('Unerwartetes Dateiende in '''+Datei+'''!');
+ f.free;
+ exit;
+ end;
+ if leftStr(s,24)<>'length(MFInteraktionen) ' then begin
+ writeln('Syntaxfehler in '''+Datei+'''!');
+ f.free;
+ exit;
+ end;
+ delete(s,1,24);
+ setlength(MD.MFInteraktionen,strtoint(s));
+ for i:=0 to length(MD.MFInteraktionen)-1 do begin
+ if not f.readln(s) then begin
+ writeln('Unerwartetes Dateiende in '''+Datei+'''!');
+ f.free;
+ exit;
+ end;
+ if pos('MFInteraktionen['+inttostr(i)+'] ',s)<>1 then begin
+ writeln('Syntaxfehler in '''+Datei+'''!');
+ f.free;
+ exit;
+ end;
+ delete(S,1,length('MFInteraktionen['+inttostr(i)+'] '));
+ MD.MFInteraktionen[i]:=importMFInteraktion(MD.Personen,MD.Familien,s);
+ end;
+ if not f.readln(s) then begin
+ writeln('Unerwartetes Dateiende in '''+Datei+'''!');
+ f.free;
+ exit;
+ end;
+ if leftStr(s,24)<>'length(FFInteraktionen) ' then begin
+ writeln('Syntaxfehler in '''+Datei+'''!');
+ f.free;
+ exit;
+ end;
+ delete(s,1,24);
+ setlength(MD.FFInteraktionen,strtoint(s));
+ for i:=0 to length(MD.FFInteraktionen)-1 do begin
+ if not f.readln(s) then begin
+ writeln('Unerwartetes Dateiende in '''+Datei+'''!');
+ f.free;
+ exit;
+ end;
+ if pos('FFInteraktionen['+inttostr(i)+'] ',s)<>1 then begin
+ writeln('Syntaxfehler in '''+Datei+'''!');
+ f.free;
+ exit;
+ end;
+ delete(s,1,length('FFInteraktionen['+inttostr(i)+'] '));
+ MD.FFInteraktionen[i]:=importFFInteraktion(MD.Familien,s);
+ end;
+ if not f.readln(s) then begin
+ writeln('Unerwartetes Dateiende in '''+Datei+'''!');
+ f.free;
+ exit;
+ end;
+ if leftStr(s,23)<>'length(Tauschfamilien) ' then begin
+ writeln('Syntaxfehler in '''+Datei+'''!');
+ f.free;
+ exit;
+ end;
+ delete(s,1,23);
+ setlength(MD.Tauschfamilien,strtoint(s));
+ for i:=0 to length(MD.Tauschfamilien)-1 do begin
+ if not f.readln(s) then begin
+ writeln('Unerwartetes Dateiende in '''+Datei+'''!');
+ f.free;
+ exit;
+ end;
+ if pos('Tauschfamilien['+inttostr(i)+'] ',s)<>1 then begin
+ writeln('Syntaxfehler in '''+Datei+'''!');
+ f.free;
+ exit;
+ end;
+ delete(s,1,length('Tauschfamilien['+inttostr(i)+'] '));
+ MD.Tauschfamilien[i]:=findeFamilie(MD.Familien,s);
+ end;
+ if not f.readln(s) then begin
+ writeln('Unerwartetes Dateiende in '''+Datei+'''!');
+ f.free;
+ exit;
+ end;
+ if s<>'Ende' then begin
+ writeln('Syntaxfehler in '''+Datei+'''!');
+ f.free;
+ exit;
+ end;
+ if not f.eof then begin
+ writeln('Zu viele Daten in '''+Datei+'''!');
+ f.free;
+ exit;
+ end;
+
+ f.free;
+
+ writeln('... fertig');
+
+ MD.berechneAbhaengigeVariable(Parameter{$IFDEF detaillierteZeitanalyse},true{$ENDIF});
+ Energie:=MD.Energie(Parameter,Kreuzungen,i{$IFDEF detaillierteZeitanalyse},true{$ENDIF});
+ printStatus(7);
+ result:=true;
+end;
+
+function TStabile.SpeichereInDatei(Datei: String): boolean;
+var
+ f: tMyStringList;
+ i: longint;
+ s: string;
+begin
+ result:=not fileexists(Datei);
+ if not result then exit;
+ printStatus(7);
+ write('Speichere in '''+Datei+''' ...');
+ f:=tMyStringList.create;
+ f.add('Stabile-Zwischenzustand (menschenlesbar, aber nicht unbedingt menschenverstehbar)');
+ f.add('Schritte '+inttostr(Schritte));
+ f.add('stepsize '+myfloattostr(stepsize));
+ for I:=0 to 9 do
+ f.add('Stati['+inttostr(I)+'] '+inttostr(byte(NotAus.Stati[I])));
+ write('.');
+ f.add('Laufzeit '+myfloattostr(Laufzeit));
+ f.add('length(Ereignisse) '+inttostr(length(MD.Ereignisse)));
+ for I:=0 to length(MD.Ereignisse)-1 do
+ f.add('Ereignisse['+inttostr(I)+'] '+TEreignisToStr(MD.Ereignisse[I]));
+ write('.');
+ f.add('length(Personen) '+inttostr(length(MD.Personen)));
+ for I:=0 to length(MD.Personen)-1 do
+ f.add('Personen['+inttostr(I)+'] '+TPersonToStr(MD.Personen[I]));
+ write('.');
+ f.add('length(Familien) '+inttostr(length(MD.Familien)));
+ for I:=0 to length(MD.Familien)-1 do
+ f.add('Familien['+inttostr(I)+'] '+TFamilieToStr(MD.Familien[I]));
+ write('.');
+ setlength(s,length(MD.ParameterAttribute));
+ for I:=0 to length(MD.ParameterAttribute)-1 do
+ s[I+1]:=MD.ParameterAttribute[I].toChar;
+ write('.');
+ f.add('Unabhaengig '+s);
+ f.add('length(Parameter) '+inttostr(length(Parameter)));
+ for I:=0 to length(Parameter)-1 do
+ f.add('Parameter['+inttostr(I)+'] '+myfloattostr(Parameter[I]));
+ write('.');
+ f.add('length(Verknuepfungen) '+inttostr(length(MD.Verknuepfungen)));
+ for I:=0 to length(MD.Verknuepfungen)-1 do
+ f.add('Verknuepfungen['+inttostr(I)+'] '+TVerknuepfungToStr(MD.Verknuepfungen[I]));
+ write('.');
+ f.add('length(MMInteraktionen) '+inttostr(length(MD.MMInteraktionen)));
+ for I:=0 to length(MD.MMInteraktionen)-1 do
+ f.add('MMInteraktionen['+inttostr(I)+'] '+TMMInteraktionToStr(MD.MMInteraktionen[I]));
+ write('.');
+ f.add('length(MFInteraktionen) '+inttostr(length(MD.MFInteraktionen)));
+ for I:=0 to length(MD.MFInteraktionen)-1 do
+ f.add('MFInteraktionen['+inttostr(I)+'] '+TMFInteraktionToStr(MD.MFInteraktionen[I]));
+ write('.');
+ f.add('length(FFInteraktionen) '+inttostr(length(MD.FFInteraktionen)));
+ for I:=0 to length(MD.FFInteraktionen)-1 do
+ f.add('FFInteraktionen['+inttostr(I)+'] '+TFFInteraktionToStr(MD.FFInteraktionen[I]));
+ write('.');
+ f.add('length(Tauschfamilien) '+inttostr(length(MD.Tauschfamilien)));
+ for I:=0 to length(MD.Tauschfamilien)-1 do
+ f.add('Tauschfamilien['+inttostr(I)+'] '+PFamilieToStr(MD.Tauschfamilien[I]));
+ write('.');
+ f.add('Ende');
+ f.saveToGz(Datei);
+ writeln(' fertig');
+end;
+
+procedure TStabile.Initialisiere(Anzahl: Longint; Art: string);
+var
+ werDran,extraZufall: tIntArray; // werDran[wannDran[i].x] = i und
+ // wannDran[werDran[j]].x = j
+ wannDran: t4DPointArray; // 2 ^ -wannDran[i].y ist die eigene Sollbeziehungslänge;
+ // wannDrann[i].z ... abhängig von wem?;
+ // wannDran[i].u ...
+ // 0: als Vater abhängig, \
+ // 1: als Mutter abhängig, --> 0 & 1 können _innerhalb_ einer Familie getauscht sein
+ // 2: als Mann abhängig,
+ // 3: als Frau abhängig,
+ // 4: als Nachfahr abhängig
+ //Kreise: array of tPointArray; // x: Person, y: Familie
+ i,j,k,l,m,n,Luecken,Wurzel: longint;
+ Timer: tTimer;
+ gefunden,fertig: boolean;
+ its: array of tStabileInitThread;
+begin
+ Timer:=tTimer.create;
+ Timer.Start;
+ writeln('Initialisiere Parametersatz ...');
+
+ for k:=0 to length(MD.Personen)-1 do
+ MD.Personen[k].Index:=k;
+ for k:=0 to length(MD.Familien)-1 do
+ MD.Familien[k].Index:=k;
+ for k:=0 to length(MD.Ereignisse)-1 do
+ MD.Ereignisse[k].Index:=k;
+
+ if length(Art)=0 then Art:='i';
+ Schritte:=-1;
+ stepsize:=minSchrittweite;
+ setlength(Parameter,MD.ParameterLaenge);
+ Energie:=0;
+ Kreuzungen:=0;
+ for i:=1 to length(Art) do begin
+ if NotAus.istZuende then break;
+ case Art[i] of
+ 'b': begin
+ if (i=1) or (Art[i]<>Art[i-1]) then writeln(' - auf Bäume optimiert:');
+ Wurzel:=-1;
+ Luecken:=length(MD.Personen);
+ for j:=0 to length(MD.Personen)-1 do begin
+ for k:=0 to length(Parameter)-1 do
+ Parameter[k]:=-1;
+ Parameter[MD.Personen[j].P1]:=1;
+ Parameter[MD.Personen[j].P2]:=1;
+ for k:=length(MD.Verknuepfungen)-1 downto 0 do
+ if Parameter[MD.Verknuepfungen[k].Output['x']]>0 then begin
+ Parameter[MD.Verknuepfungen[k].Input[0,'x']]:=1;
+ Parameter[MD.Verknuepfungen[k].Input[0,'y']]:=1;
+ Parameter[MD.Verknuepfungen[k].Input[1,'x']]:=1;
+ Parameter[MD.Verknuepfungen[k].Input[1,'y']]:=1;
+ end;
+ for k:=0 to length(MD.Verknuepfungen)-1 do
+ if (Parameter[MD.Verknuepfungen[k].Input[0,'x']]>0) or
+ (Parameter[MD.Verknuepfungen[k].Input[1,'x']]>0) then begin
+ Parameter[MD.Verknuepfungen[k].Output['x']]:=1;
+ Parameter[MD.Verknuepfungen[k].Output['y']]:=1;
+ Parameter[MD.Verknuepfungen[k].Input[0,'x']]:=1;
+ Parameter[MD.Verknuepfungen[k].Input[0,'y']]:=1;
+ Parameter[MD.Verknuepfungen[k].Input[1,'x']]:=1;
+ Parameter[MD.Verknuepfungen[k].Input[1,'y']]:=1;
+ end;
+ l:=0;
+ for k:=0 to length(MD.Personen)-1 do
+ if Parameter[MD.Personen[k].P1]<0 then
+ inc(l);
+ if (Wurzel=-1) or (l<Luecken) then begin
+ Wurzel:=j;
+ Luecken:=l;
+ end;
+ end;
+ writeln(' ('+
+ MD.Personen[Wurzel].Vorname+' '+
+ MD.Personen[Wurzel].Nachname+
+ ', Lücken: '+inttostr(Luecken)+')');
+(* if Art[i]='i' then begin
+ writeln('Kreise suchen ...');
+ Kreise:=md.findeKreise;
+ writeln('... und '+inttostr(length(Kreise))+' Kreise gefunden!');
+ for j:=0 to length(Kreise)-1 do
+ write(length(Kreise[j]),' ');
+ if length(Kreise)>0 then begin
+ writeln;
+ j:=20;
+ while (not keypressed) and (j>0) do begin
+ sleep(100);
+ dec(j);
+ end;
+ if keypressed then
+ case readkey of
+ #27,'q': halt;
+ #13: begin
+ for j:=0 to length(Kreise)-1 do begin
+ writeln;
+ for k:=0 to length(Kreise[j])-1 do
+ writeln(md.Personen[Kreise[j,k].x].Vorname+' '+md.Personen[Kreise[j,k].x].Nachname+' ('+inttostr(Kreise[j,k].x)+')<--->('+inttostr(Kreise[j,k].y)+') Familie '+md.Familien[Kreise[j,k].y].Eltern[0].Nachname+' ('+md.Familien[Kreise[j,k].y].Eltern[1].Nachname+')');
+ if readkey in [#27,'q'] then halt;
+ end;
+ halt;
+ end;
+ end{of case};
+ end;
+ end; *)
+
+ // Es folgt die Initialisierung von wannDran, werDran und extraZufall
+
+ setlength(extraZufall,0);
+ setlength(werDran,length(MD.Personen));
+ setlength(wannDran,length(MD.Personen));
+ for k:=0 to length(werDran)-1 do begin
+ werDran[k]:=-1;
+ wannDran[k].x:=-1;
+ wannDran[k].y:=-1;
+ wannDran[k].z:=-1;
+ wannDran[k].u:=-1;
+ end;
+ werDran[0]:=Wurzel;
+ wannDran[Wurzel].x:=0;
+ wannDran[Wurzel].y:=2;
+ wannDran[Wurzel].z:=-1;
+ wannDran[Wurzel].u:=-1;
+
+ m:=1;
+ while (m<length(wannDran)) and not NotAus.istZuende do begin // Zweierpotenzen verteilen
+ gefunden:=false;
+ for k:=0 to length(MD.Familien)-1 do // von den Nachfahren zu den Vorfahren
+ with MD.Familien[k] do
+ if (wannDran[Eltern[0].Index].x=-1) and
+ (wannDran[Eltern[1].Index].x=-1) then // beide Elternteile sind noch nicht dran gewesen
+ for l:=0 to length(Kinder)-1 do
+ if wannDran[Kinder[l].Index].x<>-1 then begin // dieses Kind war schon dran
+ if (wannDran[Eltern[0].Index].x<>-1) and
+ (wannDran[Eltern[1].Index].x<>-1) then begin // ein anderes Kind hat die Eltern schon fixiert (relativ selten)
+ if j=1 then
+ writeln('doppelt bestimmt: '+Eltern[0].Vorname+' '+Eltern[0].Nachname+' und '+Eltern[1].Vorname+' '+Eltern[1].Nachname+' -> ['+inttostr(Kinder[l].Index)+'] '+inttostr(wannDran[Kinder[l].Index].x));
+ setlength(extraZufall,length(extraZufall)+1);
+ extraZufall[length(extraZufall)-1]:=Kinder[l].P3;
+ continue;
+ end;
+ for n:=0 to 1 do begin
+ wannDran[Eltern[n].Index].x:=m;
+ wannDran[Eltern[n].Index].y:=wannDran[Kinder[l].Index].y+1; // 1/2 so lang wie das Kind
+ wannDran[Eltern[n].Index].z:=Kinder[l].Index;
+ wannDran[Eltern[n].Index].u:=n;
+ werDran[m]:=Eltern[n].Index;
+ inc(m);
+ end;
+ gefunden:=true;
+ end;
+ if gefunden then continue; // Solange von den Nachfahren zu den Vorfahren was gefunden wurde, wird da auch noch mal gesucht!
+ for k:=0 to length(MD.Familien)-1 do // von den Vorfahren zu den Nachfahren
+ with MD.Familien[k] do
+ if (wannDran[Eltern[0].Index].x<>-1) and
+ (wannDran[Eltern[1].Index].x<>-1) then begin // beide Elternteile sind schon dran gewesen
+ for l:=0 to length(Kinder)-1 do
+ if wannDran[Kinder[l].Index].x=-1 then begin // dieses Kind war noch nicht dran
+ wannDran[Kinder[l].Index].x:=m;
+ wannDran[Kinder[l].Index].y:=max(wannDran[Eltern[0].Index].y,wannDran[Eltern[1].Index].y);
+ wannDran[Kinder[l].Index].z:=k; // nur hier indiziert .z die Familie !!! (ansonsten Personen)
+ wannDran[Kinder[l].Index].u:=4;
+ werDran[m]:=Kinder[l].Index;
+ inc(m);
+ gefunden:=true;
+ break;
+ end;
+ if gefunden then break;
+ end;
+ if gefunden then continue; // Solange von den Vorfahren zu den Nachfahren was gefunden wurde, wird noch mal gesucht!
+ n:=-1;
+ for k:=0 to length(MD.Familien)-1 do // von Partner zu Partner
+ with MD.Familien[k] do
+ if ((wannDran[Eltern[0].Index].x<>-1) xor
+ (wannDran[Eltern[1].Index].x<>-1)) and // genau ein Elternteil schon dran gewesen
+ ((n=-1) or
+ (MD.Familien[n].Anfang.Jahr > Anfang.Jahr)) then // Familie ist älter
+ n:=k;
+ if n<>-1 then
+ with MD.Familien[n] do begin
+ if (wannDran[Eltern[0].Index].x=-1) then begin // Vater noch nicht dran gewesen
+ wannDran[Eltern[0].Index].x:=m;
+ wannDran[Eltern[0].Index].y:=wannDran[Eltern[1].Index].y+1; // 1/2 so lang wie die andere Ehe der Frau
+ wannDran[Eltern[0].Index].z:=Eltern[1].Index;
+ wannDran[Eltern[0].Index].u:=2;
+ werDran[m]:=Eltern[0].Index;
+ gefunden:=true;
+ inc(m);
+ end;
+ if wannDran[Eltern[1].Index].x=-1 then begin // Mutter noch nicht dran gewesen
+ wannDran[Eltern[1].Index].x:=m;
+ wannDran[Eltern[1].Index].y:=wannDran[Eltern[0].Index].y+1; // 1/2 so lang wie die andere Ehe des Mannes
+ wannDran[Eltern[1].Index].z:=Eltern[0].Index;
+ wannDran[Eltern[1].Index].u:=3;
+ werDran[m]:=Eltern[1].Index;
+ gefunden:=true;
+ inc(m);
+ end;
+ end;
+ if gefunden then continue;
+ writeln('*** Fehler *** Manche Personen gehören nicht in die Zusammenhangskomponente der Wurzel!'); // sollte nicht passieren, wurde in ladeXML ggf. korrigiert!
+ for k:=0 to length(MD.Familien)-1 do
+ with MD.Familien[k] do begin
+ gefunden:=false;
+ if (wannDran[Eltern[0].Index].x=-1) or
+ (wannDran[Eltern[1].Index].x=-1) then gefunden:=true;
+ for l:=0 to length(Kinder)-1 do
+ if wannDran[Kinder[l].Index].x=-1 then gefunden:=true;
+ if gefunden then begin
+ writeln('ID: '+ID);
+ writeln(' '+inttostr(wannDran[Eltern[0].Index].x)+' '+Eltern[0].Vorname+' '+Eltern[0].Nachname+' '+inttostr(Eltern[0].Anfang.Jahr));
+ writeln(' '+inttostr(wannDran[Eltern[0].Index].x)+' '+Eltern[1].Vorname+' '+Eltern[1].Nachname+' '+inttostr(Eltern[1].Anfang.Jahr));
+ writeln(' '+inttostr(length(Kinder))+' Kinder');
+ for l:=0 to length(Kinder)-1 do
+ with Kinder[l] do
+ writeln(' '+inttostr(l)+' '+inttostr(wannDran[Index].x)+' '+' '+Vorname+' '+Nachname+' '+inttostr(Anfang.Jahr));
+ writeln;
+ end;
+ end;
+ halt;
+ end;
+
+ for k:=0 to length(wannDran)-1 do
+ if werDran[wannDran[k].x]<>k then begin
+ writeln('Fehler: werDran[wannDran['+inttostr(k)+'].x]<>'+inttostr(k));
+ halt;
+ end;
+ for k:=0 to length(werDran)-1 do
+ if wannDran[werDran[k]].x<>k then begin
+ writeln('Fehler: wannDran[werDran['+inttostr(k)+']].x<>'+inttostr(k));
+ halt;
+ end;
+ end;
+ 'M': if (i=1) or (Art[i]<>Art[i-1]) then writeln(' - zufällig:');
+ else begin
+ writeln('Den Parameter '''+Art[i]+''' kenne ich nicht!');
+ exit;
+ end;
+ end{of Case};
+
+ setlength(its,max(2,momentanFreieCpus-1));
+ for j:=0 to length(its)-1 do
+ its[j]:=tStabileInitThread.create(self,werDran,extraZufall,wannDran,Art[i],(Anzahl div length(its)) + (Anzahl mod length(its))*byte(j=length(its)));
+
+ for j:=0 to length(its)-1 do
+ its[j].suspended:=false;
+
+ repeat
+ sleep(10);
+ fertig:=true;
+ for j:=0 to length(its)-1 do
+ fertig:=fertig and its[j].fertig;
+ until fertig;
+
+ if not NotAus.istZuende then begin
+ k:=0;
+ for j:=1 to length(its)-1 do
+ if (its[j].Kreuzungen<its[k].Kreuzungen) or
+ ((its[j].Kreuzungen=its[k].Kreuzungen) and
+ (its[j].Energie<its[k].Energie)) then
+ k:=j;
+
+ Energie:=its[k].Energie;
+ Kreuzungen:=its[k].Kreuzungen;
+ for j:=0 to length(Parameter)-1 do
+ Parameter[j]:=its[k].Parameter[j];
+ end;
+
+ for j:=0 to length(its)-1 do
+ its[j].free;
+ setlength(its,0);
+ end;
+ writeln('... fertig');
+ Laufzeit:=Laufzeit+Timer.gibZeit;
+ Timer.free;
+end;
+
+procedure TStabile.optimiere;
+var
+ Timer: TTimer;
+ i,j,k,NKreuzung,Kreuzung,NK: longint;
+ c: char;
+ NP,Richtung: TExtendedArray;
+ abhaengiges: TBooleanArray;
+ Perm: TIntArray;
+ Ax,Ay,Rx,Ry,tmp,sz,gesamtSchritt: extended;
+ echtePermutation,wasGefunden,TauschenErlauben: boolean;
+begin
+ Timer:=tTimer.create;
+ Timer.Start;
+ writeln('Starte Optimierung ...');
+ setlength(abhaengiges,MD.ParameterLaenge);
+ setlength(NP,MD.ParameterLaenge);
+ setlength(Richtung,MD.ParameterLaenge);
+ TauschenErlauben:=true;
+ Kreuzung:=-1;
+ NKreuzung:=-1;
+ while not NotAus.istZuende do
+ begin
+ inc(Schritte);
+ stepsize:=max(minSchrittweite,stepsize/power(schrittweitenmultiplikator,sollABAnteil));
+ for c:='a' to 'f' do
+ begin
+ if NotAus.istZuende then break;
+ case c of
+ 'a':
+ begin
+ for I:=0 to length(NP)-1 do
+ if random*SchrittweitenSchwelle < stepSize then
+ NP[I]:=min(1,max(0,Parameter[I]+max(stepsize,SchrittweitenSchwelle)*(random-0.5)));
+ end;
+ 'b':
+ begin
+ for I:=0 to length(NP)-1 do
+ begin
+ tmp:=NP[I]-Parameter[I];
+ NP[I]:=min(1,max(0,Parameter[I]-tmp));
+ end;
+ end;
+ 'c'..'f':
+ begin
+ if (Kreuzungen=0) or not TauschenErlauben then continue;
+ for I:=0 to length(NP)-1 do
+ abhaengiges[I]:=false;
+ for I:=0 to 1 do begin
+ abhaengiges[MD.FFInteraktionen[Kreuzung]._Fs[I].Eltern[WenTauschen[ord(C)-ord('c'),I]].P1]:=true;
+ abhaengiges[MD.FFInteraktionen[Kreuzung]._Fs[I].Eltern[WenTauschen[ord(C)-ord('c'),I]].P2]:=true;
+ end;
+ repeat
+ wasGefunden:=false;
+ for I:=0 to length(MD.Verknuepfungen)-1 do
+ if (abhaengiges[MD.Verknuepfungen[I].Output['x']] or
+ abhaengiges[MD.Verknuepfungen[I].Output['y']]) and
+ not abhaengiges[MD.Verknuepfungen[I].Input[0,'x']] then begin
+ wasGefunden:=true;
+ abhaengiges[MD.Verknuepfungen[I].Input[0,'x']]:=true;
+ abhaengiges[MD.Verknuepfungen[I].Input[0,'y']]:=true;
+ abhaengiges[MD.Verknuepfungen[I].Input[1,'x']]:=true;
+ abhaengiges[MD.Verknuepfungen[I].Input[1,'y']]:=true;
+ end;
+ until not wasGefunden;
+ Ax:=
+ (Parameter[MD.FFInteraktionen[Kreuzung]._Fs[0].Eltern[WenTauschen[ord(C)-ord('c'),0]].P1]+
+ Parameter[MD.FFInteraktionen[Kreuzung]._Fs[1].Eltern[WenTauschen[ord(C)-ord('c'),1]].P1]);
+ Ay:=
+ (Parameter[MD.FFInteraktionen[Kreuzung]._Fs[0].Eltern[WenTauschen[ord(C)-ord('c'),0]].P2]+
+ Parameter[MD.FFInteraktionen[Kreuzung]._Fs[1].Eltern[WenTauschen[ord(C)-ord('c'),1]].P2]);
+ Rx:=
+ (Parameter[MD.FFInteraktionen[Kreuzung]._Fs[0].Eltern[WenTauschen[ord(C)-ord('c'),0]].P2]-
+ Parameter[MD.FFInteraktionen[Kreuzung]._Fs[1].Eltern[WenTauschen[ord(C)-ord('c'),1]].P2]);
+ Ry:=
+ (Parameter[MD.FFInteraktionen[Kreuzung]._Fs[1].Eltern[WenTauschen[ord(C)-ord('c'),1]].P1]-
+ Parameter[MD.FFInteraktionen[Kreuzung]._Fs[0].Eltern[WenTauschen[ord(C)-ord('c'),0]].P1]);
+ tmp:=sqrt(sqr(Rx)+sqr(Ry));
+ Rx:=Rx/max(epsilon,tmp);
+ Ry:=Ry/max(epsilon,tmp);
+ for I:=0 to length(Parameter)-1 do
+ NP[I]:=Parameter[I];
+ for I:=0 to length(MD.Personen)-1 do
+ if abhaengiges[MD.Personen[I].P1] then begin
+ tmp:=(Rx * (Ax - NP[MD.Personen[I].P1]) + Ry * (Ay - NP[MD.Personen[I].P2]));
+ NP[MD.Personen[I].P1]:=
+ NP[MD.Personen[I].P1] + Rx * tmp;
+ NP[MD.Personen[I].P2]:=
+ NP[MD.Personen[I].P2] + Ry * tmp; // eine Spiegelung an der Geraden durch A[x,y], senkrecht zu R[x,y]
+(* tmp:=
+ Ax
+ + 2*((NP[MD.Personen[I].P1]-Ax)*Rx + (NP[MD.Personen[I].P2]-Ay)*Ry)*Rx
+ - (NP[MD.Personen[I].P1]-Ax);
+ NP[MD.Personen[I].P2]:=
+ Ay
+ + 2*((NP[MD.Personen[I].P1]-Ax)*Rx + (NP[MD.Personen[I].P2]-Ay)*Ry)*Ry
+ - (NP[MD.Personen[I].P2]-Ay); *)
+ NP[MD.Personen[I].P1]:=tmp;
+// NP[MD.Personen[I].P1]:=min(1,max(0,NP[MD.Personen[I].P1]));
+// NP[MD.Personen[I].P2]:=min(1,max(0,NP[MD.Personen[I].P2]));
+ if (NP[MD.Personen[I].P1]<0) or (NP[MD.Personen[I].P1]>1) or
+ (NP[MD.Personen[I].P2]<0) or (NP[MD.Personen[I].P2]>1) then begin
+ ax:=NP[MD.Personen[I].P1];
+ ay:=NP[MD.Personen[I].P2];
+ rx:=ax;
+ ry:=ay;
+ for j:=0 to length(MD.Personen)-1 do
+ if MD.Parameterattribute[MD.Personen[j].P1].istUnabhaengig then begin
+ ax:=min(ax,NP[MD.Personen[j].P1]);
+ ay:=min(ay,NP[MD.Personen[j].P2]);
+ rx:=max(rx,NP[MD.Personen[j].P1]);
+ ry:=max(ry,NP[MD.Personen[j].P2]);
+ end;
+ rx:=1/max(rx-ax,epsilon);
+ ry:=1/max(ry-ay,epsilon);
+ for j:=0 to length(MD.Personen)-1 do begin
+ NP[MD.Personen[j].P1]:=(NP[MD.Personen[j].P1]-ax)*rx;
+ NP[MD.Personen[j].P2]:=(NP[MD.Personen[j].P2]-ay)*ry;
+ end;
+ end;
+ abhaengiges[MD.Personen[I].P1]:=false;
+ abhaengiges[MD.Personen[I].P2]:=false;
+ end;
+ end;
+ 'g'..'z':
+ begin
+ TauschenErlauben:=Kreuzungen>100;
+ if length(MD.Tauschfamilien)=0 then break;
+ for I:=0 to length(Parameter)-1 do
+ NP[I]:=Parameter[I];
+ I:=Random(length(MD.Tauschfamilien));
+ if odd(ord(c)-ord('g')) then
+ begin //nur zwei permutieren
+ J:=random(length(MD.Tauschfamilien[I].Kinder));
+ K:=random(length(MD.Tauschfamilien[I].Kinder)-1);
+ K:=K+Byte(K>=J);
+ NP[MD.Personen[J].P3]:=Parameter[MD.Personen[K].P3];
+ NP[MD.Personen[K].P3]:=Parameter[MD.Personen[J].P3];
+ echtePermutation:=false;
+ end
+ else
+ begin //beliebige Permutation
+ Perm:=Permutation(length(MD.Tauschfamilien[I].Kinder));
+ J:=0;
+ for K:=0 to length(Perm)-1 do
+ J:=J+Byte(Perm[K]<>K);
+ echtePermutation:=J>2;
+ for K:=0 to length(Perm)-1 do
+ NP[MD.Tauschfamilien[I].Kinder[Perm[K]].P3]:=
+ Parameter[MD.Tauschfamilien[I].Kinder[K].P3];
+ end;
+ end;
+ end{of case};
+ MD.berechneAbhaengigeVariable(NP{$IFDEF detaillierteZeitanalyse},true{$ENDIF});
+ tmp:=MD.Energie(NP,NK,NKreuzung{$IFDEF detaillierteZeitanalyse},true{$ENDIF});
+ if Kreuzung<0 then
+ Kreuzung:=NKreuzung;
+ if (c in ['a'..'b']) and NotAus.Stati[6] then
+ writeln('6) '+c+' ',tmp,' ',NK,' Kreuzungen (',stepsize,')');
+ if
+ (Kreuzungen>NK) or
+ ((tmp<Energie) and
+ (Kreuzungen=NK)) then
+ begin
+ TauschenErlauben:=true;
+ Energie:=tmp;
+ Kreuzungen:=NK;
+ Kreuzung:=NKreuzung;
+ if (c<='b') and ((exp(Kreuzungen)-1)*random<=Byte(Kreuzungen<4)) then
+ begin
+ for I:=0 to length(Parameter)-1 do
+ begin
+ Richtung[I]:=NP[I]-Parameter[I];
+ Parameter[I]:=NP[I];
+ end;
+ sz:=1;
+ j:=0;
+ gesamtSchritt:=1;
+ repeat
+ for I:=0 to length(Parameter)-1 do
+ NP[I]:=Parameter[I]+sz*Richtung[I];
+ MD.berechneAbhaengigeVariable(NP{$IFDEF detaillierteZeitanalyse},true{$ENDIF});
+ tmp:=MD.Energie(NP,NK,NKreuzung{$IFDEF detaillierteZeitanalyse},true{$ENDIF});
+ if
+ (Kreuzungen>NK) or
+ ((tmp<Energie) and
+ (Kreuzungen=NK)) then
+ begin
+ inc(j);
+ TauschenErlauben:=true;
+ Energie:=tmp;
+ Kreuzungen:=NK;
+ Kreuzung:=NKreuzung;
+ for I:=0 to length(Parameter)-1 do
+ Parameter[I]:=NP[I];
+ gesamtSchritt:=gesamtSchritt+sz;
+ sz:=sz*1.2;
+ end
+ else
+ sz:=-sz/1.05;
+ until (abs(sz)<0.1) or NotAus.istZuende;
+ if NotAus.Stati[8] then
+ begin
+ write('8) '+inttostr(j)+' fach optimiert, insgesamt Faktor '+myfloattostr(gesamtSchritt)+' ');
+ j:=0;
+ for I:=0 to length(Richtung)-1 do
+ j:=j+Byte(Richtung[I]<>0);
+ writeln(inttostr(j)+'/'+inttostr(MD.ParameterLaenge)+' Parameter variiert');
+ end;
+ end
+ else
+ begin
+ for I:=0 to length(Parameter)-1 do
+ Parameter[I]:=NP[I];
+ end;
+ if NotAus.Stati[7] then
+ begin
+ write(char(ord(c)+(ord('A')-ord('a'))*Byte((c>='g') and echtePermutation)));
+ printStatus(7);
+ end;
+ printStatus(5);
+ if C<='b' then
+ stepsize:=min(0.5,stepsize*schrittweitenmultiplikator);
+ NotAus.istZuende;
+ break;
+ end;
+ if NotAus.istZuende then break;
+ end;
+ end;
+ Laufzeit:=Laufzeit+Timer.gibZeit;
+ Timer.free;
+end;
+
+procedure tStabile.downHillSimplex;
+var
+ Timer: tTimer;
+ off,tol,i,cnt,aPos: longint;
+ c: char;
+ erg: tSchrittErgebnis;
+ np: tExtendedArray;
+ mi,ma: extended;
+ Simplex: tParameterSimplex;
+const
+ startCnt = 100;
+begin
+ if notAus.istZuende then exit;
+ Timer:=tTimer.create;
+ Timer.Start;
+
+ writeln('Unabhängige Parameter normieren ...');
+ mi:=1;
+ ma:=0;
+ for i:=0 to md.ParameterLaenge-1 do
+ if md.Parameterattribute[i].istKoordinate and md.Parameterattribute[i].istUnabhaengig then begin
+ mi:=min(mi,Parameter[i]);
+ ma:=max(ma,Parameter[i]);
+ end;
+ ma:=0.5/(ma-mi);
+ mi:=mi - 0.25/ma;
+ for i:=0 to md.ParameterLaenge-1 do
+ if md.Parameterattribute[i].istKoordinate and md.Parameterattribute[i].istUnabhaengig then
+ Parameter[i]:=(Parameter[i]-mi)*ma;
+ writeln('... fertig');
+
+ writeln('Simplex initialisieren ...');
+ Simplex:=tParameterSimplex.create;
+ Simplex.md:=md;
+ Simplex.init(Parameter,max(1,momentanFreieCpus-1));
+ writeln('... fertig');
+ Simplex.printHistogramm;
+
+ cnt:=0;
+ off:=0;
+ c:='-';
+ tol:=10;
+ setlength(np,Simplex.pDim);
+ while not NotAus.istZuende do begin
+
+(* if Simplex.maxKreuzungen-Simplex.minKreuzungen>2 then begin
+ Simplex.printSpur('test.txt',Simplex.Reihenfolge[length(Simplex.Reihenfolge)-1],Simplex.Reihenfolge[0]);
+ Simplex.printHistogramm;
+ halt;
+ end; *)
+
+ aPos:=Simplex.Reihenfolge[Simplex.dim-off];
+ erg:=Simplex.SimplexSchritt(np,1,-0.2,1.1,1.25,off);
+ if (false and (cnt<=0.9*startCnt) and erg.besserAlsVorher) or (cnt<-startCnt) then begin
+ write(c+' '+inttostr(aPos)+'. Ecke ('+inttostr(off+1)+'. von hinten) ver');
+ if erg.besserAlsVorher then write('bess')
+ else write('schlecht');
+ write('ert');
+ if erg.Platzveraenderung<>0 then write(' ('+inttostr(erg.Platzveraenderung)+' Plätze)');
+ if erg.faktorNeutralisiert then write(' (Faktor neutralisiert)');
+ writeln(' '+inttostr(Simplex.minKreuzungen)+'..'+inttostr(Simplex.maxKreuzungen)+' Kreuzungen, Energie: '+myfloattostr(Simplex.minEnergie)+'..'+myfloattostr(Simplex.maxEnergie)+' Kantenlänge: '+myfloattostr(Simplex.mittlereKantenlaenge));
+ Simplex.printHistogramm;
+ cnt:=startCnt;
+ end;
+ dec(cnt);
+ case NotAus.lastKey of
+ 'v': begin
+ writeln('mittlere Simplex-Kantenlänge: '+myfloattostr(Simplex.mittlereKantenlaenge));
+ NotAus.lastKey:=#0;
+ end;
+ {$IFDEF detaillierteZeitanalyse}
+ 't': begin
+ writeln('Zeiten: ');
+ md.printTimer(' ');
+ NotAus.lastKey:=#0;
+ end;
+ {$ENDIF}
+ 'a': begin
+ cpuUtilization;
+ NotAus.lastKey:=#0;
+ write('Soll ich den Simplex neu an der beseten Ecke ausrichten? (j/n) ');
+ c:=readkey;
+ while not (c in ['j','J','n','N']) do begin
+ writeln;
+ writeln(''''+c+''' verstehe ich nicht, aber ich wiederhole die Frage gerne noch einmal:');
+ write('Soll ich den Simplex neu an der beseten Ecke ausrichten? (j/n) ');
+ c:=readkey;
+ end;
+ writeln;
+ if c in ['j','J'] then begin
+ writeln('Neu ausrichten ...');
+ Simplex.outit(Parameter);
+ Simplex.init(Parameter,max(1,momentanFreieCpus-1));
+ writeln('... fertig');
+ Simplex.printHistogramm;
+ end;
+ end;
+ 'm': begin
+ NotAus.lastKey:=#0;
+ writeln('belegter Speicher: '+inttostr(belegterSpeicher)+' kB');
+ end;
+ end{of case};
+ if (erg.Platzveraenderung>0) or (off>Simplex.dim-2) then begin // Platz gut gemacht, wir arbeiten uns von unten wieder hoch
+ tol:=10;
+ off:=0;
+ end
+ else if erg.Platzveraenderung<0 then // Platz verloren, wir füllen die Toleranz neu
+ tol:=10
+ else if erg.besserAlsVorher then begin // verbessert, aber kein Platz gut gemacht, Toleranz wird decrementiert
+ dec(tol);
+ if tol<=0 then begin
+ tol:=10;
+ inc(off);
+ end;
+ end
+ else begin // verschlechtert ohne Platzverlust, wir optimieren am nächsten rum
+ tol:=10;
+ inc(off);
+ end;
+ case c of
+ '-': c:='/';
+ '/': c:='|';
+ '|': c:='\';
+ '\': c:='-';
+ end;
+ end;
+ setlength(np,0);
+ Simplex.outit(Parameter); // Fortschritt auf Stabile übertragen
+
+ Simplex.free;
+ Laufzeit:=Laufzeit+Timer.gibZeit;
+ Timer.free;
+end;
+
+procedure tStabile.gradientenOptimierung;
+var
+ Timer: tTimer;
+ Gradient,step,alt,ganzAlt,semiAlt: tExtendedArray;
+ mi,ma,aEner,ener,gaEner,phi,tmp: extended;
+ i,aKrzgn,krzgn,gaKrzgn,
+ ocnt,cnt,gut,schlecht: longint;
+ vkn: tVerknuepfung;
+ modus,baMod: byte; // 0 = nur Eltern[0] einzufügen; 1 = nur Eltern[1] einzufügen; 2 = beide Eltern einzufügen; 3 = Kind einzufügen
+ neuP: tPerson;
+ neuF: tFamilie;
+(*
+ j: longint;
+ f: textfile; *)
+begin
+ if notAus.istZuende then exit;
+ Timer:=tTimer.create;
+ Timer.Start;
+
+ writeln('Unabhängige Parameter normieren ...');
+ mi:=1;
+ ma:=0;
+ for i:=0 to md.ParameterLaenge-1 do
+ if md.Parameterattribute[i].istKoordinate and
+ md.Parameterattribute[i].wirdBenutzt then begin
+ mi:=min(mi,Parameter[i]);
+ ma:=max(ma,Parameter[i]);
+ end;
+ ma:=0.5/(ma-mi);
+ mi:=mi - 0.25/ma;
+ for i:=0 to md.ParameterLaenge-1 do
+ if md.Parameterattribute[i].istKoordinate and
+ md.Parameterattribute[i].wirdBenutzt then
+ Parameter[i]:=(Parameter[i]-mi)*ma;
+ writeln('... fertig');
+
+ setlength(step,md.ParameterLaenge);
+ setlength(Gradient,md.ParameterLaenge);
+ setlength(alt,md.ParameterLaenge);
+
+ md.berechneAbhaengigeVariable(Parameter);
+ aEner:=md.Energie(Parameter,aKrzgn,i);
+
+ gaEner:=aEner;
+ gaKrzgn:=aKrzgn;
+ setlength(ganzAlt,length(Parameter));
+ setlength(semiAlt,length(Parameter));
+ for i:=0 to length(ganzAlt)-1 do begin
+ ganzAlt[i]:=Parameter[i];
+ semiAlt[i]:=Parameter[i];
+ end;
+
+(* md.Gradient(Parameter,Gradient);
+ md.GradientenRueckPropagation(Parameter,Gradient);
+
+ assignfile(f,'test.txt');
+ rewrite(f);
+ for i:=0 to md.Unabhaengig-1 do begin
+ if i<>0 then write(f,#9);
+ write(f,myfloattostr(Parameter[i]));
+ end;
+ writeln(f);
+ for i:=0 to md.Unabhaengig-1 do begin
+ if i<>0 then write(f,#9);
+ write(f,myfloattostr(Gradient[i]));
+ end;
+ writeln(f);
+ setlength(Gradient,length(Parameter));
+ for i:=-1 to md.Unabhaengig-1 do begin
+ for j:=0 to md.Unabhaengig-1 do
+ Gradient[j]:=Parameter[j]+1e-10*byte(i=j);
+ md.berechneAbhaengigeVariable(Gradient);
+ ener:=md.Energie(Gradient,krzgn,j);
+ write(f,myfloattostr(ener));
+ for j:=0 to md.Unabhaengig-1 do
+ write(f,#9+myfloattostr(Gradient[j]));
+ writeln(f);
+ end;
+
+ closefile(f);
+
+ halt; *)
+
+ baMod:=0;
+
+ repeat
+
+ cnt:=100;
+ gut:=0;
+ schlecht:=0;
+ ocnt:=3;
+
+ if baMod=1 then write('-');
+
+ while (not NotAus.istZuende) and ((baMod=2) or (aKrzgn>0) or (ocnt>0)) do begin
+ if (baMod=1) and
+ (aKrzgn>0) then write('!');
+
+ if baMod<=1 then begin
+ if aKrzgn=0 then
+ dec(ocnt)
+ else
+ ocnt:=3;
+ end;
+
+ md.Gradient(Parameter,Gradient);
+ md.GradientenRueckPropagation(Parameter,Gradient);
+
+ ma:=0;
+ for i:=0 to md.ParameterLaenge-1 do
+ if md.Parameterattribute[i].istUnabhaengig then
+ ma:=ma + sqr(Gradient[i]);
+ ma:=-stepsize/sqrt(ma);
+ tmp:=2*stepsize/(1+99*byte(baMod<>2));
+
+ for i:=0 to md.ParameterLaenge-1 do begin
+ alt[i]:=Parameter[i];
+ if md.Parameterattribute[i].istUnabhaengig then begin
+ step[i]:=Gradient[i]*ma + tmp*(random-0.5);
+ Parameter[i]:=min(1,max(0,Parameter[i]+step[i]));
+ end;
+ end;
+
+ md.berechneAbhaengigeVariable(Parameter);
+ ener:=md.Energie(Parameter,Krzgn,i);
+
+ if (krzgn>aKrzgn) or ((krzgn=aKrzgn) and (ener>aEner)) then begin
+ inc(schlecht);
+ if (0.5*stepsize<minSchrittweite) and
+ ((krzgn=0) or (baMod=2)) then begin
+ write('X');
+ aEner:=ener;
+ aKrzgn:=krzgn;
+ if stepsize=minSchrittweite then
+ break;
+ stepsize:=minSchrittweite;
+ end
+ else
+ for i:=0 to md.ParameterLaenge-1 do
+ Parameter[i]:=alt[i];
+ stepsize:=max(stepsize*0.5,minSchrittweite);
+ end
+ else begin
+ inc(gut);
+ stepsize:=min(stepsize*1.2,0.5);
+ aEner:=ener;
+ aKrzgn:=krzgn;
+ end;
+ dec(cnt);
+ if cnt<0 then begin
+ tmp:=0;
+ for i:=0 to length(ganzAlt)-1 do
+ tmp:=tmp+sqr(ganzAlt[i]-Parameter[i]);
+ write(' '+inttostr(aKrzgn)+' & '+myfloattostr(aEner)+' ('+myfloattostr(stepsize)+' '+inttostr(gut)+'/'+inttostr(schlecht)+' = '+myfloattostr(gut/(gut+schlecht))+') '+inttostr(gaKrzgn-aKrzgn)+' & '+myfloattostr(gaEner-aEner)+' <- '+myfloattostr(sqrt(tmp))+' / ');
+ tmp:=0;
+ for i:=0 to length(semiAlt)-1 do begin
+ tmp:=tmp+sqr(semiAlt[i]-Parameter[i]);
+ semiAlt[i]:=Parameter[i];
+ end;
+ writeln(myfloattostr(sqrt(tmp)));
+ gut:=0;
+ schlecht:=0;
+ cnt:=100;
+ end;
+ end;
+
+ if baMod=1 then begin
+ writeln(inttostr(aKrzgn)+' & '+myfloattostr(aEner)+' ('+myfloattostr(stepsize)+' '+inttostr(gut)+'/'+inttostr(schlecht)+' = '+myfloattostr(gut/(gut+schlecht))+')');
+ writeln(' '+inttostr(length(md.Laubhaufen))+' '+inttostr(md.anzUnbenutzt)+'/'+inttostr(md.ParameterLaenge));
+ end;
+
+ if NotAus.istZuende then continue;
+
+ if baMod=0 then begin
+ writeln('Alle Kreuzungen entfernt, füge den Rest wieder ein ...');
+ inc(baMod);
+ end;
+ if (baMod=1) and
+ ((not assigned(md.sicherung)) or
+ (length(md.Laubhaufen)=0)) then begin
+ writeln('Ursprünglicher Graph wieder hergestellt, optimiere noch weiter ...');
+ inc(baMod);
+ end;
+
+ if baMod=1 then begin
+ md.letztesBlattWiederAnkleben(vkn,neuP);
+
+ if not (assigned(vkn) or assigned(neuP)) then begin
+ writeln('*** Fehler ***');
+ writeln('Beim Einfügen des Blattes weder Person noch Verknüpfung zurückgegeben!');
+ halt;
+ end;
+
+ neuF:=nil;
+ if assigned(vkn) then begin
+ if assigned(neuP) then modus:=3 // Kind (=neuP) einzufügen
+ else begin
+ modus:=2; // beide Eltern einzufügen
+ neuP:=vkn.outP; // das Kind der Verknüpfung merken
+ end;
+ end
+ else begin
+ neuF:=neuP.elterVonFamilie(0);
+ if neuF<>nil then modus:=0
+ else begin
+ neuF:=neuP.elterVonFamilie(1);
+ if neuF<>nil then modus:=1
+ else begin
+ writeln('*** Fehler ***');
+ writeln('Verknüfpung nicht zugewiesen, aber Person ist auch kein Elter einer bekannten Familie!');
+ halt;
+ end;
+ end;
+ end;
+
+ case modus of
+ 0,1: begin
+ mi:=1;
+ if assigned(neuF.Eltern[1-modus].KindIn) then // minimale Familienlänge der Familie finden, in der neuF.Eltern[1-modus] Kind ist
+ mi:=min(mi,QAbstand(Parameter,neuF.Eltern[1-modus].KindIn.Eltern[0],neuF.Eltern[1-modus].KindIn.Eltern[1]));
+ for i:=0 to length(neuF.Eltern[1-modus].ElterIn)-1 do // minimale Familienlänge der Familie finden, in der neuF.Elter[1-modus] Elter ist
+ if neuF.Eltern[1-modus].ElterIn[i]<>neuF then // und die nicht selbst die neue Familie ist
+ mi:=min(mi,QAbstand(Parameter,neuF.Eltern[1-modus].ElterIn[i].Eltern[0],neuF.Eltern[1-modus].ElterIn[i].Eltern[1]));
+ mi:=sqrt(mi);
+ end;
+ 2: begin
+ mi:=1;
+ for i:=0 to length(neuP.ElterIn)-1 do // minimale Familienlänge der Kindfamilien finden
+ mi:=min(mi,QAbstand(Parameter,neuP.ElterIn[i].Eltern[0],neuP.ElterIn[i].Eltern[1]));
+ mi:=sqrt(mi);
+ end;
+ end{of case};
+
+ cnt:=100;
+
+ repeat
+ dec(cnt);
+ if cnt<0 then begin
+ cnt:=100;
+ write('-');
+ end;
+ case modus of
+ 0,1: begin
+ phi:=2*pi*random; // der Winkel der neuen Familie
+ ma:=(0.1+0.8*random)*mi; // die Länge der neuen Familie
+ Parameter[neuP.p1]:=Parameter[neuF.Eltern[1-modus].p1] + ma*cos(phi);
+ Parameter[neuP.p2]:=Parameter[neuF.Eltern[1-modus].p2] + ma*sin(phi);
+ end;
+ 2: begin
+ phi:=2*pi*random; // der Winkel der neuen Familie
+ Parameter[vkn.Lambda]:=0.1+0.8*random; // Lambda des alten Kindes in der neuen Familie
+ ma:=(0.1+0.8*random)*mi; // die Länge der neuen Familie
+ Parameter[vkn.input[0,'x']]:=
+ Parameter[vkn.output['x']] - ma*Parameter[vkn.Lambda]*cos(phi);
+ Parameter[vkn.input[0,'y']]:=
+ Parameter[vkn.output['y']] - ma*Parameter[vkn.Lambda]*sin(phi);
+
+ Parameter[vkn.input[1,'x']]:=
+ Parameter[vkn.output['x']] - ma*(Parameter[vkn.Lambda]-1)*cos(phi);
+ Parameter[vkn.input[1,'y']]:=
+ Parameter[vkn.output['y']] - ma*(Parameter[vkn.Lambda]-1)*sin(phi);
+ end;
+ 3:
+ Parameter[vkn.Lambda]:=0.1+0.8*random; // Lambda des neuen Kindes
+ end{of case};
+
+ md.berechneAbhaengigeVariable(Parameter);
+ md.Energie(Parameter,aKrzgn,i);
+ until (aKrzgn=0) or NotAus.istZuende;
+ end;
+
+ until NotAus.istZuende;
+
+ setlength(gradient,0);
+ setlength(alt,0);
+ setlength(step,0);
+ Laufzeit:=Laufzeit+Timer.gibZeit;
+ Timer.free;
+end;
+
+// tEnergieThread **************************************************************
+
+constructor tEnergieThread.create(s: tParameterSimplex; von,bis: longint; psBerechnen: boolean);
+begin
+ inherited create(true);
+ _s:=s;
+ _von:=von;
+ _bis:=bis;
+ bp:=psBerechnen;
+ fertig:=false;
+ freeonterminate:=false;
+ suspended:=false;
+end;
+
+destructor tEnergieThread.destroy;
+begin
+ inherited destroy;
+end;
+
+procedure tEnergieThread.execute;
+var i: longint;
+begin
+ for i:=_von to _bis do begin
+ if bp then
+ _s.berechneAbhaengigeVariable(i{$IFDEF detaillierteZeitanalyse},false{$ENDIF});
+ _s.berechneEnergie(i{$IFDEF detaillierteZeitanalyse},false{$ENDIF});
+ if (_bis-i) mod ((_bis-_von) div 10) = 0 then
+ write('.');
+ end;
+ fertig:=true;
+end;
+
+
+// tStabileInitThread **********************************************************
+
+constructor tStabileInitThread.create(s: tStabile; werDran,extraZufall: tIntArray; wannDran: t4DPointArray; art: char; anzahl: longint);
+begin
+ inherited create(true);
+ _s:=s;
+ setlength(_werDran,length(werDran));
+ if length(_werDran)>0 then
+ move(werDran[0],_werDran[0],length(_werDran)*sizeof(_werDran[0]));
+ setlength(_wannDran,length(wannDran));
+ if length(_wannDran)>0 then
+ move(wannDran[0],_wannDran[0],length(_wannDran)*sizeof(_wannDran[0]));
+ setlength(_extraZufall,length(extraZufall));
+ if length(_extraZufall)>0 then
+ move(extraZufall[0],_extraZufall[0],length(_extraZufall)*sizeof(_extraZufall[0]));
+ _art:=art;
+ _anzahl:=anzahl;
+ _mt:=tMersenneTwister.Create;
+ _mt.init(random(high(longword)));
+ Kreuzungen:=-1;
+ Energie:=-1;
+ setlength(Parameter,length(_s.Parameter));
+ fertig:=false
+end;
+
+destructor tStabileInitThread.destroy;
+begin
+ _s:=nil;
+ _mt.free;
+ setlength(_werDran,0);
+ setlength(_wannDran,0);
+ setlength(_extraZufall,0);
+ inherited destroy;
+end;
+
+procedure tStabileInitThread.execute;
+var
+ i,j,k,l,m,NK,zufallMerker: longint;
+ NP: TExtendedArray;
+ tmp,Ax,Ay,Rx,Ry: extended;
+begin
+ setlength(NP,_s.MD.ParameterLaenge);
+
+ for j:=0 to length(NP)-1 do
+ NP[j]:=-1;
+
+ for i:=1 to max(1,_Anzahl) do begin
+ zufallMerker:=0;
+ case _Art of
+ 'b': begin
+ if _s.NotAus.istZuende then break;
+ for j:=0 to length(_extraZufall)-1 do
+ NP[_extraZufall[j]]:=_mt.random;
+ for j:=0 to length(_werDran)-1 do
+ case _wannDran[_werDran[j]].u of
+ -1: begin // die Wurzel
+ NP[_s.MD.Personen[_werDran[j]].P1]:=0.5+0.01*_mt.random;
+ NP[_s.MD.Personen[_werDran[j]].P2]:=0.5+0.01*_mt.random;
+ end;
+ 0,1: begin // als +/- Vorfahr abhängig,
+ if _wannDran[_werDran[j]].u=0 then
+ zufallMerker:=2*_mt.random(2)-1 // + oder -
+ else
+ zufallMerker:=-zufallMerker; // - oder +
+
+ NP[_s.MD.Personen[_werDran[j]].P1]:=NP[_s.MD.Personen[_wannDran[_werDran[j]].z].P1] + zufallMerker*power(2,-(_wannDran[_werDran[j]].y div 2)-1)*byte(odd(_wannDran[_werDran[j]].y));
+ NP[_s.MD.Personen[_werDran[j]].P2]:=NP[_s.MD.Personen[_wannDran[_werDran[j]].z].P2] + zufallMerker*power(2,-(_wannDran[_werDran[j]].y div 2)-1)*byte(not odd(_wannDran[_werDran[j]].y));
+ NP[_s.MD.Personen[_wannDran[_werDran[j]].z].P3]:=0.5+0.01*_mt.random;
+ end;
+ 2,3: begin // als Mann/Frau abhängig,
+ tmp:=_mt.random*2*pi;
+ NP[_s.MD.Personen[_werDran[j]].P1]:=NP[_s.MD.Personen[_wannDran[_werDran[j]].z].P1] - power(2,-(_wannDran[_werDran[j]].y div 2)-1)*cos(tmp);
+ NP[_s.MD.Personen[_werDran[j]].P2]:=NP[_s.MD.Personen[_wannDran[_werDran[j]].z].P2] - power(2,-(_wannDran[_werDran[j]].y div 2)-1)*sin(tmp);
+ end;
+ 4: begin // als Nachfahr abhängig
+ NP[_s.MD.Personen[_werDran[j]].P3]:=_mt.random;
+ NP[_s.MD.Personen[_werDran[j]].P1]:=NP[_s.MD.Familien[_wannDran[_werDran[j]].z].Eltern[0].P1] * (1 - NP[_s.MD.Personen[_werDran[j]].P3])
+ + NP[_s.MD.Familien[_wannDran[_werDran[j]].z].Eltern[1].P1] * NP[_s.MD.Personen[_werDran[j]].P3];
+ NP[_s.MD.Personen[_werDran[j]].P2]:=NP[_s.MD.Familien[_wannDran[_werDran[j]].z].Eltern[0].P2] * (1 - NP[_s.MD.Personen[_werDran[j]].P3])
+ + NP[_s.MD.Familien[_wannDran[_werDran[j]].z].Eltern[1].P2] * NP[_s.MD.Personen[_werDran[j]].P3];
+ end;
+ end{of case};
+ k:=0;
+ for j:=0 to length(NP)-1 do
+ if (NP[j]<-0.5) and _s.MD.Parameterattribute[j].wirdBenutzt then begin
+ for l:=0 to length(_s.MD.Personen)-1 do begin
+ if (_s.MD.Personen[l].p1=j) then
+ writeln(inttostr(_wannDran[l].x)+' Personen['+inttostr(l)+'].P1 = '+myfloattostr(NP[j])+' '+inttostr(_wannDran[l].u));
+ if (_s.MD.Personen[l].p2=j) then
+ writeln(inttostr(_wannDran[l].x)+' Personen['+inttostr(l)+'].P2 = '+myfloattostr(NP[j])+' '+inttostr(_wannDran[l].u));
+ if (_s.MD.Personen[l].p3=j) then begin
+ writeln(inttostr(_wannDran[l].x)+' Personen['+inttostr(l)+'].P3 = '+myfloattostr(NP[j])+' '+inttostr(_wannDran[l].u));
+ writeln(' '+inttostr(byte(assigned(_s.MD.Personen[l].KindIn))));
+ if assigned(_s.MD.Personen[l].KindIn) then
+ writeln(' ['+inttostr(_s.MD.Personen[l].KindIn.Eltern[0].Index)+'] '+
+ inttostr(_wannDran[_s.MD.Personen[l].KindIn.Eltern[0].Index].x)+' '+
+ inttostr(_wannDran[_s.MD.Personen[l].KindIn.Eltern[0].Index].u)+' ['+
+ inttostr(_s.MD.Personen[l].KindIn.Eltern[1].Index)+'] '+
+ inttostr(_wannDran[_s.MD.Personen[l].KindIn.Eltern[1].Index].x)+' '+
+ inttostr(_wannDran[_s.MD.Personen[l].KindIn.Eltern[1].Index].u));
+ for m:=0 to length(_wannDran)-1 do
+ if _wannDran[m].z=l then
+ writeln(' <- ['+inttostr(m)+'] '+inttostr(_wannDran[m].x)+' '+inttostr(_wannDran[m].u));
+ end;
+ end;
+ inc(k);
+ end;
+ if k>0 then begin // es gibt ungesetzte Parameter
+ writeln('Irgendwie sind '+inttostr(k)+' benutzte von insgesamt '+inttostr(_s.MD.ParameterLaenge)+' Parametern (davon '+inttostr(_s.MD.anzUnbenutzt)+' planmäßig unbenutzt) ungesetzt ...');
+ halt(1);
+ end;
+ end;
+ 'M':
+ for j:=0 to _s.MD.ParameterLaenge-1 do
+ if _s.MD.Parameterattribute[j].istUnabhaengig then
+ NP[j]:=_mt.random;
+ end{of Case};
+ _s.MD.berechneAbhaengigeVariable(NP{$IFDEF detaillierteZeitanalyse},true{$ENDIF});
+ Ax:=NP[_s.MD.Personen[0].P1];
+ Ay:=NP[_s.MD.Personen[0].P2];
+ Rx:=Ax;
+ Ry:=Ay;
+ for j:=1 to length(_s.MD.Personen)-1 do begin
+ Ax:=min(Ax,NP[_s.MD.Personen[j].P1]);
+ Ay:=min(Ay,NP[_s.MD.Personen[j].P2]);
+ Rx:=max(Rx,NP[_s.MD.Personen[j].P1]);
+ Ry:=max(Ry,NP[_s.MD.Personen[j].P2]);
+ end;
+ Rx:=1/max(epsilon,Rx-Ax);
+ Ry:=1/max(epsilon,Ry-Ay);
+ for j:=0 to length(_s.MD.Personen)-1 do begin
+ NP[_s.MD.Personen[j].P1]:=
+ (NP[_s.MD.Personen[j].P1]-Ax)*Rx;
+ NP[_s.MD.Personen[j].P2]:=
+ (NP[_s.MD.Personen[j].P2]-Ay)*Ry;
+ end;
+ _s.MD.berechneAbhaengigeVariable(NP{$IFDEF detaillierteZeitanalyse},true{$ENDIF});
+ tmp:=_s.MD.Energie(NP,NK,j{$IFDEF detaillierteZeitanalyse},true{$ENDIF});
+ if (i=1) or
+ (Kreuzungen>NK) or
+ ((tmp<Energie) and
+ (Kreuzungen=NK)) then begin
+ Energie:=tmp;
+ Kreuzungen:=NK;
+ for j:=0 to length(Parameter)-1 do
+ Parameter[j]:=NP[j];
+ end;
+ if _s.NotAus.istZuende then break;
+ end;
+
+ fertig:=true;
+end;
+
+end.
diff --git a/make b/make
new file mode 100755
index 0000000..8f6fa96
--- /dev/null
+++ b/make
@@ -0,0 +1,3 @@
+#!/bin/bash
+
+fpc -MObjFPC -Scghi -Cirot -O3 -g -gl -vewnhi -Filib/x86_64-linux -Fl/opt/gnome/lib -Fu/usr/lib/lazarus/lcl/units/x86_64-linux/gtk2 -Fu/usr/lib/lazarus/lcl/units/x86_64-linux -Fu/usr/lib/lazarus/components/lazutils/lib/x86_64-linux -Fu/usr/lib/lazarus/packager/units/x86_64-linux -Fu. -FUlib/x86_64-linux -dLCL -dLCLgtk2 stabile.lpr
diff --git a/stabile.lpi b/stabile.lpi
new file mode 100644
index 0000000..6befb4e
--- /dev/null
+++ b/stabile.lpi
@@ -0,0 +1,93 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<CONFIG>
+ <ProjectOptions>
+ <Version Value="9"/>
+ <General>
+ <Flags>
+ <MainUnitHasCreateFormStatements Value="False"/>
+ <MainUnitHasTitleStatement Value="False"/>
+ </Flags>
+ <SessionStorage Value="InProjectDir"/>
+ <MainUnit Value="0"/>
+ <Title Value="stabile"/>
+ <UseAppBundle Value="False"/>
+ <ResourceType Value="res"/>
+ </General>
+ <i18n>
+ <EnableI18N LFM="False"/>
+ </i18n>
+ <VersionInfo>
+ <StringTable ProductVersion=""/>
+ </VersionInfo>
+ <BuildModes Count="1">
+ <Item1 Name="Default" Default="True"/>
+ </BuildModes>
+ <PublishOptions>
+ <Version Value="2"/>
+ </PublishOptions>
+ <RunParams>
+ <local>
+ <FormatVersion Value="1"/>
+ </local>
+ </RunParams>
+ <Units Count="4">
+ <Unit0>
+ <Filename Value="stabile.lpr"/>
+ <IsPartOfProject Value="True"/>
+ </Unit0>
+ <Unit1>
+ <Filename Value="grampsmath.pas"/>
+ <IsPartOfProject Value="True"/>
+ <UnitName Value="grampsmath"/>
+ </Unit1>
+ <Unit2>
+ <Filename Value="energiefunktion.inc"/>
+ <IsPartOfProject Value="True"/>
+ </Unit2>
+ <Unit3>
+ <Filename Value="lowlevelunit.pas"/>
+ <IsPartOfProject Value="True"/>
+ </Unit3>
+ </Units>
+ </ProjectOptions>
+ <CompilerOptions>
+ <Version Value="11"/>
+ <Target>
+ <Filename Value="stabile"/>
+ </Target>
+ <SearchPaths>
+ <IncludeFiles Value="$(ProjOutDir)"/>
+ <OtherUnitFiles Value="../units"/>
+ <UnitOutputDirectory Value="lib/$(TargetCPU)-$(TargetOS)"/>
+ </SearchPaths>
+ <CodeGeneration>
+ <Checks>
+ <IOChecks Value="True"/>
+ <RangeChecks Value="True"/>
+ <OverflowChecks Value="True"/>
+ <StackChecks Value="True"/>
+ </Checks>
+ <VerifyObjMethodCallValidity Value="True"/>
+ </CodeGeneration>
+ <Linking>
+ <Options>
+ <Win32>
+ <GraphicApplication Value="True"/>
+ </Win32>
+ </Options>
+ </Linking>
+ </CompilerOptions>
+ <Debugging>
+ <Exceptions Count="3">
+ <Item1>
+ <Name Value="EAbort"/>
+ </Item1>
+ <Item2>
+ <Name Value="ECodetoolError"/>
+ </Item2>
+ <Item3>
+ <Name Value="EFOpenError"/>
+ </Item3>
+ </Exceptions>
+ </Debugging>
+</CONFIG>
diff --git a/stabile.lpr b/stabile.lpr
new file mode 100644
index 0000000..b65017e
--- /dev/null
+++ b/stabile.lpr
@@ -0,0 +1,95 @@
+program stabile;
+
+uses grampsunit, sysutils, crt, grampstypen, grampsmath, matheunit;
+
+var
+ S: String;
+ c: char;
+ Stb: TStabile;
+
+procedure Status(Level: Longint);
+begin
+ case Level of
+ 0:
+ writeln('Fehler: obiger Fehler!');
+ 2:
+ writeln('Fehler: Korrupte Zwischenstand-Datei!');
+ else begin
+ writeln('Verwendung: '+Paramstr(0)+' (e|E)[bM]* input.xml/input.gramps');
+ writeln('oder: '+Paramstr(0)+' l Zwischenzustand.txt');
+ end;
+ end{of case};
+ if Assigned(Stb) then Stb.destroy;
+ halt;
+end;
+
+begin
+ if GetEnvironmentVariable('randseed')<>'' then
+ randseed:=strtoint(GetEnvironmentVariable('randseed'));
+
+ if (Paramcount<>2) or
+ (length(Paramstr(1))<1) or
+ ((length(Paramstr(1))<>1) and
+ (leftStr(Paramstr(1),1)='l')) then Status(1);
+ case Paramstr(1)[1] of
+ 'e','E': begin // aus gramps-xml lesen
+ if ((rightStr(Paramstr(2),4)<>'.xml') and
+ (rightStr(Paramstr(2),7)<>'.gramps')) or
+ not fileexists(Paramstr(2)) then Status(1);
+ Stb:=TStabile.create;
+ if not Stb.LadeXML(Paramstr(2)) then begin
+ Stb.destroy;
+ halt;
+ end;
+ Stb.printStatus(0);
+ Stb.generiereFehlendeInfos;
+ Stb.printStatus(1);
+
+ if (length(Paramstr(1))=1) or (pos('b',Paramstr(1))>0) or (pos('i',Paramstr(1))>0) then
+ Stb.nurGroeszteZusammenhangskomponente;
+
+ Stb.printStatus(2);
+ if not Stb.analysiereInteraktionen then begin
+ Stb.destroy;
+ halt;
+ end;
+ Stb.printStatus(3);
+
+ if Paramstr(1)[1]='E' then
+ Stb.blaetterAbschneiden;
+
+ Stb.Initialisiere(10000,rightStr(Paramstr(1),length(Paramstr(1))-1));
+ end;
+ 'l': begin // aus Zwischenstandsdatei einlesen
+ if Paramcount<>2 then Status(1);
+ if not fileexists(Paramstr(2)) then Status(1);
+ Stb:=TStabile.create;
+ if not Stb.LadeVonDatei(Paramstr(2)) then Status(2);
+ Stb.printStatus(4);
+ end;
+ end{of Case};
+// Stb.optimiere;
+// Stb.downHillSimplex;
+ Stb.gradientenOptimierung;
+ writeln('Du hattest '+myTimeToStr(Stb.Zeit)+' Geduld.');
+ write('Möchtest du den Fortschritt speichern? (j/n) ');
+ c:=readkey;
+ while not (c in ['j','J','n','N']) do begin
+ writeln;
+ writeln(''''+c+''' verstehe ich nicht, aber ich wiederhole die Frage gerne noch einmal:');
+ write('Möchtest du den Fortschritt speichern? (j/n) ');
+ c:=readkey;
+ end;
+ writeln;
+ if c in ['j','J'] then begin
+ writeln('Und wohin?');
+ readln(S);
+ while not Stb.SpeichereInDatei(S) do begin
+ writeln('Die Datei '''+S+''' existiert bereits, nimm bitte eine andere!');
+ readln(S);
+ end;
+ end;
+ writeln;
+ Stb.destroy;
+end.
+
diff --git a/stabile.lps b/stabile.lps
new file mode 100644
index 0000000..5a27a08
--- /dev/null
+++ b/stabile.lps
@@ -0,0 +1,194 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<CONFIG>
+ <ProjectSession>
+ <Version Value="9"/>
+ <BuildModes Active="Default"/>
+ <Units Count="6">
+ <Unit0>
+ <Filename Value="stabile.lpr"/>
+ <IsPartOfProject Value="True"/>
+ <CursorPos X="67" Y="3"/>
+ <UsageCount Value="200"/>
+ <Loaded Value="True"/>
+ </Unit0>
+ <Unit1>
+ <Filename Value="grampsmath.pas"/>
+ <IsPartOfProject Value="True"/>
+ <UnitName Value="grampsmath"/>
+ <IsVisibleTab Value="True"/>
+ <EditorIndex Value="3"/>
+ <CursorPos X="48" Y="12"/>
+ <UsageCount Value="128"/>
+ <Loaded Value="True"/>
+ </Unit1>
+ <Unit2>
+ <Filename Value="energiefunktion.inc"/>
+ <IsPartOfProject Value="True"/>
+ <EditorIndex Value="2"/>
+ <TopLine Value="150"/>
+ <CursorPos X="31" Y="185"/>
+ <UsageCount Value="107"/>
+ <Loaded Value="True"/>
+ </Unit2>
+ <Unit3>
+ <Filename Value="lowlevelunit.pas"/>
+ <IsPartOfProject Value="True"/>
+ <EditorIndex Value="-1"/>
+ <TopLine Value="57"/>
+ <CursorPos X="43" Y="97"/>
+ <UsageCount Value="25"/>
+ </Unit3>
+ <Unit4>
+ <Filename Value="grampsunit.pas"/>
+ <UnitName Value="grampsunit"/>
+ <EditorIndex Value="1"/>
+ <CursorPos X="116" Y="7"/>
+ <UsageCount Value="98"/>
+ <Bookmarks Count="9">
+ <Item0 Y="595" ID="1"/>
+ <Item1 X="24" Y="3952" ID="3"/>
+ <Item2 Y="2620" ID="2"/>
+ <Item3 Y="3524" ID="4"/>
+ <Item4 X="31" Y="4028" ID="5"/>
+ <Item5 Y="3024" ID="6"/>
+ <Item6 X="40" Y="2871" ID="9"/>
+ <Item7 Y="2782" ID="7"/>
+ <Item8 X="44" Y="1465" ID="8"/>
+ </Bookmarks>
+ <Loaded Value="True"/>
+ </Unit4>
+ <Unit5>
+ <Filename Value="grampstypen.pas"/>
+ <UnitName Value="grampstypen"/>
+ <EditorIndex Value="4"/>
+ <CursorPos X="20" Y="5"/>
+ <UsageCount Value="98"/>
+ <Bookmarks Count="1">
+ <Item0 Y="1798"/>
+ </Bookmarks>
+ <Loaded Value="True"/>
+ </Unit5>
+ </Units>
+ <JumpHistory Count="30" HistoryIndex="29">
+ <Position1>
+ <Filename Value="grampstypen.pas"/>
+ <Caret Line="271" Column="18" TopLine="238"/>
+ </Position1>
+ <Position2>
+ <Filename Value="grampstypen.pas"/>
+ <Caret Line="272" Column="19" TopLine="239"/>
+ </Position2>
+ <Position3>
+ <Filename Value="grampstypen.pas"/>
+ <Caret Line="1872" Column="58" TopLine="1833"/>
+ </Position3>
+ <Position4>
+ <Filename Value="grampstypen.pas"/>
+ </Position4>
+ <Position5>
+ <Filename Value="grampstypen.pas"/>
+ <Caret Line="210" Column="13" TopLine="177"/>
+ </Position5>
+ <Position6>
+ <Filename Value="grampstypen.pas"/>
+ <Caret Line="224" Column="41" TopLine="191"/>
+ </Position6>
+ <Position7>
+ <Filename Value="grampstypen.pas"/>
+ <Caret Line="1806" Column="15" TopLine="1773"/>
+ </Position7>
+ <Position8>
+ <Filename Value="grampstypen.pas"/>
+ <Caret Line="1827" Column="29" TopLine="1808"/>
+ </Position8>
+ <Position9>
+ <Filename Value="grampstypen.pas"/>
+ <Caret Line="1874" Column="11" TopLine="1852"/>
+ </Position9>
+ <Position10>
+ <Filename Value="grampstypen.pas"/>
+ <Caret Line="1837" Column="32" TopLine="1807"/>
+ </Position10>
+ <Position11>
+ <Filename Value="grampstypen.pas"/>
+ <Caret Line="1884" Column="24" TopLine="1850"/>
+ </Position11>
+ <Position12>
+ <Filename Value="grampsunit.pas"/>
+ <Caret Line="2192" Column="20" TopLine="2177"/>
+ </Position12>
+ <Position13>
+ <Filename Value="stabile.lpr"/>
+ <Caret Line="28" Column="13" TopLine="7"/>
+ </Position13>
+ <Position14>
+ <Filename Value="stabile.lpr"/>
+ <Caret Line="3" Column="56"/>
+ </Position14>
+ <Position15>
+ <Filename Value="grampstypen.pas"/>
+ <Caret Line="1867" Column="29" TopLine="1828"/>
+ </Position15>
+ <Position16>
+ <Filename Value="grampstypen.pas"/>
+ <Caret Line="5" Column="13"/>
+ </Position16>
+ <Position17>
+ <Filename Value="grampstypen.pas"/>
+ <Caret Line="375" Column="4" TopLine="355"/>
+ </Position17>
+ <Position18>
+ <Filename Value="grampstypen.pas"/>
+ <Caret Line="5" Column="23"/>
+ </Position18>
+ <Position19>
+ <Filename Value="grampstypen.pas"/>
+ <Caret Line="11" Column="56"/>
+ </Position19>
+ <Position20>
+ <Filename Value="grampsunit.pas"/>
+ <Caret Line="2177" Column="36" TopLine="2173"/>
+ </Position20>
+ <Position21>
+ <Filename Value="grampsunit.pas"/>
+ <Caret Line="7" Column="63"/>
+ </Position21>
+ <Position22>
+ <Filename Value="grampsunit.pas"/>
+ <Caret Line="193" Column="28" TopLine="173"/>
+ </Position22>
+ <Position23>
+ <Filename Value="grampsunit.pas"/>
+ <Caret Line="7" Column="75"/>
+ </Position23>
+ <Position24>
+ <Filename Value="grampsunit.pas"/>
+ <Caret Line="647" Column="27" TopLine="627"/>
+ </Position24>
+ <Position25>
+ <Filename Value="grampsunit.pas"/>
+ <Caret Line="7" Column="93"/>
+ </Position25>
+ <Position26>
+ <Filename Value="grampsunit.pas"/>
+ <Caret Line="2173" Column="61" TopLine="2153"/>
+ </Position26>
+ <Position27>
+ <Filename Value="grampsunit.pas"/>
+ <Caret Line="7" Column="104"/>
+ </Position27>
+ <Position28>
+ <Filename Value="grampsunit.pas"/>
+ <Caret Line="3805" Column="24" TopLine="3785"/>
+ </Position28>
+ <Position29>
+ <Filename Value="stabile.lpr"/>
+ <Caret Line="71" Column="33" TopLine="54"/>
+ </Position29>
+ <Position30>
+ <Filename Value="stabile.lpr"/>
+ <Caret Line="74" Column="24" TopLine="54"/>
+ </Position30>
+ </JumpHistory>
+ </ProjectSession>
+</CONFIG>