{ 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 (xk[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=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=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 (j0) and (jwork1^[r] then begin Inc(r); work1^[r] := xyw[j].x end else if xyw[j].x=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=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=ky[k+1]) and (kqx 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 xx1 then x1 := x; if yy1 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 isigma; 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]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 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.