diff options
Diffstat (limited to 'packages/numlib/src/roo.pas')
-rw-r--r-- | packages/numlib/src/roo.pas | 1435 |
1 files changed, 1435 insertions, 0 deletions
diff --git a/packages/numlib/src/roo.pas b/packages/numlib/src/roo.pas new file mode 100644 index 0000000000..39da1be41f --- /dev/null +++ b/packages/numlib/src/roo.pas @@ -0,0 +1,1435 @@ +{ + 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) + + Unit to find roots of (various kinds of) equations + + 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 roo; +{$i direct.inc} + +interface + +uses typ, spe; + +{Find the all roots of the binomial eq. x^n=a, with "a" a complex number} + +Procedure roobin(n: ArbInt; a: complex; Var z: complex; Var term: ArbInt); + +{Find root point of f(x)=0 with f(x) a continuous function on domain [a,b] + If f(a)*f(b)<=0 then there must be (at least) one rootpoint} + +Procedure roof1r(f: rfunc1r; a, b, ae, re: ArbFloat; Var x: ArbFloat; + Var term: ArbInt); + +{Determine all zeropoints for a given n'th degree polynomal with real +coefficients} + +Procedure roopol(Var a: ArbFloat; n: ArbInt; Var z: complex; + Var k, term: ArbInt); + +{Find roots for a simple 2th degree eq x^2+px+q=0 with p and q real} + +Procedure rooqua(p, q: ArbFloat; Var z1, z2: complex); + +{Roofnr is undocumented, but verry big} + +Procedure roofnr(f: roofnrfunc; n: ArbInt; Var x, residu: ArbFloat; re: ArbFloat; + Var term: ArbInt); + +{ term : 1 succesful termination + 2 Couldn't reach the specified precision + Value X is the best one which could be found. + 3 Wrong input + 4 Too many functionvalues calculated, try to recalc with the + calculated X + 5 Not enough progress. Possibly there is no solution, or the + solution is too close to 0. Try to choose a different + initial startingvalue + 6 Process wants to calculate a function value outside the by + "deff" defined area. +} + +implementation + +Procedure roobin(n: ArbInt; a: complex; Var z: complex; Var term: ArbInt); +{ This procedure solves the binomial equation z**n = a, with a complex} + +Var i, j, k : ArbInt; + w, fie, dfie, r : ArbFloat; + pz : ^arcomp1; +Begin + If n<1 Then + Begin + term := 2; + exit + End; + term := 1; + pz := @z; + dfie := 2*pi/n; + k := 1; + If a.im=0 Then + Begin + If a.re>0 Then + Begin + r := spepow(a.re, 1/n); + pz^[1].Init(r, 0); + k := k+1; + i := (n-1) Div 2; + If Not odd(n) Then + Begin + pz^[k].Init(-r, 0); + k := k+1 + End; + For j:=1 To i Do + Begin + w := j*dfie; + pz^[k].Init(r*cos(w), r*sin(w)); + pz^[k+1] := pz^[k]; + pz^[k+1].Conjugate; + k := k+2 + End + End + Else + Begin + fie := pi/n; + r := spepow(-a.re, 1/n); + i := n Div 2-1; + If odd(n) Then + Begin + pz^[k].Init(-r, 0); + k := k+1 + End; + For j:=0 To i Do + Begin + w := fie+j*dfie; + pz^[k].Init(r*cos(w), r*sin(w)); + pz^[k+1] := pz^[k]; + pz^[k+1].Conjugate; + k := k+2 + End + End + End + Else + Begin + If abs(a.re)>=abs(a.im) Then + r := spepow(abs(a.re)*sqrt(1+sqr(a.im/a.re)), 1/n) + Else r := spepow(abs(a.im)*sqrt(1+sqr(a.re/a.im)), 1/n); + fie := a.arg/n; + i := n Div 2; + For j:=0 To n-1 Do + Begin + w := fie+(j-i)*dfie; + pz^[j+1].Init(r*cos(w), r*sin(w)) + End + End +End {roobin}; + +Procedure roof1r(f: rfunc1r; a, b, ae, re: ArbFloat; Var x: ArbFloat; + Var term: ArbInt); + +Var fa, fb, c, fc, m, tol, w1, w2 : ArbFloat; + k : ArbInt; + stop : boolean; + +Begin + fa := f(a); + fb := f(b); + If (spesgn(fa)*spesgn(fb)=1) Or (ae<0) Or (re<0) + Then {wrong input} + Begin + term := 3; + exit + End; + If abs(fb)>abs(fa) Then + Begin + c := b; + fc := fb; + x := a; + b := a; + fb := fa; + a := c; + fa := fc + End + Else + Begin + c := a; + fc := fa; + x := b + End; + k := 0; + tol := ae+re*spemax(abs(a), abs(b)); + w1 := abs(b-a); + stop := false; + while (abs(b-a)>tol) and (fb<>0) and (Not stop) Do + Begin + m := (a+b)/2; + If (k>=2) Or (fb=fc) Then x := m + Else + Begin + x := (b*fc-c*fb)/(fc-fb); + If abs(b-x)<tol Then x := b-tol*spesgn(b-a); + If spesgn(x-m)=spesgn(x-b) Then x := m + End; + c := b; + fc := fb; + b := x; + fb := f(x); + If spesgn(fa)*spesgn(fb)>0 Then + Begin + a := c; + fa := fc; + k := 0 + End + Else k := k+1; + If abs(fb)>=abs(fa) Then + Begin + c := b; + fc := fb; + x := a; + b := a; + fb := fa; + a := c; + fa := fc; + k := 0 + End; + tol := ae+re*spemax(abs(a), abs(b)); + w2 := abs(b-a); + If w2>=w1 Then + Begin + stop := true; + term := 2 + End; + w1 := w2 + End; + If Not stop Then term := 1 +End {roof1r}; + +Procedure roopol(Var a: ArbFloat; n: ArbInt; Var z: complex; + Var k, term: ArbInt); + +Const max = 50; + +Type rnep2 = array[-2..$ffe0 div SizeOf(ArbFloat)] Of ArbFloat; + +Var rk, i, j, l, m, length, term1 : ArbInt; + p, q, r, s, f, df, delp, delq, delr, telp, telq, sn, sn1, + sn2, noise, noise1, noise2, g, absr, maxcoef, coef, d, t, + maxx, fac, meps : ArbFloat; + convergent, linear, quadratic : boolean; + u, v : complex; + pa : ^arfloat1; + pb, pc, ph : ^rnep2; + pz : ^arcomp1; + +Function gcd(n, m: ArbInt): ArbInt; +{ This function computes the greatest common divisor of m and n} + +Var r : ArbInt; +Begin + r := n Mod m; + while r>0 Do + Begin + n := m; + m := r; + r := n Mod m + End; + gcd := m +End {gcd}; +Begin + If n<1 Then + Begin + term := 3; + exit + End; + length := (n+3)*sizeof(ArbFloat); + getmem(pb, length); + getmem(pc, length); + getmem(ph, length); + meps := macheps; + pa := @a; + pz := @z; + pb^[-2] := 0; + pb^[-1] := 0; + pc^[-2] := 0; + pc^[-1] := 0; + ph^[-1] := 0; + ph^[0] := 1; + For i:=1 To n Do + ph^[i] := pa^[i]; + k := 0; + while (n>0) and (ph^[n]=0) Do + Begin + k := k+1; + pz^[k].Init(0, 0); + n := n-1 + End; + If n>0 Then + Begin + l := n; + i := 1; + while (l>1) and (i<n) Do + Begin + If ph^[i] <> 0 Then l := gcd(l, n-i); + i := i+1 + End; + If l>1 Then + Begin + n := n Div l; + For i:=1 To n Do + ph^[i] := ph^[l*i] + End + End; + convergent := true ; + while (n>0) and convergent Do + Begin + linear := false; + quadratic := false ; + If n=1 Then + Begin + r := -ph^[1]/ph^[0]; + linear := true + End; + If n=2 Then + Begin + p := ph^[1]/ph^[0]; + q := ph^[2]/ph^[0]; + quadratic := true + End; + If n>2 Then + Begin + If (ph^[n-1]=0) Or (ph^[n-2]=0) Then + Begin + maxcoef := abs(ph^[n-1]/ph^[n]); + For i:=2 To n Do + Begin + coef := spepow(abs(ph^[n-i]/ph^[n]),1/i); + If maxcoef<coef Then maxcoef := coef + End; + maxcoef := 2*maxcoef + End; + If ph^[n-1]=0 Then r := -spesgn(ph^[0])*spesgn(ph^[n])/maxcoef + Else r := -ph^[n]/ph^[n-1]; + If ph^[n-2]=0 Then + Begin + p := 0; + q := -1/sqr(maxcoef) + End + Else + Begin + q := ph^[n]/ph^[n-2]; + p := (ph^[n-1]-q*ph^[n-3])/ph^[n-2] + End; + m := 0; + while (m<max) and (Not linear) and (Not quadratic) Do + Begin + m := m+1; + For j:=0 To n Do + pb^[j] := ph^[j]-p*pb^[j-1]-q*pb^[j-2]; + For j:=0 To n-2 Do + pc^[j] := pb^[j]-p*pc^[j-1]-q*pc^[j-2]; + pc^[n-1] := -p*pc^[n-2]-q*pc^[n-3]; + s := sqr(pc^[n-2])-pc^[n-1]*pc^[n-3]; + telp := pb^[n-1]*pc^[n-2]-pb^[n]*pc^[n-3]; + telq := pb^[n]*pc^[n-2]-pb^[n-1]*pc^[n-1]; + If s=0 Then + Begin + delp := telp; + delq := telq + End + Else + Begin + delp := telp/s; + delq := telq/s + End; + noise1 := 0; + sn1 := 0; + sn := 1; + noise2 := 4*abs(pb^[n])+3*abs(p*pb^[n-1]); + For j:=n-1 Downto 0 Do + Begin + g := 4*abs(pb^[j])+3*abs(p*pb^[j-1]); + noise1 := noise1+g*abs(sn); + sn2 := sn1; + sn1 := sn; + sn := -p*sn1-q*sn2; + noise2 := noise2+g*abs(sn) + End; + d := p*p-4*q; + absr := abs(r); + f := ph^[0]; + df := 0; + noise := abs(f)/2; + For j:=1 To n Do + Begin + df := f+r*df; + f := ph^[j]+r*f; + noise := abs(f)+absr*noise + End; + If df=0 Then delr := f + Else delr := f/df; + If (abs(telp)<=meps*(noise1*abs(pc^[n-2])+ + noise2*abs(pc^[n-3]))) + And + (abs(telq)<=meps*(noise1* abs(pc^[n-1])+ + noise2*abs(pc^[n-2]))) + Then quadratic := true + Else + Begin + p := p+delp; + q := q+delq + End; + If abs(f)<=2*meps*noise Then linear := true + Else r := r-delr + End + End; + convergent := linear Or quadratic; + If linear Then + Begin + If l=1 Then + Begin + k := k+1; + pz^[k].xreal := r; + pz^[k].imag := 0 + End + Else + Begin + u.init(r, 0); + roobin(l, u, pz^[k+1], term1); + k := k+l + End; + maxx := 0; + rk := 0; + fac := 1; + For j:=n Downto 0 Do + Begin + s := abs(ph^[j]*fac); + fac := fac*r; + If s>maxx Then + Begin + maxx := s; + rk := j-1 + End + End; + For j:=1 To rk Do + ph^[j] := ph^[j]+r*ph^[j-1]; + If rk<n-1 Then + Begin + s := ph^[n-1]; + ph^[n-1] := -ph^[n]/r; + For j:=n-2 Downto rk+1 Do + Begin + t := ph^[j]; + ph^[j] := (ph^[j+1]-s)/r; + s := t + End + End; + n := n-1; + End + Else + If quadratic Then + Begin + If l=1 Then + Begin + rooqua(p,q,pz^[k+1],pz^[k+2]); + k := k+2 + End + Else + Begin + rooqua(p,q,u,v); + roobin(l,u,pz^[k+1],term1); + roobin(l,v,pz^[k+l+1],term1); + k := k+2*l + End; + n := n-2; + For j:=1 To n Do + ph^[j] := ph^[j]-p*ph^[j-1]-q*ph^[j-2] + End + End; + If k<n Then term := 2 + Else term := 1; + freemem(pb, length); + freemem(pc, length); + freemem(ph, length); +End {roopol}; + +Procedure rooqua(p, q: ArbFloat; Var z1, z2: complex); + +Var s, d : ArbFloat; +Begin + p := -p/2; + d := sqr(p)-q; + If d<0 Then + Begin + z1.Init(p, sqrt(-d)); + z2 := z1; + z2.conjugate + End + Else + Begin + If p>0 Then s := p+sqrt(d) + Else s := p-sqrt(d); + If s=0 Then + Begin + z1.Init(0, 0); + z2 := z1 + End + Else + Begin + z1.Init(s, 0); + z2.Init(q/s, 0) + End + End +End {rooqua}; + +Procedure roo001(uplo, trans, diag: char; n: ArbInt; Var ap1, x1: ArbFloat; + incx: ArbInt); + +Var + ap : arfloat1 absolute ap1; + x : arfloat1 absolute x1; + temp : ArbFloat; + info, ix, j, jx, k, kk, kx: ArbInt; + nounit: boolean; +Begin + info := 0; + uplo := upcase(uplo); + trans := upcase(trans); + diag := upcase(diag); + If n=0 Then exit; + nounit := diag='N'; + If incx<=0 Then kx := 1-(n-1)*incx + Else kx := 1; + If trans='N' Then + Begin + If uplo='U' Then + Begin + kk := 1; + jx := kx; + For j:=1 To n Do + Begin + If x[jx]<>0 Then + Begin + temp := x[jx]; + ix := kx; + For k:=kk To kk+j-2 Do + Begin + x[ix] := x[ix]+temp*ap[k]; + inc(ix, incx) + End; + If nounit Then x[jx] := x[jx]*ap[kk+j-1] + End; + inc(jx, incx); + inc(kk, j) + End + End + Else + Begin + kk := n*(n+1) Div 2; + inc(kx, (n-1)*incx); + jx := kx; + For j:=n Downto 1 Do + Begin + If x[jx]<>0 Then + Begin + temp := x[jx]; + ix := kx; + For k:=kk Downto kk-(n-(j+1)) Do + Begin + x[ix] := x[ix]+temp*ap[k]; + dec(ix, incx) + End; + If nounit Then x[jx] := x[jx]*ap[kk-n+j] + End; + dec(jx, incx); + dec(kk, n-j+1) + End + End + End + Else + Begin + If uplo='U' Then + Begin + kk := n*(n+1) Div 2; + jx := kx+(n-1)*incx; + For j:= n Downto 1 Do + Begin + temp := x[jx]; + ix := jx; + If nounit Then temp := temp*ap[kk]; + For k:= kk-1 Downto kk-j+1 Do + Begin + dec(ix, incx); + temp := temp+ap[k]*x[ix] + End; + x[jx] := temp; + dec(jx, incx); + dec(kk, j) + End + End + Else + Begin + kk := 1; + jx := kx; + For j:=1 To n Do + Begin + temp := x[jx]; + ix := jx; + If nounit Then temp := temp*ap[kk]; + For k:=kk+1 To kk+n-j Do + Begin + inc(ix, incx); + temp := temp+ap[k]*x[ix] + End; + x[jx] := temp; + inc(jx, incx); + inc(kk, n-j+1) + End + End + End +End; + +Procedure roo002(uplo, trans, diag: char; n: ArbInt; + Var ap1, x1: ArbFloat; incx: ArbInt ); + +Var ap : arfloat1 absolute ap1; + x : arfloat1 absolute x1; + temp : ArbFloat; + info, ix, j, jx, k, kk, kx: ArbInt; + nounit: boolean; +Begin + info := 0; + uplo := upcase(uplo); + trans := upcase(trans); + diag := upcase(diag); + If n=0 Then exit; + nounit := diag='N'; + If incx<=0 Then kx := 1-(n-1)*incx + Else kx := 1; + If trans='N' Then + Begin + If uplo='U' Then + Begin + kk := n*(n+1) Div 2; + jx := kx+(n-1)*incx; + For j:=n Downto 1 Do + Begin + If x[jx]<>0 Then + Begin + If nounit Then x[jx] := x[jx]/ap[kk]; + temp := x[jx]; + ix := jx; + For k:=kk-1 Downto kk-j+1 Do + Begin + dec(ix, incx); + x[ix] := x[ix]-temp*ap[k]; + End + End; + dec(jx, incx); + dec(kk, j) + End + End + Else + Begin + kk := 1; + jx := kx; + For j:=1 To n Do + Begin + If x[jx]<>0 Then + Begin + If nounit Then x[jx] := x[jx]/ap[kk]; + temp := x[jx]; + ix := jx; + For k:= kk+1 To kk+n-j Do + Begin + inc(ix, incx); + x[ix] := x[ix]-temp*ap[k] + End; + End; + inc(jx, incx); + inc(kk, n-j+1) + End + End + End + Else + Begin + If uplo='U' Then + Begin + kk := 1; + jx := kx; + For j:= 1 To n Do + Begin + temp := x[jx]; + ix := kx; + For k:= kk To kk+j-2 Do + Begin + temp := temp-ap[k]*x[ix]; + inc(ix, incx); + End; + If nounit Then temp := temp/ap[kk+j-1]; + x[jx] := temp; + inc(jx, incx); + inc(kk, j) + End + End + Else + Begin + kk := n*(n+1) Div 2; + kx := kx+(n-1)*incx; + jx := kx; + For j:=n Downto 1 Do + Begin + temp := x[jx]; + ix := kx; + For k:= kk Downto kk-(n-(j+1)) Do + Begin + temp := temp-ap[k]*x[ix]; + dec(ix, incx) + End; + If nounit Then temp := temp/ap[kk-n+j]; + x[jx] := temp; + dec(jx, incx); + dec(kk, n-j+1) + End + End + End +End; + +Procedure roo003( n: ArbInt; Var x1: ArbFloat; incx: ArbInt; + Var scale, sumsq: ArbFloat ); + +Var absxi : ArbFloat; + i, ix : ArbInt; + x : arfloat1 absolute x1; +Begin + ix := 1; + If n>0 Then + For i:=1 To n Do + Begin + If x[ix]<>0 Then + Begin + absxi := abs(x[ix]); + If (scale<absxi) Then + Begin + sumsq := 1+sumsq*sqr(scale/absxi); + scale := absxi + End + Else sumsq := sumsq + sqr(absxi/scale) + End; + inc(ix, incx) + End +End; + +Function norm2( n: ArbInt; Var x1: ArbFloat; incx: ArbInt): ArbFloat; + +Var scale, ssq : ArbFloat; + sqt: ArbFloat; +Begin + If n<1 Then norm2 := 0 + Else + If n=1 Then norm2 := abs(x1) + Else + Begin + scale := 0; + ssq := 1; + roo003(n, x1, incx, scale, ssq ); + sqt := sqrt( ssq ); + If scale<(giant/sqt) Then norm2 := scale*sqt + Else norm2 := giant + End +End; + +Procedure roo004(n: ArbInt; Var r1, diag1, qtb1: ArbFloat; + delta: ArbFloat; Var x1: ArbFloat); + +Var + r : arfloat1 absolute r1; + diag : arfloat1 absolute diag1; + qtb : arfloat1 absolute qtb1; + x : arfloat1 absolute x1; + wa1, wa2 : ^arfloat1; + alpha, bnorm, gnorm, qnorm, sgnorm, temp: ArbFloat; + i, j, jj, l : ArbInt; +Begin + getmem(wa1, n*sizeof(ArbFloat)); + getmem(wa2, n*sizeof(ArbFloat)); + jj := 1; + For j:=1 To n Do + Begin + wa1^[j] := r[jj]; + If r[jj]=0 Then + Begin + temp := 0; + l := j; + For i:=1 To j-1 Do + Begin + If abs(r[l])>temp Then temp := abs(r[l]); + inc(l, n-i) + End; + If temp=0 Then r[jj] := macheps + Else r[jj] := macheps*temp + End; + inc(jj, n-j+1) + End; + move(qtb, x, n*sizeof(ArbFloat)); + roo002('l','t','n', n, r1, x1, 1); + jj := 1; + For j:=1 To n Do + Begin + r[jj] := wa1^[j]; + inc(jj, n - j + 1) + End; + For j:=1 To n Do + wa2^[j] := diag[j]*x[j]; + qnorm := norm2(n, wa2^[1], 1); + If qnorm>delta Then + Begin + move(qtb, wa1^, n*sizeof(ArbFloat)); + roo001('l','n','n', n, r1, wa1^[1], 1); + For i:=1 To n Do + wa1^[i] := wa1^[i]/diag[i]; + gnorm := norm2(n, wa1^[1], 1); + sgnorm := 0; + alpha := delta/qnorm; + If gnorm<>0 Then + Begin + For j:=1 To n Do + wa1^[j] := (wa1^[j]/gnorm)/diag[j]; + move(wa1^, wa2^, n*sizeof(ArbFloat)); + roo001('l','t','n',n,r1,wa2^[1],1); + temp := norm2(n, wa2^[1],1); + sgnorm := (gnorm/temp)/temp; + alpha := 0; + If sgnorm<delta Then + Begin + bnorm := norm2(n, qtb1, 1); + temp := (bnorm/gnorm)*(bnorm/qnorm)*(sgnorm/delta); + temp := temp-(delta/qnorm)*sqr(sgnorm/delta) + + sqrt(sqr(temp-delta/qnorm) + + (1-sqr(delta/qnorm))*(1-sqr(sgnorm/delta))); + alpha := ((delta/qnorm)*(1-sqr(sgnorm/delta)))/temp + End + End; + If sgnorm<delta Then temp := (1-alpha)*sgnorm + Else temp := (1-alpha)*delta; + For j:=1 To n Do + x[j] := temp*wa1^[j] + alpha*x[j] + End; + freemem(wa2, n*sizeof(ArbFloat)); + freemem(wa1, n*sizeof(ArbFloat)); +End; + +Procedure roo005(fcn: roofnrfunc; n: ArbInt; Var x1, fvec1, fjac1: ArbFloat; + ldfjac: ArbInt; Var iflag: ArbInt; ml, mu: ArbInt; + epsfcn: ArbFloat; Var wa1, wa2: arfloat1); + +Var eps, h, temp: ArbFloat; + i, j, k, msum: ArbInt; + x : arfloat1 absolute x1; + fvec : arfloat1 absolute fvec1; + fjac : arfloat1 absolute fjac1; + deff : boolean; +Begin + If epsfcn>macheps Then eps := sqrt(epsfcn) + Else eps := sqrt(macheps); + msum := ml+mu+1; + If msum>=n Then + Begin + For j:=1 To n Do + Begin + temp := x[j]; + h := eps*abs(temp); + If h=0 Then h := eps; + x[j] := temp+h; + deff := true; + fcn(x1, wa1[1], deff); + If Not deff Then iflag := -1; + If iflag<0 Then exit; + x[j] := temp; + For i:= 1 To n Do + fjac[j+(i-1)*ldfjac] := (wa1[i]-fvec[i])/h + End + End + Else + Begin + For k:=1 To msum Do + Begin + j := k; + while j <= n Do + Begin + wa2[j] := x[j]; + h := eps*abs(wa2[j]); + If h=0 Then h := eps; + x[j] := wa2[j]+h; + inc(j, msum) + End; + deff := true; + fcn(x1, wa1[1], deff); + If Not deff Then iflag := -1; + If iflag<0 Then exit; + j := k; + while j<= n Do + Begin + x[j] := wa2[j]; + h := eps*abs(wa2[j]); + If h=0 Then h := eps; + For i:=1 To n Do + Begin + fjac[j+(i-1)*ldfjac] := 0; + If (i>=(j-mu)) And (i<=(j+ml)) + Then fjac[j+(i-1)*ldfjac] := (wa1[i]-fvec[i])/h + End; + inc(j, msum) + End + End + End +End; + +Procedure roo006(trans: char; m, n: ArbInt; alpha: ArbFloat; Var a1: ArbFloat; + lda: ArbInt; Var x1: ArbFloat; incx : ArbInt; beta: ArbFloat; + Var y1: ArbFloat; incy : ArbInt); + +Var temp : ArbFloat; + i, info, ix, iy, j, jx, jy, kx, ky, lenx, leny: ArbInt; + x : arfloat1 absolute x1; + y : arfloat1 absolute y1; + a : arfloat1 absolute a1; +Begin + info := 0; + trans := upcase(trans); + If (m=0) Or (n=0) Or ((alpha=0) And (beta=1)) Then exit; + If trans='N' Then + Begin + lenx := n; + leny := m + End + Else + Begin + lenx := m; + leny := n + End; + If incx>0 Then kx := 1 + Else kx := 1-(lenx-1)*incx; + If incy>0 Then ky := 1 + Else ky := 1-(leny-1)*incy; + If (beta<>1) Then + Begin + iy := ky; + If beta=0 Then + For i:=1 To leny Do + Begin + y[iy] := 0; + inc(iy, incy) + End + Else + For i:=1 To leny Do + Begin + y[iy] := beta*y[iy]; + inc(iy, incy) + End; + End; + If alpha=0 Then exit; + If trans='N' Then + Begin + jx := kx; + For j:=1 To n Do + Begin + If x[jx]<>0 Then + Begin + temp := alpha*x[jx]; + iy := ky; + For i:=1 To m Do + Begin + y[iy] := y[iy]+temp*a[j+(i-1)*lda]; + inc(iy, incy) + End + End; + inc(jx, incx) + End + End + Else + Begin + jy := ky; + For j:=1 To n Do + Begin + temp := 0; + ix := kx; + For i:=1 To m Do + Begin + temp := temp+a[j+(i-1)*lda]*x[ix]; + inc(ix, incx) + End; + y[jy] := y[jy]+alpha*temp; + inc(jy, incy) + End + End +End; + +Procedure roo007(m, n: ArbInt; alpha: ArbFloat; Var x1: ArbFloat; incx: ArbInt; + Var y1: ArbFloat; incy: ArbInt; Var a1: ArbFloat; lda: ArbInt); + +Var temp: ArbFloat; + i, info, ix, j, jy, kx: ArbInt; + x : arfloat1 absolute x1; + y : arfloat1 absolute y1; + a : arfloat1 absolute a1; +Begin + info := 0; + If (m=0) Or (n=0) Or (alpha=0) Then exit; + If incy>0 Then jy := 1 + Else jy := 1-(n-1)*incy; + If incx>0 Then kx := 1 + Else kx := 1-(m-1)*incx; + For j:=1 To n Do + Begin + If y[jy]<>0 Then + Begin + temp := alpha*y[jy]; + ix := kx; + For i:=1 To m Do + Begin + a[j +(i-1)*lda] := a[j + (i-1)*lda] + x[ix]*temp; + inc(ix, incx) + End + End; + inc(jy, incy) + End +End; + +Procedure roo008(n: ArbInt; Var q1: ArbFloat; ldq: ArbInt; Var wa: arfloat1); + +Var q: arfloat1 absolute q1; + i, j, k: ArbInt; +Begin + For j:=2 To n Do + For i:=1 To j-1 Do + q[j+(i-1)*ldq] := 0; + For k:=n Downto 1 Do + Begin + If (q[k+(k-1)*ldq]<>0) And (k<>n) Then + Begin + roo006('t', n-k+1, n-k, 1, q[k+1+(k-1)*ldq], ldq, + q[k +(k-1)*ldq], ldq, 0, wa[k+1], 1); + roo007(n-k+1, n-k, -1/q[k+(k-1)*ldq], q[k+(k-1)*ldq], ldq, + wa[k+1], 1, q[k+1+(k-1)*ldq], ldq) + End; + For i:=k + 1 To n Do + q[k+(i-1)*ldq] := -q[k+(i-1)*ldq]; + q[k+(k-1)*ldq] := 1-q[k+(k-1)*ldq] + End; +End; + +Procedure roo009(n: ArbInt; Var a1: ArbFloat; lda: ArbInt; + Var rdiag1, acnorm1: ArbFloat); + +Var a : arfloat1 absolute a1; + rdiag : arfloat1 absolute rdiag1; + acnorm : arfloat1 absolute acnorm1; + ajnorm : ArbFloat; + i, j : ArbInt; +Begin + For j:=1 To n Do + acnorm[j] := norm2(n, a[j], lda); + For j:=1 To n Do + Begin + ajnorm := norm2(n-j+1, a[j+(j-1)*lda], lda); + If ajnorm<>0 Then + Begin + If a[j+(j-1)*lda]<0 Then ajnorm := -ajnorm; + For i:=j To n Do + a[j+(i-1)*lda] := a[j+(i-1)*lda]/ajnorm; + a[j+(j-1)*lda] := a[j+(j-1)*lda]+1; + If j<>n Then + Begin + roo006('t', n-j+1, n-j, 1, a[j+1+(j-1)*lda], lda, + a[j+(j-1)*lda], lda, 0, rdiag[j+1], 1); + roo007(n-j+1, n-j, -1/a[j+(j-1)*lda], a[j+(j-1)*lda], lda, + rdiag[j+1], 1, a[j+1+(j-1)*lda], lda) + End + End; + rdiag[j] := -ajnorm + End +End; + +Procedure roo010(n: ArbInt; Var x1: ArbFloat; incx: ArbInt; + Var y1: ArbFloat; incy: ArbInt; c, s:ArbFloat ); + +Var temp1: ArbFloat; + x : arfloat1 absolute x1; + y : arfloat1 absolute y1; + i, ix, iy: ArbInt; +Begin + If incy>=0 Then iy := 1 + Else iy := 1-(n-1)*incy; + If incx>=0 Then ix := 1 + Else ix := 1-(n-1)*incx; + For i:=1 To n Do + Begin + temp1 := x[ix]; + x[ix] := s*y[iy]+c*temp1; + y[iy] := c*y[iy]-s*temp1; + inc(ix, incx); + inc(iy, incy) + End +End; + +Procedure roo011(m, n: ArbInt; Var a1: ArbFloat; lda: ArbInt; Var v1, w1: ArbFloat); + +Var a: arfloat1 absolute a1; + v: arfloat1 absolute v1; + w: arfloat1 absolute w1; + sine, cosine: ArbFloat; + j, nm1, nmj: ArbInt; +Begin + nm1 := n-1; + For nmj:=1 To nm1 Do + Begin + j := n-nmj; + If (abs(v[j])>1) Then + Begin + cosine := 1/v[j]; + sine := sqrt(1-sqr(cosine)) + End + Else + Begin + sine := v[j]; + cosine := sqrt(1-sqr(sine)) + End; + roo010(m, a[n], lda, a[j], lda, cosine, sine) + End; + For j:=1 To nm1 Do + Begin + If (abs(w[j])>1) Then + Begin + cosine := 1/w[j]; + sine := sqrt(1-sqr(cosine)) + End + Else + Begin + sine := w[j]; + cosine := sqrt(1-sqr(sine)) + End; + roo010(m, a[j], lda, a[n], lda, cosine, sine) + End +End; + +Procedure roo012(m, n: ArbInt; Var s1: ArbFloat; ls: ArbInt; + Var u1, v1, w1: ArbFloat; Var sing: boolean); + +Const one = 1.0; + p5 = 0.5; + p25 = 0.25; + zero = 0.0; + +Var cosine, cotan, sine, tangnt, tau: ArbFloat; + i, j, jj, nm1, nmj: ArbInt; + s : arfloat1 absolute s1; + u : arfloat1 absolute u1; + v : arfloat1 absolute v1; + w : arfloat1 absolute w1; +Begin + jj := (n*(2*m-n+1)) Div 2 - (m-n); + If m>=n Then move(s[jj], w[n], (m-n+1)*sizeof(ArbFloat)); + nm1 := n-1; + For nmj:=1 To nm1 Do + Begin + j := n-nmj; + jj := jj-(m-j+1); + w[j] := zero; + If (v[j]<>zero) Then + Begin + If (abs(v[n])<abs(v[j])) Then + Begin + cotan := v[n]/v[j]; + sine := p5/sqrt(p25+p25*sqr(cotan)); + cosine := sine*cotan; + If (abs(cosine)*giant)>one + Then tau := one/cosine + Else tau := one + End + Else + Begin + tangnt := v[j]/v[n]; + cosine := p5/sqrt(p25+p25*sqr(tangnt)); + sine := cosine*tangnt; + tau := sine; + End; + v[n] := sine*v[j]+cosine*v[n]; + v[j] := tau; + roo010(m-j+1, w[j], 1, s[jj], 1, cosine, sine) + End + End; + For i:=1 To m Do + w[i] := w[i]+v[n]*u[i]; + sing := false; + For j:=1 To nm1 Do + Begin + If w[j]<>zero Then + Begin + If abs(s[jj])<abs(w[j]) Then + Begin + cotan := s[jj]/w[j]; + sine := p5/sqrt(p25+p25*sqr(cotan)); + cosine := sine*cotan; + If (abs(cosine)*giant)>one Then tau := one/cosine + Else tau := one + End + Else + Begin + tangnt := w[j]/s[jj]; + cosine := p5/sqrt(p25+p25*sqr(tangnt)); + sine := cosine*tangnt; + tau := sine + End; + roo010(m-j+1, s[jj], 1, w[j], 1, cosine, sine); + w[j] := tau + End; + If (s[jj]=zero) Then sing := true; + inc(jj, m-j+1) + End; + If m>=n Then move(w[n], s[jj], (m-n+1)*sizeof(ArbFloat)); + If s[jj]=zero Then sing := true +End; + +Procedure roo013(fcn: roofnrfunc; n: ArbInt; Var x1, fvec1: ArbFloat; + xtol: ArbFloat; maxfev, ml, mu: ArbInt; epsfcn: ArbFloat; + Var diag1: ArbFloat; factor: ArbFloat; Var info: ArbInt; + Var fjac1: ArbFloat; ldfjac: ArbInt; + Var r1: ArbFloat; lr: ArbInt; Var qtf1: ArbFloat); + +Const p1 = 0.1; + p5 = 0.5; + p001 = 0.001; + p0001 = 0.0001; + +Var diag : arfloat1 absolute diag1; + fjac : arfloat1 absolute fjac1; + fvec : arfloat1 absolute fvec1; + qtf : arfloat1 absolute qtf1; + r : arfloat1 absolute r1; + wa1, wa2, wa3, wa4: ^arfloat1; + x : arfloat1 absolute x1; + actred, delta, fnorm, fnorm1, pnorm, + prered, ratio, sum, temp, xnorm : ArbFloat; + i, iflag, iter, j, jm1, l, msum, ncfail, ncsuc, nfev, + nslow1, nslow2, ns : ArbInt; + jeval, sing, deff: boolean; +Begin + info := 1; + iflag := 0; + nfev := 0; + ns := n*sizeof(ArbFloat); + For j:=1 To n Do + If diag[j]<=0 Then exit; + iflag := 1; + deff := true; + fcn(x1, fvec1, deff); + If Not deff Then iflag := -1; + nfev := 1; + If iflag<0 Then + Begin + info := iflag; + exit + End; + fnorm := norm2(n, fvec1, 1); + msum := ml+mu+1; + If msum>n Then msum := n; + getmem(wa1, ns); + getmem(wa2, ns); + getmem(wa3, ns); + getmem(wa4, ns); + iter := 1; + ncsuc := 0; + ncfail := 0; + nslow1 := 0; + nslow2 := 0; + while (info=1) and (iflag>=0) Do + Begin + jeval := true; + iflag := 2; + roo005(fcn, n, x1, fvec1, fjac1, ldfjac, iflag, ml, mu, epsfcn, + wa1^, wa2^); + inc(nfev, msum); + If iflag>=0 Then + Begin + roo009(n, fjac1, ldfjac, wa1^[1], wa2^[1]); + If iter=1 Then + Begin + For j:=1 To n Do + wa3^[j] := diag[j]*x[j]; + xnorm := norm2(n, wa3^[1], 1); + delta := factor*xnorm; + If delta=0 Then delta := factor; + End; + For i:=1 To n Do + qtf[i] := fvec[i]; + For j:=1 To n Do + If fjac[j+(j-1)*ldfjac]<>0 Then + Begin + sum := 0; + For i:=j To n Do + sum := sum+fjac[j+(i-1)*ldfjac]*qtf[i]; + temp := -sum/fjac[j+(j-1)*ldfjac]; + For i:=j To n Do + qtf[i] := qtf[i]+fjac[j+(i-1)*ldfjac]*temp + End; + sing := false; + For j:=1 To n Do + Begin + l := j; + jm1 := j-1; + For i:=1 To jm1 Do + Begin + r[l] := fjac[j+(i-1)*ldfjac]; + inc(l, n-i) + End; + r[l] := wa1^[j]; + If wa1^[j]=0 Then sing := true + End; + roo008(n, fjac1, ldfjac, wa1^); + Repeat + roo004(n, r1, diag1, qtf1, delta, wa1^[1]); + For j:=1 To n Do + Begin + wa1^[j] := -wa1^[j]; + wa2^[j] := x[j]+wa1^[j]; + wa3^[j] := diag[j]*wa1^[j] + End; + pnorm := norm2(n, wa3^[1], 1); + If iter=1 Then If pnorm<delta Then delta := pnorm; + iflag := 1; + deff := true; + fcn(wa2^[1], wa4^[1], deff); + If Not deff Then iflag := -1; + inc(nfev); + If iflag>0 Then + Begin + fnorm1 := norm2(n, wa4^[1], 1); + If fnorm1<fnorm Then actred := 1-sqr(fnorm1/fnorm) + Else actred := -1; + move(wa1^, wa3^, n*sizeof(ArbFloat)); + roo001('l','t','n', n, r1, wa3^[1], 1); + For i:=1 To n Do + wa3^[i] := wa3^[i] + qtf[i]; + temp := norm2(n, wa3^[1], 1); + If temp<fnorm + Then prered := 1 - sqr(temp/fnorm) + Else prered := 1; + If prered>0 Then ratio := actred/prered + Else ratio := 0; + If ratio<p1 Then + Begin + ncsuc := 0; + inc(ncfail); + delta := p5*delta + End + Else + Begin + ncfail := 0; + inc(ncsuc); + If (ratio>=p5) Or (ncsuc>1) + Then If delta<pnorm/p5 Then delta := pnorm/p5; + If abs(ratio-1)<=p1 Then delta := pnorm/p5 + End; + If ratio>=p0001 Then + Begin + For j:=1 To n Do + Begin + x[j] := wa2^[j]; + wa2^[j] := diag[j]*x[j]; + fvec[j] := wa4^[j] + End; + xnorm := norm2(n, wa2^[1], 1); + fnorm := fnorm1; + inc(iter) + End; + inc(nslow1); + If actred>=p001 Then nslow1 := 0; + If jeval Then inc(nslow2); + If actred>=p1 Then nslow2 := 0; + If (delta<=xtol*xnorm) Or + (fnorm=0) Or (pnorm=0) Then info := 0 + Else If nfev>=maxfev Then info := 2 + Else If delta<=macheps*xnorm Then info := 3 + Else If nslow2=5 Then info := 4 + Else If nslow1=10 Then info := 5; + If (info=1) And (ncfail<>2) Then + Begin + roo006('t', n, n, 1, fjac1, ldfjac, wa4^[1], 1, 0, + wa2^[1], 1); + If ratio>=p0001 Then move(wa2^, qtf, ns); + For j:=1 To n Do + Begin + wa2^[j] := (wa2^[j]-wa3^[j])/pnorm; + wa1^[j] := diag[j]*((diag[j]*wa1^[j])/pnorm) + End; + roo012(n, n, r1, lr, wa1^[1], wa2^[1], wa3^[1], sing); + roo011(n, n, fjac1, ldfjac, wa2^[1], wa3^[1]); + roo011(1, n, qtf1, 1, wa2^[1], wa3^[1]); + jeval := false + End + End + Until (iflag<0) Or (ncfail=2) Or (info<>1) + End + End; + freemem(wa4, ns); + freemem(wa3, ns); + freemem(wa2, ns); + freemem(wa1, ns); + If iflag<0 Then info := iflag; +End; + +Procedure roofnr(f: roofnrfunc; n: ArbInt; Var x, residu: ArbFloat; re: ArbFloat; + Var term: ArbInt); + +Var j, lr, ns : ArbInt; + wa1, wa2, wa3, wa4, fx : ^arfloat1; +Begin + ns := n*sizeof(ArbFloat); + If n<=0 Then term := 3 + Else + Begin + If re<0 Then term := 3 + Else + Begin + lr := (n*(n+1)) Div 2; + getmem(wa1, ns); + getmem(wa2, ns); + getmem(wa3, lr*sizeof(ArbFloat)); + getmem(wa4, n*ns); + getmem(fx, ns); + For j:=1 To n Do + wa1^[j] := 1; + roo013(f, n, x, fx^[1], re, 200*(n+1), n-1, n-1, 0, wa1^[1], + 100.0, term, wa4^[1], n, wa3^[1], lr, wa2^[1]); + residu := Norm2(n, fx^[1], 1); + freemem(fx, ns); + freemem(wa4, n*ns); + freemem(wa3, lr*sizeof(ArbFloat)); + freemem(wa2, ns); + freemem(wa1, ns); + If term<0 Then term := 6 + Else + Case term Of + 0: term := 1; + 2: term := 4; + 3: term := 2; + 4, 5: term := 5; + End + End + End +End; +End. |