summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorErich Eckner <git@eckner.net>2018-12-17 14:01:39 +0100
committerErich Eckner <git@eckner.net>2018-12-17 14:01:39 +0100
commitab79eab86cf5fd4846238ac1d83afc2fcdd9dc9f (patch)
tree3ee6515e593e4577577c84278021b6994bdcc676
parent52901e961b1adf03a3b632c9a966435a2ef96284 (diff)
downloadunits-ab79eab86cf5fd4846238ac1d83afc2fcdd9dc9f.tar.xz
optimierung neu
-rw-r--r--optimierung.inc22
-rw-r--r--optimierung.pas405
2 files changed, 427 insertions, 0 deletions
diff --git a/optimierung.inc b/optimierung.inc
new file mode 100644
index 0000000..80a5cb2
--- /dev/null
+++ b/optimierung.inc
@@ -0,0 +1,22 @@
+{$IFDEF tGausz2dFitParameterBuffer.initSamples}
+//procedure tGausz2dFitParameterBuffer.initSamples(qu: tExtendedArray; xSteps,tSiz,zoom: longint);
+var
+ x,y: longint;
+begin
+ sXSteps:=xSteps div zoom;
+ sTSiz:=tSiz div zoom;
+ setLength(samples,sXSteps*sTSiz);
+ for x:=0 to sXSteps-1 do
+ for y:=0 to sTSiz-1 do
+ samples[x+y*sXSteps]:=0;
+ for x:=0 to xSteps-1 do
+ for y:=0 to tSiz-1 do
+ samples[round(x/(xSteps-1)*(sXSteps-1)) + round(y/(tSiz-1)*(sTSiz-1))*sTSiz]:=
+ samples[round(x/(xSteps-1)*(sXSteps-1)) + round(y/(tSiz-1)*(sTSiz-1))*sTSiz] +
+ qu[x + y*xSteps];
+ for x:=0 to sXSteps-1 do
+ for y:=0 to sTSiz-1 do
+ samples[x+y*sXSteps]:=
+ samples[x+y*sXSteps] / xSteps * sXSteps / tSiz * sTSiz;
+end;
+{$ENDIF}
diff --git a/optimierung.pas b/optimierung.pas
new file mode 100644
index 0000000..5c8e91e
--- /dev/null
+++ b/optimierung.pas
@@ -0,0 +1,405 @@
+unit optimierung;
+
+{$mode objfpc}{$H+}
+
+interface
+
+uses
+ Classes, SysUtils, lowlevelunit;
+
+type
+ tParameterBuffer = class(tObject)
+ function abstandsQuadrat(const params: tExtendedArray): extended; virtual; abstract;
+ function aktiviereWeitereParameter(const params: tExtendedArray; out neu,neuD: tExtendedArray): boolean; virtual; abstract;
+ end;
+
+ tOptimierer = class(tObject)
+ private
+ buf: tParameterBuffer;
+ dim: longint;
+ function rPar(i: longint): extended; virtual; abstract;
+ function rAbst: extended; virtual; abstract;
+ public
+ property parameter[i: longint]: extended
+ read rPar;
+ property abstand: extended
+ read rAbst;
+ constructor create(buffer: tParameterBuffer; dimension: longint);
+ function optimiere(minVerbesserung, minSchritt: extended; maxSchritte: int64): int64; virtual; abstract;
+ end;
+
+ tDownHillSimplexOptimierer = class(tOptimierer)
+ private
+ pars: array of tExtendedArray;
+ absts: tExtendedArray;
+ bester,schlechtester: longint;
+ function rPar(i: longint): extended; override;
+ function rAbst: extended; override;
+ function simplexSchritt(wer: longint; wieWeit: extended): extended; inline;
+ procedure ermittleRaenge(schlechtesten, besten: boolean); inline;
+ public
+ constructor create(buffer: tParameterBuffer; startParams,dStartParams: tExtendedArray);
+ destructor destroy; override;
+ function optimiere(minVerbesserung, minSchritt: extended; maxSchritte: int64): int64; override;
+ end;
+
+ tGausz2dFitParameterBuffer = class(tParameterBuffer)
+ private
+ anz,iteration: longint;
+ xxs,yys,xys: tExtendedArray;
+ sXSteps,sTSiz: longint;
+ samples: tExtendedArray;
+ procedure setzeBufferParameter(const params: tExtendedArray); inline;
+ public
+ // offset, { xx, yy, x0, y0, a, e }
+ // exp ( -(xx^2 * cos(a)^2 + yy^2 * sin(a)^2) * (X-x0)^2 - (yy^2 * cos(a)^2 + xx^2 * sin(a)^2) * (Y-y0)^2 + 2(xx^2 - yy^2) * cos(a)sin(a) * (X-x0) * (Y-y0) + e)
+ geschaetzteFitParams,
+ geschaetzteDFitParams: tExtendedArray;
+ constructor create(anzahl: longint);
+ destructor destroy; override;
+ procedure initSamples(qu: array of single; xSteps,tSiz,zoom: longint); overload;
+ procedure initSamples(qu: array of double; xSteps,tSiz,zoom: longint); overload;
+ procedure initSamples(qu: array of extended; xSteps,tSiz,zoom: longint); overload;
+ procedure initParamsSchaetzung;
+ procedure initOffset(offset: extended);
+ function aktiviereWeitereParameter(const params: tExtendedArray; out neu,neuD: tExtendedArray): boolean; override;
+ function abstandsQuadrat(const params: tExtendedArray): extended; override;
+ end;
+
+
+// TODOs:
+// - Grenzen für Parameter
+// - einstellbare Schrittlängenfaktoren
+
+implementation
+
+uses
+ math;
+
+// tOptimierer *****************************************************************
+
+constructor tOptimierer.create(buffer: tParameterBuffer; dimension: longint);
+begin
+ inherited create;
+ buf:=buffer;
+ dim:=dimension;
+end;
+
+// tDownHillSimplexOptimierer **************************************************
+
+function tDownHillSimplexOptimierer.rPar(i: longint): extended;
+begin
+ result:=pars[bester][i];
+end;
+
+function tDownHillSimplexOptimierer.rAbst: extended;
+begin
+ result:=absts[bester];
+end;
+
+function tDownHillSimplexOptimierer.simplexSchritt(wer: longint; wieWeit: extended): extended;
+var
+ i,j: longint;
+ tmp: extended;
+begin // neu - Schwerpunkt = wieWeit * (Schwerpunkt - alt) => wieWeit = 1 <=> Spiegelung
+ result:=0;
+ for i:=0 to dim-1 do begin
+ tmp:=0;
+ for j:=0 to dim do
+ if j<>wer then
+ tmp:=tmp+pars[j,i];
+ result:=result + sqr((1 + wieWeit) * (tmp/dim - pars[wer,i]));
+ pars[wer,i]:=tmp * (1 + wieWeit)/dim - wieWeit * pars[wer,i];
+ end;
+end;
+
+procedure tDownHillSimplexOptimierer.ermittleRaenge(schlechtesten, besten: boolean);
+var
+ i: longint;
+begin
+ if besten then
+ for i:=0 to dim do
+ if absts[i] < absts[bester] then
+ bester:=i;
+ if schlechtesten then
+ for i:=0 to dim do
+ if absts[i] > absts[schlechtester] then
+ schlechtester:=i;
+end;
+
+constructor tDownHillSimplexOptimierer.create(buffer: tParameterBuffer; startParams,dStartParams: tExtendedArray);
+var
+ i,j: longint;
+begin
+ inherited create(buffer, length(startParams));
+ if length(dStartParams)<>dim then
+ fehler('tDownHillSimplexOptimierer.create: die Längen von startParams und dStartParams müssen übereinstimmen!');
+ setLength(pars,dim+1);
+ for i:=0 to dim do begin
+ setLength(pars[i],dim);
+ for j:=0 to dim-1 do
+ pars[i,j]:=startParams[j] + dStartParams[j] * byte(j=i);
+ end;
+ setLength(absts,dim+1);
+ bester:=0;
+ schlechtester:=0;
+ for i:=0 to length(absts)-1 do
+ absts[i]:=buf.abstandsQuadrat(pars[i]);
+ ermittleRaenge(true,true);
+end;
+
+destructor tDownHillSimplexOptimierer.destroy;
+var
+ i: longint;
+begin
+ for i:=0 to length(pars)-1 do
+ setLength(pars[i],0);
+ setLength(pars,0);
+ setLength(absts,0);
+ inherited destroy;
+end;
+
+function tDownHillSimplexOptimierer.optimiere(minVerbesserung, minSchritt: extended; maxSchritte: int64): int64;
+var
+ schritt,verbesserung,tmp: extended;
+ i,j,altDim: longint;
+ neu,neuD: tExtendedArray;
+begin
+ if (minVerbesserung<=0) and (minSchritt<=0) and (maxSchritte<=0) then
+ fehler('tDownHillSimplexOptimierer.optimiere benötigt ein Abbruchkriterium!');
+
+ if minSchritt>0 then
+ minSchritt:=sqr(minSchritt);
+
+ result:=0;
+ verbesserung:=0;
+ repeat
+ repeat
+ inc(result);
+ schritt:=simplexSchritt(schlechtester,1);
+
+ tmp:=absts[schlechtester];
+ absts[schlechtester]:=buf.abstandsQuadrat(pars[schlechtester]);
+ verbesserung:=tmp - absts[schlechtester];
+ if absts[schlechtester] < absts[bester] then begin // ist jetzt der beste
+ // => wir gehen noch weiter in dieser Richtung
+ simplexSchritt(schlechtester,-3);
+ schritt:=schritt * sqr(2); // statt von -1 zu 1 sind wir von -1 zu 3 gelaufen => Faktor 2
+ absts[schlechtester]:=buf.abstandsQuadrat(pars[schlechtester]);
+ verbesserung:=tmp - absts[schlechtester];
+ ermittleRaenge(true,true);
+ continue;
+ end;
+ if verbesserung < 0 then begin // verschlechtert
+ // => wir gehen einen kleineren Schritt
+ simplexSchritt(schlechtester,-0.5);
+ schritt:=schritt * sqr(3/4); // statt von -1 zu 1 sind wir von -1 zu 0.5 gelaufen => Faktor 3/4
+ absts[schlechtester]:=buf.abstandsQuadrat(pars[schlechtester]);
+ verbesserung:=tmp - absts[schlechtester];
+ ermittleRaenge(true,false);
+ continue;
+ end;
+ ermittleRaenge(true,false);
+ until
+ ((maxSchritte>0) and (result>=maxSchritte)) or
+ ((minVerbesserung>0) and (verbesserung<minVerbesserung)) or
+ ((minSchritt>0) and (schritt<minSchritt));
+ if buf.aktiviereWeitereParameter(pars[bester],neu,neuD) then begin
+ altDim:=dim;
+ dim:=dim+length(neu);
+ for i:=0 to altDim do begin // alte Eckpunkte um neue Dimensionen erweitern
+ setLength(pars[i],dim);
+ for j:=altDim to dim-1 do
+ pars[i,j]:=neu[j-altDim];
+ end;
+ setLength(pars,dim+1);
+ for i:=altDim+1 to dim do begin // neue Eckpunkte an besten Punkt anfügen
+ setLength(pars[i],dim);
+ for j:=0 to dim-1 do
+ pars[i,j]:=pars[bester,j];
+ for j:=altDim to dim-1 do
+ pars[i,j]:=pars[i,j] + neuD[j-altDim] * byte(j+1=i);
+ end;
+ setLength(absts,dim+1);
+ for i:=0 to dim do // auch alte Eckpunkte müssen aktualisiert werden, da sich die Fitfunktion geändert hat!
+ absts[i]:=buf.abstandsQuadrat(pars[i]);
+ ermittleRaenge(true,true);
+ end
+ else
+ break;
+ until false;
+end;
+
+// tGausz2dFitParameterBuffer **************************************************
+
+const
+ xx_i = 1;
+ yy_i = 2;
+ x0_i = 3;
+ y0_i = 4;
+ a_i = 5;
+ e_i = 6;
+ p_l = 6;
+
+procedure tGausz2dFitParameterBuffer.setzeBufferParameter(const params: tExtendedArray);
+var
+ i: longint;
+ ca,sa: extended;
+begin
+ for i:=0 to iteration-1 do begin
+ ca:=cos(params[p_l*i + a_i]);
+ sa:=sin(params[p_l*i + a_i]);
+ xxs[i]:=-sqr(params[p_l*i + xx_i]*ca)-sqr(params[p_l*i + yy_i]*sa);
+ yys[i]:=-sqr(params[p_l*i + yy_i]*ca)-sqr(params[p_l*i + xx_i]*sa);
+ xys[i]:=(sqr(params[p_l*i + xx_i])-sqr(params[p_l*i + yy_i]))*2*ca*sa;
+ end;
+end;
+
+constructor tGausz2dFitParameterBuffer.create(anzahl: longint);
+begin
+ inherited create;
+ setLength(geschaetzteFitParams,0);
+ setLength(geschaetzteDFitParams,0);
+ setLength(xxs,0);
+ setLength(yys,0);
+ setLength(xys,0);
+ setLength(samples,0);
+ anz:=anzahl;
+end;
+
+destructor tGausz2dFitParameterBuffer.destroy;
+begin
+ setLength(geschaetzteFitParams,0);
+ setLength(geschaetzteDFitParams,0);
+ setLength(xxs,0);
+ setLength(yys,0);
+ setLength(xys,0);
+ setLength(samples,0);
+ inherited destroy;
+end;
+
+{$DEFINE tGausz2dFitParameterBuffer.initSamples}
+procedure tGausz2dFitParameterBuffer.initSamples(qu: array of single; xSteps,tSiz,zoom: longint);
+{$I optimierung.inc}
+procedure tGausz2dFitParameterBuffer.initSamples(qu: array of double; xSteps,tSiz,zoom: longint);
+{$I optimierung.inc}
+procedure tGausz2dFitParameterBuffer.initSamples(qu: array of extended; xSteps,tSiz,zoom: longint);
+{$I optimierung.inc}
+{$UNDEF tGausz2dFitParameterBuffer.initSamples}
+
+procedure tGausz2dFitParameterBuffer.initParamsSchaetzung;
+begin
+ setLength(geschaetzteFitParams,0);
+ setLength(geschaetzteDFitParams,0);
+ iteration:=0;
+end;
+
+procedure tGausz2dFitParameterBuffer.initOffset(offset: extended);
+begin
+ setLength(geschaetzteFitParams,1);
+ setLength(geschaetzteDFitParams,1);
+ geschaetzteFitParams[0]:=offset;
+ geschaetzteDFitParams[0]:=1;
+end;
+
+function tGausz2dFitParameterBuffer.aktiviereWeitereParameter(const params: tExtendedArray; out neu,neuD: tExtendedArray): boolean;
+var
+ i,x,y: longint;
+ dx,dy,tmp: extended;
+ samples2: tExtendedArray;
+begin
+ result:= iteration < anz;
+ if not result then
+ exit;
+
+ setzeBufferParameter(params);
+
+ inc(iteration);
+ setLength(xxs,length(xxs)+1);
+ setLength(yys,length(yys)+1);
+ setLength(xys,length(xys)+1);
+ setLength(neu,6);
+ setLength(neuD,6);
+ for i:=0 to 3 do // xx,yy,x0,y0
+ neuD[i]:=1;
+ neuD[a_i-1]:=0.1; // a
+ neuD[e_i-1]:=0.1; // e
+
+ setLength(samples2,length(samples));
+
+ for y:=0 to sTSiz-1 do
+ for x:=0 to sXSteps-1 do begin
+ samples2[x+y*sXSteps]:=samples[x+y*sXSteps] - params[0];
+ for i:=0 to iteration-2 do begin
+ dx:= x - params[p_l*i + x0_i];
+ dy:= y - params[p_l*i + y0_i];
+ samples2[x+y*sXSteps]:= samples2[x+y*sXSteps] -
+ exp(
+ params[p_l*i + e_i] +
+ xxs[i] * sqr(dx) +
+ yys[i] * sqr(dy) +
+ xys[i] * dx * dy
+ );
+ end;
+ end;
+ neu[e_i-1]:=0;
+ neu[xx_i-1]:=(10 + 0.5 * random) / sXSteps;
+ neu[yy_i-1]:=(10 + 0.5 * random) / sTSiz;
+ neu[x0_i-1]:=0;
+ neu[y0_i-1]:=0;
+ neu[a_i-1]:=0.01 * random - 0.005;
+ tmp:=-1;
+ for y:=0 to sTSiz-1 do
+ for x:=0 to sXSteps-1 do
+ if samples2[x+y*sXSteps]>tmp then begin
+ tmp:= samples2[x+y*sXSteps];
+ neu[x0_i-1]:=x;
+ neu[y0_i-1]:=y;
+ end;
+ if tmp>0 then
+ neu[e_i-1]:=ln(tmp)
+ else
+ neu[e_i-1]:=0;
+ x:=round(neu[x0_i-1]);
+ y:=round(neu[y0_i-1]);
+ for i:=1 to min(x,sXSteps-1-x) do
+ if samples2[x+i+y*sXSteps] + samples2[x-i+y*sXSteps] < 2 * exp(-1) * samples2[x+y*sXSteps] then begin
+ neu[xx_i-1]:=1/i;
+ break;
+ end;
+ for i:=1 to min(y,sTSiz-1-y) do
+ if samples2[x+(y+i)*sXSteps] + samples2[x+(y-i)*sXSteps] - 2 * params[0] < 2 * exp(-1) * samples2[x+y*sXSteps] then begin
+ neu[yy_i-1]:=1/i;
+ break;
+ end;
+
+ setLength(samples2,0);
+end;
+
+function tGausz2dFitParameterBuffer.abstandsQuadrat(const params: tExtendedArray): extended;
+var
+ i,x,y: longint;
+ tmp,dx,dy: extended;
+begin
+ setzeBufferParameter(params);
+
+ result:=0;
+ for x:=0 to sXSteps-1 do
+ for y:=0 to sTSiz-1 do begin
+ tmp:= params[0] - samples[x + y*sXSteps];
+ for i:=0 to iteration-1 do begin
+ dx:= x - params[p_l*i + x0_i];
+ dy:= y - params[p_l*i + y0_i];
+ tmp:= tmp +
+ exp(
+ params[p_l*i + e_i] +
+ xxs[i] * sqr(dx) +
+ yys[i] * sqr(dy) +
+ xys[i] * dx * dy
+ );
+ end;
+ result:= result + sqr(tmp);
+ end;
+end;
+
+end.