diff options
Diffstat (limited to 'packages/numlib/src/spl.pas')
-rw-r--r-- | packages/numlib/src/spl.pas | 1114 |
1 files changed, 1114 insertions, 0 deletions
diff --git a/packages/numlib/src/spl.pas b/packages/numlib/src/spl.pas new file mode 100644 index 0000000000..68c76c399b --- /dev/null +++ b/packages/numlib/src/spl.pas @@ -0,0 +1,1114 @@ +{ + This file is part of the Numlib package. + Copyright (c) 1986-2000 by + Kees van Ginneken, Wil Kortsmit and Loek van Reij of the + Computational centre of the Eindhoven University of Technology + + FPC port Code by Marco van de Voort (marco@freepascal.org) + documentation by Michael van Canneyt (Michael@freepascal.org) + + Undocumented unit. B- and other Splines. Not imported by the other units + afaik. + + See the file COPYING.FPC, included in this distribution, + for details about the copyright. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + **********************************************************************} +unit spl; +{$I direct.inc} + +interface + +uses typ, sle; + +function spl1bspv(q: ArbInt; var kmin1, c1: ArbFloat; x: ArbFloat; var term: ArbInt): ArbFloat; +function spl2bspv(qx, qy: ArbInt; var kxmin1, kymin1, c11: ArbFloat; x, y: ArbFloat; var term: ArbInt): ArbFloat; +procedure spl1bspf(M, Q: ArbInt; var XYW1: ArbFloat; + var Kmin1, C1, residu: ArbFloat; + var term: ArbInt); +procedure spl2bspf(M, Qx, Qy: ArbInt; var XYZW1: ArbFloat; + var Kxmin1, Kymin1, C11, residu: ArbFloat; + var term: ArbInt); +procedure spl1nati(n: ArbInt; var xyc1: ArbFloat; var term: ArbInt); +procedure spl1naki(n: ArbInt; var xyc1: ArbFloat; var term: ArbInt); +procedure spl1cmpi(n: ArbInt; var xyc1: ArbFloat; dy1, dyn: ArbFloat; + var term: ArbInt); +procedure spl1peri(n: ArbInt; var xyc1: ArbFloat; var term: ArbInt); +function spl1pprv(n: ArbInt; var xyc1: ArbFloat; t: ArbFloat; var term: ArbInt): ArbFloat; + +procedure spl1nalf(n: ArbInt; var xyw1: ArbFloat; lambda:ArbFloat; + var xac1, residu: ArbFloat; var term: ArbInt); +function spl2natv(n: ArbInt; var xyg0: ArbFloat; u, v: ArbFloat): ArbFloat; +procedure spl2nalf(n: ArbInt; var xyzw1: ArbFloat; lambda:ArbFloat; + var xyg0, residu: ArbFloat; var term: ArbInt); + { term = 1: succes, + term = 2: set linear equations is not "PD" + term = 4: Approx. number of points? On a line. + term = 3: wrong input n<3 or a weight turned out to be <=0 } +implementation +{$goto on} + +type + Krec = record K1, K2, K3, K4, K5, K6 : ArbFloat end; + +function spl1bspv(q: ArbInt; var kmin1, c1: ArbFloat; x: ArbFloat; var term: ArbInt): ArbFloat; +var c : arfloat1 absolute c1; + k : arfloat_1 absolute kmin1; + D1, D2, D3, + E2, E3, E4, E5: ArbFloat; + pk : ^Krec; + l, r, m : ArbInt; +begin + spl1bspv := NaN; + term := 3; { q >=4 ! } + if q<4 then exit; { at least 1 interval } + if (x<k[2]) or (x>k[q-1]) then exit; { x inside the interval } + term := 1; { Let's hope the params are good :-)} + l := 2; r := q-1; + while l+1<r do { after this loop goes: } + begin { k[l]<=x<=k[l+1] with } + m := (l+r) div 2; { k[l] < k[l+1] } + if x>=k[m] then l := m else r := m + end; + pk := @k[l-2]; { the (de) Boor algoritm .. } + with pk^ do + begin + E2 := X - K2; E3 := X - K3; E4 := K4 - X; E5 := K5 - X; + D2 := C[l]; D3 := C[l+1]; + D1 := ((X-K1)*D2+E4*C[l-1])/(K4-K1); + D2 := (E2*D3+E5*D2)/(K5-K2); + D3 := (E3*C[l+2]+(K6-X)*D3)/(K6-K3); + D1 := (E2*D2+E4*D1)/(K4-K2); + D2 := (E3*D3+E5*D2)/(K5-K3); + spl1bspv := (E3*D2+E4*D1)/(K4-K3) + end; +end; + +function spl2bspv(qx, qy: ArbInt; var kxmin1, kymin1, c11: ArbFloat; x, y: ArbFloat; var term: ArbInt): ArbFloat; +var pd: ^arfloat1; + i, iy: ArbInt; + c: arfloat1 absolute c11; +begin + GetMem(pd, qx*SizeOf(ArbFloat)); + i := 0; + iy := 1; + repeat + i := i + 1; + pd^[i] := spl1bspv(qy, kymin1, c[iy], y, term); + Inc(iy, qy) + until (i=qx) or (term<>1); + if term=1 + then spl2bspv := spl1bspv(qx, kxmin1, pd^[1], x, term) + else spl2bspv := NaN; + FreeMem(pd, qx*SizeOf(ArbFloat)); +end; + +(* Bron: NAG LIBRARY SUBROUTINE E02BAF *) + +function Imin(x, y: ArbInt): ArbInt; +begin if x<y then Imin := x else Imin := y end; + +type ar4 = array[1..$ffe0 div (4*SizeOf(ArbFloat)),1..4] of ArbFloat; + ar3 = array[1..$ffe0 div (3*SizeOf(ArbFloat)),1..3] of ArbFloat; + r_3 = record x, y, w: ArbFloat end; + r3Ar= array[1..$ffe0 div SizeOf(r_3)] of r_3; + r_4 = record x, y, z, w: ArbFloat end; + r4Ar= array[1..$ffe0 div SizeOf(r_4)] of r_4; + r4 = array[1..4] of ArbFloat; + r2 = array[1..2] of ArbFloat; + + r4x = record xy: R2; alfa, d: ArbFloat end; + r4xAr= array[1..$ffe0 div SizeOf(r4x)] of r4x; + nsp2rec = array[0..$ff80 div (3*SizeOf(ArbFloat))] of + record xy: R2; gamma: ArbFloat end; + +procedure spl1bspf(M, Q: ArbInt; var XYW1: ArbFloat; + var Kmin1, C1, residu: ArbFloat; + var term: ArbInt); +var work1: ^arfloat1; + work2: ^ar4; + c : arfloat1 absolute c1; + k : arfloat_1 absolute kmin1; + xyw : r3Ar absolute XYW1; + r, j, jmax, l, lplus1, i, iplusj, jold, jrev, + jplusl, iu, lplusu : ArbInt; + s, k0, k4, sigma, + d, d4, d5, d6, d7, d8, d9, + e2, e3, e4, e5, + n1, n2, n3, + relemt, dprime, cosine, sine, + acol, arow, crow, ccol, ss : ArbFloat; + pk : ^Krec; + +label einde; +(* + DOUBLE PRECISION C(NCAP7), K(NCAP7), W(M), WORK1(M), + * WORK2(4,NCAP7), X(M), Y(M) + .. Local Scalars .. + DOUBLE PRECISION ACOL, AROW, CCOL, COSINE, CROW, D, D4, D5, D6, + * D7, D8, D9, DPRIME, E2, E3, E4, E5, K0, K1, K2, + * K3, K4, K5, K6, N1, N2, N3, RELEMT, S, SIGMA, + * SINE, WI, XI + INTEGER I, IERROR, IPLUSJ, IU, J, JOLD, JPLUSL, JREV, L, + * L4, LPLUS1, LPLUSU, NCAP, NCAP3, NCAPM1, R +*) +begin + term := 3; + if q<4 then exit; + if m<q then exit; +(* + CHECK THAT THE VALUES OF M AND NCAP7 ARE REASONABLE + IF (NCAP7.LT.8 .OR. M.LT.NCAP7-4) GO TO 420 + NCAP = NCAP7 - 7 + NCAPM1 = NCAP - 1 + NCAP3 = NCAP + 3 + + IN ORDER TO DEFINE THE FULL B-SPLINE BASIS, AUGMENT THE + PRESCRIBED INTERIOR KNOTS BY KNOTS OF MULTIPLICITY FOUR + AT EACH END OF THE DATA RANGE. + +*) + for j:=-1 to 2 do k[j] := xyw[1].x; + for j:=q-1 to q+2 do k[j] := xyw[m].x; + + if (k[3]<=xyw[1].x) or (k[q-2]>=xyw[m].x) then exit; +(* + CHECK THAT THE KNOTS ARE ORDERED AND ARE INTERIOR + TO THE DATA INTERVAL. +*) + j := 3; while (k[j]<=k[j+1]) and (j<q-2) do Inc(j); + if j<q-2 then exit; +(* + CHECK THAT THE WEIGHTS ARE STRICTLY POSITIVE. +*) + j := 1; + while (xyw[j].w>0) and (j<m) do Inc(j); + if xyw[j].w<=0 then exit; +(* + CHECK THAT THE DATA ABSCISSAE ARE ORDERED, THEN FORM THE + ARRAY WORK1 FROM THE ARRAY X. THE ARRAY WORK1 CONTAINS + THE + SET OF DISTINCT DATA ABSCISSAE. +*) + GetMem(Work1, m*SizeOf(ArbFloat)); + GetMem(Work2, q*4*SizeOf(ArbFloat)); + r := 1; work1^[1] := xyw[1].x; + j := 1; + while (j<m) do + begin + Inc(j); + if xyw[j].x>work1^[r] + then begin Inc(r); work1^[r] := xyw[j].x end + else if xyw[j].x<work1^[r] then goto einde; + end; + if r<q then goto einde; + +(* + CHECK THE FIRST S AND THE LAST S SCHOENBERG-WHITNEY + CONDITIONS ( S = MIN(NCAP - 1, 4) ). +*) + jmax := Imin(q-4,4); + j := 1; + while (j<=jmax) do + begin + if (work1^[j]>=k[j+2]) or (k[q-j-1]>=work1^[r-j+1]) then goto einde; + Inc(j) + end; +(* + CHECK ALL THE REMAINING SCHOENBERG-WHITNEY CONDITIONS. +*) + Dec(r, 4); i := 4; j := 5; + while j<=q-4 do + begin + K0 := K[j+2]; K4 := K[J-2]; + repeat Inc(i) until (Work1^[i]>k4); + if (I>R) or (WORK1^[I]>=K0) then goto einde; + Inc(j) + end; + +(* + INITIALISE A BAND TRIANGULAR SYSTEM (I.E. A + MATRIX AND A RIGHT HAND SIDE) TO ZERO. THE + PROCESSING OF EACH DATA POINT IN TURN RESULTS + IN AN UPDATING OF THIS SYSTEM. THE SUBSEQUENT + SOLUTION OF THE RESULTING BAND TRIANGULAR SYSTEM + YIELDS THE COEFFICIENTS OF THE B-SPLINES. +*) + FillChar(Work2^, q*4*SizeOf(ArbFloat), 0); + FillChar(c, q*SizeOf(ArbFloat), 0); + + SIGMA := 0; j := 0; jold := 0; + for i:=1 to m do + with xyw[i] do + begin +(* + FOR THE DATA POINT (X(I), Y(I)) DETERMINE AN INTERVAL + K(J + 3) .LE. X .LT. K(J + 4) CONTAINING X(I). (IN THE + CASE J + 4 .EQ. NCAP THE SECOND EQUALITY IS RELAXED TO + INCLUDE + EQUALITY). +*) + while (x>=k[j+2]) and (j<=q-4) do Inc(j); + if j<>jold then + begin + pk := @k[j-1]; + with pk^ do + begin + D4 := 1/(K4-K1); D5 := 1/(K5-K2); D6 := 1/(K6-K3); + D7 := 1/(K4-K2); D8 := 1/(K5-K3); D9 := 1/(K4-K3) + end; + JOLD := J; + end; +(* + COMPUTE AND STORE IN WORK1(L) (L = 1, 2, 3, 4) THE VALUES + OF + THE FOUR NORMALIZED CUBIC B-SPLINES WHICH ARE NON-ZERO AT + X=X(I). +*) with pk^ do + begin + E5 := k5 - X; + E4 := K4 - X; + E3 := X - K3; + E2 := X - K2; + N1 := W*D9; + N2 := E3*N1*D8; + N1 := E4*N1*D7; + N3 := E3*N2*D6; + N2 := (E2*N1+E5*N2)*D5; + N1 := E4*N1*D4; + WORK1^[4] := E3*N3; + WORK1^[3] := E2*N2 + (K6-X)*N3; + WORK1^[2] := (X-K1)*N1 + E5*N2; + WORK1^[1] := E4*N1; + CROW := Y*W; + end; +(* + ROTATE THIS ROW INTO THE BAND TRIANGULAR SYSTEM USING PLANE + ROTATIONS. +*) + for lplus1:=1 to 4 do + begin L := LPLUS1 - 1; + RELEMT := WORK1^[LPLUS1]; + if relemt<>0 then + begin JPLUSL := J + L; + D := WORK2^[JPLUSL,1]; + IF (ABS(RELEMT)>=D) + then DPRIME := ABS(RELEMT)*SQRT(1+sqr(D/RELEMT)) + else DPRIME := D*SQRT(1+sqr(RELEMT/D)); + WORK2^[JPLUSL,1] := DPRIME; + COSINE := D/DPRIME; SINE := RELEMT/DPRIME; + for iu :=2 to 4-l do + begin + LPLUSU := L + IU; + ACOL := WORK2^[JPLUSL,iu]; + AROW := WORK1^[LPLUSU]; + WORK2^[JPLUSL,iu] := COSINE*ACOL + SINE*AROW; + WORK1^[LPLUSU] := COSINE*AROW - SINE*ACOL + end; + + CCOL := C[JPLUSL]; + C[JPLUSL] := COSINE*CCOL + SINE*CROW; + CROW := COSINE*CROW - SINE*CCOL + end; + end; + SIGMA := SIGMA + sqr(CROW) + end; + + residu := SIGMA; +(* + SOLVE THE BAND TRIANGULAR SYSTEM FOR THE B-SPLINE + COEFFICIENTS. IF A DIAGONAL ELEMENT IS ZERO, AND HENCE + THE TRIANGULAR SYSTEM IS SINGULAR, THE IMPLICATION IS + THAT THE SCHOENBERG-WHITNEY CONDITIONS ARE ONLY JUST + SATISFIED. THUS IT IS APPROPRIATE TO EXIT IN THIS + CASE WITH THE SAME VALUE (IFAIL=5) OF THE ERROR + INDICATOR. +*) + term := 2; + L := -1; + for jrev:=1 to q do + begin + J := q - JREV + 1; D := WORK2^[J,1]; + if d=0 then goto einde; + IF l<3 then L := L + 1; + S := C[j]; + for i:=1 to l do + begin + IPLUSJ := I + J; + S := S - WORK2^[j,i+1]*C[IPLUSJ]; + end; + C[J] := S/D + end; + + term:=1; +einde: + FreeMem(Work2, q*4*SizeOf(ArbFloat)); + FreeMem(Work1, m*SizeOf(ArbFloat)) + +end; + +procedure spl2bspf(M, Qx, Qy: ArbInt; var XYZW1: ArbFloat; + var Kxmin1, Kymin1, C11, residu: ArbFloat; + var term: ArbInt); + +(* !!!!!!!! Test input !!!!!!!!!! *) + +(* +cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc +c part 1: determination of the number of knots and their position. c +c **************************************************************** c +c given a set of knots we compute the least-squares spline sinf(x,y), c +c and the corresponding weighted sum of squared residuals fp=f(p=inf). c +c if iopt=-1 sinf(x,y) is the requested approximation. c +c if iopt=0 or iopt=1 we check whether we can accept the knots: c +c if fp <=s we will continue with the current set of knots. c +c if fp > s we will increase the number of knots and compute the c +c corresponding least-squares spline until finally fp<=s. c +c the initial choice of knots depends on the value of s and iopt. c +c if iopt=0 we first compute the least-squares polynomial of degree c +c 3 in x and 3 in y; nx=nminx=2*3+2 and ny=nminy=2*3+2. c +c fp0=f(0) denotes the corresponding weighted sum of squared c +c residuals c +c if iopt=1 we start with the knots found at the last call of the c +c routine, except for the case that s>=fp0; then we can compute c +c the least-squares polynomial directly. c +c eventually the independent variables x and y (and the corresponding c +c parameters) will be switched if this can reduce the bandwidth of the c +c system to be solved. c +cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc *) + +function Min(a, b:ArbInt): ArbInt; +begin if a<b then Min := a else Min := b end; + +procedure WisselR(var x, y: ArbFloat); +var h: ArbFloat; begin h := x; x := y; y := h end; + +procedure Wisseli(var x, y: ArbInt); +var h: ArbInt; begin h := x; x := y; y := h end; + +procedure fprota(var cos1, sin1, a, b: ArbFloat); +var store: ArbFloat; +begin + store := b; b := cos1*b+sin1*a; a := cos1*a-sin1*store +end; + +procedure fpgivs(var piv, ww, cos1, sin1: ArbFloat); +var store, dd: ArbFloat; +begin + store := abs(piv); + if store>=ww + then dd := store*sqrt(1+sqr(ww/piv)) + else dd := ww*sqrt(1+sqr(piv/ww)); + cos1 := ww/dd; sin1 := piv/dd; ww := dd +end; + +procedure fpback(var a11, z1: ArbFloat; n, k: ArbInt; var c1: ArbFloat); +(* + subroutine fpback calculates the solution of the system of + equations a*c = z with a a n x n upper triangular matrix + of bandwidth k. + ArbFloat a(.,k) +*) +var a: arfloat1 absolute a11; + z: arfloat1 absolute z1; + c: arfloat1 absolute c1; + i, l: ArbInt; + store : ArbFloat; +begin + for i:=n downto 1 do + begin + store := z[i]; + for l:=min(n+1-i,k)-1 downto 1 do store := store-c[i+l]*a[(i-1)*k+l+1]; + c[i] := store/a[(i-1)*k+1] + end; +end; + +procedure fpbspl(var kmin1: ArbFloat; x: ArbFloat; l: ArbInt; var h: r4); +(* + subroutine fpbspl evaluates the 4 non-zero b-splines of + degree 3 at t(l) <= x < t(l+1) using the stable recurrence + relation of de boor and cox. +*) +var k : arfloat_1 absolute kmin1; + f : ArbFloat; + hh: array[1..3] of ArbFloat; + i, j, li, lj : ArbInt; +begin + h[1] := 1; + for j:=1 to 3 do + begin + for i:=1 to j do hh[i] := h[i]; + h[1] := 0; + for i:=1 to j do + begin + li := l+i; lj := li-j; + f := hh[i]/(k[li]-k[lj]); + h[i] := h[i]+f*(k[li]-x); + h[i+1] := f*(x-k[lj]) + end; + end; +end; + +procedure fporde(m, qx, qy: ArbInt; var xyzw1, kxmin1, kymin1: ArbFloat; + var nummer1, index1: ArbInt); +var xi, yi : ArbFloat; + i, im, num, + k, l : ArbInt; + xyzw : r4Ar absolute xyzw1; + kx : arfloat_1 absolute kxmin1; + ky : arfloat_1 absolute kymin1; + nummer : arint1 absolute nummer1; + index : arint1 absolute index1; +begin + for i:=1 to (qx-3)*(qy-3) do index[i] := 0; + for im:=1 to m do + with xyzw[im] do + begin + l := 2; while (x>=kx[l+1]) and (l<qx-2) do Inc(l); + k := 2; while (y>=ky[k+1]) and (k<qy-2) do Inc(k); + num := (l-2)*(qy-3)+k-1; + nummer[im] := index[num]; index[num] := im + end; +end; + +label einde; + +var x0, x1, y0, y1, eps, cos1, sin1, dmax, sigma, + wi, zi, hxi, piv : ArbFloat; + i, j, l, l1, l2, lx, ly, nreg, ncof, jrot, + inpanel, i1, j1, + iband, num, irot : ArbInt; + xyzw : r4Ar absolute xyzw1; + kx, ky : ^arfloat_1; + a, f, h : ^arfloat1; + c : arfloat1 absolute c11; + nummer, index : ^arint1; + hx, hy : r4; + ichang, fullrank : boolean; +begin + + eps := 10*macheps; +(* find the position of the additional knots which are needed for the + b-spline representation of s(x,y) *) + iband := 1+min(3*qy+3,3*qx+3); + if qy>qx then + begin + ichang := true; + kx := @kymin1; ky := @kxmin1; + for i:=1 to m do with xyzw[i] do Wisselr(x, y); + WisselI(qx, qy) + end else + begin + ichang := false; + kx := @kxmin1; ky := @kymin1; + end; + with xyzw[1] do begin x0 := x; x1 := x; y0 := y; y1 := y end; + for i:=2 to m do with xyzw[i] do + begin if x<x0 then x0 := x; if x>x1 then x1 := x; + if y<y0 then y0 := y; if y>y1 then y1 := y + end; + for i:=-1 to 2 do kx^[i] := x0; + for i:=-1 to 2 do ky^[i] := y0; + for i:=qx-1 to qx+2 do kx^[i] := x1; + for i:=qy-1 to qy+2 do ky^[i] := y1; +(* arrange the data points according to the panel they belong to *) + nreg := (qx-3)*(qy-3); + ncof := qx*qy; + GetMem(nummer, m*SizeOf(ArbInt)); + GetMem(index, nreg*SizeOf(ArbInt)); + GetMem(h, iband*SizeOf(ArbFloat)); + GetMem(a, iband*ncof*SizeOf(ArbFloat)); + GetMem(f, ncof*SizeOf(ArbFloat)); + fporde(m, qx, qy, xyzw1, kx^[-1], ky^[-1], nummer^[1], index^[1]); + for i:=1 to ncof do f^[i] := 0; + for j:=1 to ncof*iband do a^[j] := 0; + residu := 0; +(* fetch the data points in the new order. main loop for the different panels *) + for num:=1 to nreg do + begin + lx := (num-1) div (qy-3); l1 := lx+2; + ly := (num-1) mod (qy-3); l2 := ly+2; + jrot := lx*qy+ly; + inpanel := index^[num]; + while inpanel<>0 do + with xyzw[inpanel] do + begin + wi := w; zi := z*wi; + fpbspl(kx^[-1], x, l1, hx); + fpbspl(ky^[-1], y, l2, hy); + for i:=1 to iband do h^[i] := 0; + i1 := 0; + for i:=1 to 4 do + begin + hxi := hx[i]; j1 := i1; + for j:=1 to 4 do begin Inc(j1); h^[j1] := hxi*hy[j]*wi end; + Inc(i1, qy) + end; + irot := jrot; + for i:=1 to iband do + begin + Inc(irot); piv := h^[i]; + if piv<>0 then + begin + fpgivs(piv, a^[(irot-1)*iband+1], cos1, sin1); + fprota(cos1, sin1, zi, f^[irot]); + for j:=i+1 to iband do + fprota(cos1, sin1, h^[j], a^[(irot-1)*iband+j-i+1]) + end; + end; + residu := residu+sqr(zi); + inpanel := nummer^[inpanel] + end; + end; + + dmax := 0; + i := 1; + while i<ncof*iband do + begin + if dmax<a^[i] then dmax:=a^[i]; Inc(i, iband) + end; + + sigma := eps*dmax; + i := 1; fullrank := true; + while fullrank and (i<ncof*iband) do + begin + fullrank := a^[i]>sigma; Inc(i, iband) + end; + + term := 2; if not fullrank then goto einde; + term := 1; + + fpback(a^[1], f^[1], ncof, iband, c11); + if ichang then + begin + l1 := 1; + for i:=1 to qx do + begin + l2 := i; + for j:=1 to qy do + begin + f^[l2] := c[l1]; Inc(l1); Inc(l2, qx) + end; + end; + for i:=1 to ncof do c[i] := f^[i] + end; + +einde: + if ichang then for i:=1 to m do with xyzw[i] do Wisselr(x, y); + FreeMem(f, ncof*SizeOf(ArbFloat)); + FreeMem(a, iband*ncof*SizeOf(ArbFloat)); + FreeMem(h, iband*SizeOf(ArbFloat)); + FreeMem(index, nreg*SizeOf(ArbInt)); + FreeMem(nummer, m*SizeOf(ArbInt)) +end; + + +procedure spl1nati(n: ArbInt; var xyc1: ArbFloat; var term: ArbInt); +var + xyc : r3Ar absolute XYC1; + l, b, d, u, c : ^arfloat1; + h2, h3, s2, s3: ArbFloat; + i, m : ArbInt; { afmeting van op te lossen stelsel } +begin + term:=3; + if n < 2 then exit; + for i:=2 to n do if xyc[i-1].x>=xyc[i].x then exit; + term:=1; + xyc[1].w := 0; xyc[n].w := 0; { c1=cn=0 } + m := n-2; + if m=0 then exit; + + getmem(u, n*SizeOf(ArbFloat)); + getmem(l, n*Sizeof(ArbFloat)); + getmem(d, n*SizeOf(ArbFloat)); + getmem(c, n*SizeOf(ArbFloat)); + getmem(b, n*SizeOf(ArbFloat)); + h3:=xyc[2].x-xyc[1].x; + s3:=(xyc[2].y-xyc[1].y)/h3; + + for i:=2 to n-1 do + begin + h2:=h3; h3:=xyc[i+1].x-xyc[i].x; + s2:=s3; s3:=(xyc[i+1].y-xyc[i].y)/h3; + l^[i]:=h2/6; + d^[i]:=(h2+h3)/3; + u^[i]:=h3/6; + b^[i]:=s3-s2 + end; + sledtr(m, l^[3], d^[2], u^[2], b^[2], c^[2], term); + for i:=2 to n-1 do xyc[i].w := c^[i]; + Freemem(b, n*SizeOf(ArbFloat)); + Freemem(c, n*SizeOf(ArbFloat)); + Freemem(d, n*SizeOf(ArbFloat)); + Freemem(l, n*Sizeof(ArbFloat)); + Freemem(u, n*SizeOf(ArbFloat)); +end; {spl1nati} + +procedure spl1naki(n: ArbInt; var xyc1: ArbFloat; var term: ArbInt); +var + xyc : r3Ar absolute XYC1; + l, b, d, u, c : ^arfloat1; + h2, h3, s2, s3: ArbFloat; + i, m : ArbInt; { Dimensions of set lin eqs to solve} +begin + term:=3; + if n < 4 then exit; + for i:=2 to n do if xyc[i-1].x>=xyc[i].x then exit; + term:=1; + m := n-2; + getmem(u, n*SizeOf(ArbFloat)); + getmem(l, n*Sizeof(ArbFloat)); + getmem(d, n*SizeOf(ArbFloat)); + getmem(c, n*SizeOf(ArbFloat)); + getmem(b, n*SizeOf(ArbFloat)); + h3:=xyc[2].x-xyc[1].x; + s3:=(xyc[2].y-xyc[1].y)/h3; + for i:=2 to n-1 do + begin + h2:=h3; h3:=xyc[i+1].x-xyc[i].x; + s2:=s3; s3:=(xyc[i+1].y-xyc[i].y)/h3; + l^[i]:=h2/6; + d^[i]:=(h2+h3)/3; + u^[i]:=h3/6; + b^[i]:=s3-s2 + end; + d^[n-1]:=d^[n-1]+h3/6*(1+h3/h2); l^[n-1]:=l^[n-1]-sqr(h3)/(6*h2); + h2:=xyc[2].x-xyc[1].x; h3:=xyc[3].x-xyc[2].x; + d^[2]:=d^[2]+h2/6*(1+h2/h3); u^[2]:=u^[2]-sqr(h2)/(6*h3); + + sledtr(m, l^[3], d^[2], u^[2], b^[2], c^[2], term); + for i:=2 to n-1 do xyc[i].w := c^[i]; + xyc[1].w := xyc[2].w + (h2/h3)*(xyc[2].w-xyc[3].w); + h2:=xyc[n-1].x-xyc[n-2].x; h3:=xyc[n].x-xyc[n-1].x; + xyc[n].w := xyc[n-1].w + (h3/h2)*(xyc[n-1].w-xyc[n-2].w); + Freemem(b, n*SizeOf(ArbFloat)); + Freemem(c, n*SizeOf(ArbFloat)); + Freemem(d, n*SizeOf(ArbFloat)); + Freemem(l, n*Sizeof(ArbFloat)); + Freemem(u, n*SizeOf(ArbFloat)); +end; {spl1naki} + +procedure spl1cmpi(n: ArbInt; var xyc1: ArbFloat; dy1, dyn: ArbFloat; + var term: ArbInt); +var + xyc : r3Ar absolute XYC1; + l, b, d, u, c : ^arfloat1; + h2, h3, s2, s3: ArbFloat; + i : ArbInt; { Dimensions of set lin eqs to solve} +begin + term:=3; + if n < 2 then exit; + for i:=2 to n do if xyc[i-1].x>=xyc[i].x then exit; + term:=1; + getmem(u, n*SizeOf(ArbFloat)); + getmem(l, n*Sizeof(ArbFloat)); + getmem(d, n*SizeOf(ArbFloat)); + getmem(c, n*SizeOf(ArbFloat)); + getmem(b, n*SizeOf(ArbFloat)); + h3:=xyc[2].x-xyc[1].x; + s3:=(xyc[2].y-xyc[1].y)/h3; + d^[1] := h3/3; u^[1] := h3/6; b^[1] := -dy1+s3; + for i:=2 to n-1 do + begin + h2:=h3; h3:=xyc[i+1].x-xyc[i].x; + s2:=s3; s3:=(xyc[i+1].y-xyc[i].y)/h3; + l^[i]:=h2/6; + d^[i]:=(h2+h3)/3; + u^[i]:=h3/6; + b^[i]:=s3-s2 + end; + d^[n] := h3/3; l^[n] := h3/6; b^[n] := dyn-s3; + + sledtr(n, l^[2], d^[1], u^[1], b^[1], c^[1], term); + for i:=1 to n do xyc[i].w := c^[i]; + Freemem(b, n*SizeOf(ArbFloat)); + Freemem(c, n*SizeOf(ArbFloat)); + Freemem(d, n*SizeOf(ArbFloat)); + Freemem(l, n*Sizeof(ArbFloat)); + Freemem(u, n*SizeOf(ArbFloat)); +end; {spl1cmpi} + +procedure spl1peri(n: ArbInt; var xyc1: ArbFloat; var term: ArbInt); +var + xyc : r3Ar absolute XYC1; + l, b, d, u, c, k : ^arfloat1; + k2, kn1, dy1, cn, + h2, h3, s2, s3: ArbFloat; + i, m : ArbInt; { Dimensions of set lin eqs to solve} +begin + term:=3; + if n < 2 then exit; + if xyc[1].y<>xyc[n].y then exit; + for i:=2 to n do if xyc[i-1].x>=xyc[i].x then exit; + term:=1; + m := n-2; + xyc[1].w := 0; xyc[n].w := 0; { c1=cn=0 } + if m=0 then exit; + if m=1 then + begin + h2:=xyc[2].x-xyc[1].x; + s2:=(xyc[2].y-xyc[1].y)/h2; + h3:=xyc[3].x-xyc[2].x; + s3:=(xyc[3].y-xyc[2].y)/h3; + xyc[2].w := 6*(s3-s2)/(h2+h3); + xyc[3].w := -xyc[2].w; + xyc[1].w := xyc[3].w; + exit + end; + + getmem(u, n*SizeOf(ArbFloat)); + getmem(l, n*Sizeof(ArbFloat)); + getmem(k, n*SizeOf(ArbFloat)); + getmem(d, n*SizeOf(ArbFloat)); + getmem(c, n*SizeOf(ArbFloat)); + getmem(b, n*SizeOf(ArbFloat)); + h3:=xyc[2].x-xyc[1].x; + s3:=(xyc[2].y-xyc[1].y)/h3; + k2 := h3/6; dy1 := s3; + for i:=2 to n-1 do + begin + h2:=h3; h3:=xyc[i+1].x-xyc[i].x; + s2:=s3; s3:=(xyc[i+1].y-xyc[i].y)/h3; + l^[i]:=h2/6; + d^[i]:=(h2+h3)/3; + u^[i]:=h3/6; + b^[i]:=s3-s2; + k^[i]:=0 + end; + kn1 := h3/6; k^[2] := k2; k^[n-1] := kn1; + sledtr(m, l^[3], d^[2], u^[2], k^[2], k^[2], term); + sledtr(m, l^[3], d^[2], u^[2], b^[2], c^[2], term); + cn := (dy1-s3-k2*c^[2]-kn1*c^[n-1])/(2*(k2+kn1)-k2*k^[2]-kn1*k^[n-1]); + for i:=2 to n-1 do xyc[i].w := c^[i] - cn*k^[i]; + xyc[1].w := cn; xyc[n].w := cn; + Freemem(b, n*SizeOf(ArbFloat)); + Freemem(c, n*SizeOf(ArbFloat)); + Freemem(d, n*SizeOf(ArbFloat)); + Freemem(l, n*Sizeof(ArbFloat)); + Freemem(k, n*SizeOf(ArbFloat)); + Freemem(u, n*SizeOf(ArbFloat)); +end; {spl1peri} + +function spl1pprv(n: ArbInt; var xyc1: ArbFloat; t: ArbFloat; var term: ArbInt): ArbFloat; +var + xyc : r3Ar absolute XYC1; + i, j, m : ArbInt; + d, d3, h, dy : ArbFloat; +begin { Assumption : x[i]<x[i+1] i=1..n-1 } + spl1pprv := NaN; + term:=3; if n<2 then exit; + if (t<xyc[1].x) or (t>xyc[n].x) then exit; + term:=1; + i:=1; j:=n; + while j <> i+1 do + begin + m:=(i+j) div 2; + if t>=xyc[m].x then i:=m else j:=m + end; { x[i]<= t <=x[i+1] } + h := xyc[i+1].x-xyc[i].x; + d := t-xyc[i].x; + d3 :=(xyc[i+1].w-xyc[i].w)/h; + dy :=(xyc[i+1].y-xyc[i].y)/h-h*(2*xyc[i].w+xyc[i+1].w)/6; + spl1pprv:= xyc[i].y+d*(dy+d*(xyc[i].w/2+d*d3/6)) + +end; {spl1pprv} + +procedure spl1nalf(n: ArbInt; var xyw1: ArbFloat; lambda:ArbFloat; + var xac1, residu: ArbFloat; var term: ArbInt); +var + xyw : r3Ar absolute xyw1; + xac : r3Ar absolute xac1; + i, j, ncd : ArbInt; + ca, crow : ArbFloat; + h, qty : ^arfloat1; + ch : ^arfloat0; + qtdq : ^arfloat1; +begin + term := 3; { testing input} + if n<2 then exit; + for i:=2 to n do if xyw[i-1].x>=xyw[i].x then exit; + for i:=1 to n do if xyw[i].w<=0 then exit; + if lambda<0 then exit; + term := 1; + Move(xyw, xac, n*SizeOf(r_3)); + if n=2 then begin xac[1].w := 0; xac[2].w := 0; exit end; + + Getmem(ch, (n+2)*SizeOf(ArbFloat)); FillChar(ch^, (n+2)*SizeOf(ArbFloat), 0); + Getmem(h, n*SizeOf(ArbFloat)); + Getmem(qty, n*SizeOf(ArbFloat)); + ncd := n-3; if ncd>2 then ncd := 2; + Getmem(qtdq, ((n-2)*(ncd+1)-(ncd*(ncd+1)) div 2)*SizeOf(ArbFloat)); + for i:=2 to n do h^[i] := 1/(xyw[i].x-xyw[i-1].x); h^[1] := 0; + for i:=1 to n-2 + do qty^[i] := (h^[i+1]*xyw[i].y - + (h^[i+1]+h^[i+2])*xyw[i+1].y + + h^[i+2]*xyw[i+2].y); + j := 1; i := 1; + qtdq^[j] := sqr(h^[i+1])/xyw[i].w + + sqr(h^[i+1]+h^[i+2])/xyw[i+1].w + + sqr(h^[i+2])/xyw[i+2].w + + lambda*(1/h^[i+1]+1/h^[i+2])/3; + Inc(j); + if ncd>0 then + begin i := 2; + qtdq^[j] := -h^[i+1]*(h^[i]+h^[i+1])/xyw[i].w + -h^[i+1]*(h^[i+1]+h^[i+2])/xyw[i+1].w + + lambda/h^[i+1]/6; + Inc(j); + qtdq^[j] := sqr(h^[i+1])/xyw[i].w + + sqr(h^[i+1]+h^[i+2])/xyw[i+1].w + + sqr(h^[i+2])/xyw[i+2].w + + lambda*(1/h^[i+1]+1/h^[i+2])/3; + Inc(j) + end; + for i:=3 to n-2 + do begin + qtdq^[j] := h^[i]*h^[i+1]/xyw[i].w; + Inc(j); + qtdq^[j] := -h^[i+1]*(h^[i]+h^[i+1])/xyw[i].w + -h^[i+1]*(h^[i+1]+h^[i+2])/xyw[i+1].w + + lambda/h^[i+1]/6; + Inc(j); + qtdq^[j] := sqr(h^[i+1])/xyw[i].w + + sqr(h^[i+1]+h^[i+2])/xyw[i+1].w + + sqr(h^[i+2])/xyw[i+2].w + + lambda*(1/h^[i+1]+1/h^[i+2])/3; + Inc(j) + end; + { Solving for c/lambda } + Slegpb(n-2, ncd, qtdq^[1], qty^[1], ch^[2], ca, term); + if term=1 then + begin + residu := 0; + for i:=1 to n do + begin + crow := (h^[i]*ch^[i-1] - (h^[i]+h^[i+1])*ch^[i]+h^[i+1]*ch^[i+1]) + /xyw[i].w; + xac[i].y := xyw[i].y - crow; + residu := residu + sqr(crow)*xyw[i].w + end; + xac[1].w := 0; + for i:=2 to n-1 do xac[i].w := lambda*ch^[i]; + xac[n].w := 0; + end; + Freemem(qtdq, ((n-2)*(ncd+1)-(ncd*(ncd+1)) div 2)*SizeOf(ArbFloat)); + Freemem(qty, n*SizeOf(ArbFloat)); + Freemem(h, n*SizeOf(ArbFloat)); + Freemem(ch, (n+2)*SizeOf(ArbFloat)); +end; + + +procedure spl2nalf(n: ArbInt; var xyzw1: ArbFloat; lambda:ArbFloat; + var xyg0, residu: ArbFloat; var term: ArbInt); +type R3 = array[1..3] of ArbFloat; + R33= array[1..3] of R3; + Rn3= array[1..$ffe0 div SizeOf(R3)] of R3; + +var b,e21t,ht :^Rn3; + pfac :par2dr1; + e22 :R33; + i,j,l,i1,i2,n3 :ArbInt; + s,s1,px,py,hr,ca, + x,absdet,x1,x2, + absdetmax :ArbFloat; + vr :R4x; + wr :R2; + w,u :R3; + a_alfa_d :R4xAr absolute xyzw1; + a_gamma :nsp2rec absolute xyg0; + gamma :^arfloat1; + + + function e(var x,y:R2):ArbFloat; + const c1:ArbFloat=1/(16*pi); + var s:ArbFloat; + begin s:=sqr(x[1]-y[1]) +sqr(x[2]-y[2]); + if s=0 then e:=0 else e:=c1*s*ln(s) + end {e}; + + procedure pfxpfy(var a,b,c:R2;var f:r3; var pfx,pfy:ArbFloat); + var det:ArbFloat; + begin det:=(b[1]-a[1])*(c[2]-a[2]) - (b[2]-a[2])*(c[1]-a[1]); + pfx:=((f[2]-f[1])*(c[2]-a[2]) - (f[3]-f[1])*(b[2]-a[2]))/det; + pfy:=(-(f[2]-f[1])*(c[1]-a[1]) + (f[3]-f[1])*(b[1]-a[1]))/det + end {pfxpfy}; + + procedure pxpy(var a,b,c:R2; var px,py:ArbFloat); + var det : ArbFloat; + begin det:=(b[1]-a[1])*(c[2]-a[2]) - (b[2]-a[2])*(c[1]-a[1]); + px:=(b[2]-c[2])/det; py:=(c[1]-b[1])/det + end {pxpy}; + + function p(var x,a:R2; var px,py:ArbFloat):ArbFloat; + begin p:=1 + (x[1]-a[1])*px +(x[2]-a[2])*py end {p}; + + procedure slegpdlown(n: ArbInt; var a1; var bx1: ArbFloat; + var term: ArbInt); + var i, j, k, kmin1 : ArbInt; + h, lkk : ArbFloat; + a : ar2dr1 absolute a1; + x : arfloat1 absolute bx1; + begin + k:=0; term := 2; + while (k<n) do + begin + kmin1:=k; k:=k+1; lkk:=a[k]^[k]; + for j:=1 to kmin1 do lkk:=lkk-sqr(a[k]^[j]); + if lkk<=0 then exit else + begin + a[k]^[k]:=sqrt(lkk); lkk:=a[k]^[k]; + for i:=k+1 to n do + begin + h:=a[i]^[k]; + for j:=1 to kmin1 do h:=h-a[k]^[j]*a[i]^[j]; + a[i]^[k]:=h/lkk + end; {i} + h:=x[k]; + for j:=1 to kmin1 do h:=h-a[k]^[j]*x[j]; + x[k]:=h/lkk + end {lkk > 0} + end; {k} + for i:=n downto 1 do + begin + h:=x[i]; + for j:=i+1 to n do h:=h-a[j]^[i]*x[j]; + x[i]:=h/a[i]^[i]; + end; {i} + term := 1 + end; + +begin + term := 3; if n<3 then exit; + n3 := n - 3; + i1:=1; x1:=a_alfa_d[1].xy[1]; i2:=1; x2:=x1; + for i:= 2 to n do + begin hr:=a_alfa_d[i].xy[1]; + if hr < x1 then begin i1:=i; x1:=hr end else + if hr > x2 then begin i2:=i; x2:=hr end; + end; + vr:=a_alfa_d[n-2]; a_alfa_d[n-2]:=a_alfa_d[i1]; a_alfa_d[i1]:=vr; + vr:=a_alfa_d[n-1]; a_alfa_d[n-1]:=a_alfa_d[i2]; a_alfa_d[i2]:=vr; + + for i:=1 to 2 do vr.xy[i]:=a_alfa_d[n-2].xy[i]-a_alfa_d[n-1].xy[i]; + absdetmax:=-1; i1:=0; + for i:=1 to n do + begin for j:=1 to 2 do wr[j]:=a_alfa_d[i].xy[j]-a_alfa_d[n-2].xy[j]; + if a_alfa_d[i].d<=0 then exit; + absdet:=abs(wr[1]*vr.xy[2]-wr[2]*vr.xy[1]); + if absdet > absdetmax then begin i1:=i; absdetmax:=absdet end; + end; + term := 4; + if absdetmax<=macheps*abs(x2-x1) then exit; + term := 1; + vr:=a_alfa_d[n]; a_alfa_d[n]:=a_alfa_d[i1]; a_alfa_d[i1]:=vr; + GetMem(e21t, n3*SizeOf(r3)); + GetMem(b, n3*SizeOf(r3)); + GetMem(gamma, n*SizeOf(ArbFloat)); + + pxpy(a_alfa_d[n-2].xy,a_alfa_d[n-1].xy,a_alfa_d[n].xy,px,py); + for i:=1 to n3 do b^[i][1]:=p(a_alfa_d[i].xy,a_alfa_d[n-2].xy,px,py); + pxpy(a_alfa_d[n-1].xy,a_alfa_d[n].xy,a_alfa_d[n-2].xy,px,py); + for i:=1 to n3 do b^[i][2]:=p(a_alfa_d[i].xy,a_alfa_d[n-1].xy,px,py); + pxpy(a_alfa_d[n].xy,a_alfa_d[n-2].xy,a_alfa_d[n-1].xy,px,py); + for i:=1 to n3 do b^[i][3]:=p(a_alfa_d[i].xy,a_alfa_d[n].xy,px,py); + e22[1,1]:=0; e22[2,2]:=0; e22[3,3]:=0; + e22[2,1]:=e(a_alfa_d[n-1].xy,a_alfa_d[n-2].xy); e22[1,2]:=e22[2,1]; + e22[3,1]:=e(a_alfa_d[n].xy,a_alfa_d[n-2].xy); e22[1,3]:=e22[3,1]; + e22[3,2]:=e(a_alfa_d[n].xy,a_alfa_d[n-1].xy); e22[2,3]:=e22[3,2]; + for i:=1 to 3 do + for j:=1 to n3 do e21t^[j,i]:=e(a_alfa_d[n3+i].xy,a_alfa_d[j].xy); + + GetMem(ht, n3*SizeOf(r3)); + for i:=1 to 3 do + for j:=1 to n3 do + begin s:=0; + for l:= 1 to 3 do s:=s+e22[i,l]*b^[j][l]; ht^[j][i]:=s + end; + AllocateL2dr(n3,pfac); + for i:= 1 to n3 do + for j:= 1 to i do + begin if j=i then s1:=0 else s1:=e(a_alfa_d[i].xy,a_alfa_d[j].xy); + for l:= 1 to 3 do s1:=s1+b^[i][l]*(ht^[j][l]-e21t^[j][l])-e21t^[i][l]*b^[j][l]; + if j=i then s:=1/a_alfa_d[i].d else s:=0; + for l:= 1 to 3 do s:=s+b^[i][l]*b^[j][l]/a_alfa_d[n3+l].d; + pfac^[i]^[j] := s1+s/lambda + end; + for i:= 1 to n3 do + gamma^[i]:=a_alfa_d[i].alfa-b^[i][1]*a_alfa_d[n-2].alfa-b^[i][2]*a_alfa_d[n-1].alfa-b^[i][3]*a_alfa_d[n].alfa; + slegpdlown(n3,pfac^[1],gamma^[1],term); + DeAllocateL2dr(n3,pfac); + FreeMem(ht, n3*SizeOf(r3)); + + if term=1 then + begin + for i:= 1 to 3 do + begin s:= 0; + for j:= 1 to n3 do + s:=s+b^[j][i]*gamma^[j]; w[i]:=s; + gamma^[n3+i]:=-w[i] + end;{w=btgamma} + for i:=1 to 3 do + begin s:=0; + for l:=1 to n3 do s:=s+e21t^[l][i]*gamma^[l]; + s1:=0; + for l:=1 to 3 do s1:=s1+e22[i,l]*w[l]; + u[i]:=a_alfa_d[n3+i].alfa+w[i]/(lambda*a_alfa_d[n3+i].d)+s1-s + end; + with a_gamma[0] do + pfxpfy(a_alfa_d[n-2].xy,a_alfa_d[n-1].xy,a_alfa_d[n].xy,u,xy[1],xy[2]); + residu:=0;for i:=1 to n3 do residu:=residu+sqr(gamma^[i])/a_alfa_d[i].d; + for i:= 1 to 3 do residu:=residu+sqr(w[i])/a_alfa_d[n3+i].d; + residu:=residu/sqr(lambda); + a_gamma[0].gamma := u[1]; + for i:=1 to n do + begin + a_gamma[i].xy := a_alfa_d[i].xy; + a_gamma[i].gamma := gamma^[i] + end; + end; + FreeMem(gamma, n*SizeOf(ArbFloat)); + FreeMem(b, n3*SizeOf(r3)); + FreeMem(e21t, n3*SizeOf(r3)) + end; + +function spl2natv(n: ArbInt; var xyg0: ArbFloat; u, v: ArbFloat): ArbFloat; + +const c1: ArbFloat=1/(16*pi); + + var i : ArbInt; + s : ArbFloat; + a_gamma : nsp2rec absolute xyg0; + z : R2; + + function e(var x,y:R2):ArbFloat; + var s:ArbFloat; + begin + s:=sqr(x[1]-y[1]) + sqr(x[2]-y[2]); + if s=0 then + e:= 0 + else + e:=s*ln(s) + end {e}; + + function pf(var x,a:R2;fa,pfx,pfy:ArbFloat):ArbFloat; + begin + pf:=fa + (x[1]-a[1])*pfx + (x[2]-a[2])*pfy + end {pf}; + + begin + s:=0; + z[1] := u; + z[2] := v; + for i:=1 to n do + s:=s+a_gamma[i].gamma*e(z, a_gamma[i].xy); + with a_gamma[0] do + spl2natv :=s*c1+pf(z,a_gamma[n-2].xy, gamma, xy[1], xy[2]) + end; + +begin + +end. |