|
|
BSD 4.0
subroutine buram(npts, mesh, fn, m, n, p, q, delk)
integer npts
integer m, n
real mesh(npts), fn(npts), p(1), q(1), delk
common /dfccom/ nitr
integer nitr
integer ier, maxitr, nerror, i, itol
real fnmin, fnmax
logical smonor
c Buram is a double precision subroutine which finds a
c a rational function which is the best approximation,
c in the uniform or minimax sense, to a given discrete
c function. The rational function is represented as
c the quotient of two polynomials each expanded in terms
c of Tchebychev polynomials. This routine is a shell
c which in turn calls the routine Burm1 with certain
c default values for the initial approximation and for
c the stopping criteria.
c Input:
c npts - the number of mesh points.
c mesh - the array of mesh points.
c fn - the array of function values.
c m - the degree of the desired numerator polynomial.
c n - the degree of the desired denominator polynomial.
c Output:
c p - the array of coefficients for the numerator polynomial.
c q - the array of coefficients for the denominator polynomial.
c delk - the maximum error in the approximation.
c Error States (asterisk indicates recoverable):
c 1 - invalid degree
c 2 - too few mesh points
c 3 - mesh is not strictly monotone
c 4* - approximation equals function
c 5* - no improvement in approximation
c 6* - reached 50 iterations
call enter(1)
if (m .lt. 0 .or. n .lt. 0) call seterr(
1 23h Buram - invalid degree, 23, 1, 2)
if (npts .lt. m+n+2) call seterr(28h Buram - too few mesh points
1 , 28, 2, 2)
if (.not. smonor(mesh, npts, 1)) call seterr(
1 38h Buram - mesh is not strictly monotone, 38, 3, 2)
c Initialize the numerator and demoninator polynomials.
fnmax = fn(1)
fnmin = fn(1)
do 3 i = 2, npts
if (fnmax .ge. fn(i)) goto 1
fnmax = fn(i)
goto 2
1 if (fn(i) .lt. fnmin) fnmin = fn(i)
2 continue
3 continue
call setr(m+1, 0.0e0, p)
p(1) = 0.5e0*(fnmax+fnmin)
call setr(n+1, 0.0e0, q)
q(1) = 1.0e0
delk = fnmax-p(1)
nitr = 0
if (m .eq. 0 .and. n .eq. 0) goto 11
maxitr = 50
itol = 2
call burm1(npts, mesh, fn, maxitr, itol, m, n, p, q, delk)
if (nerror(ier) .eq. 0) goto 10
if (ier .ne. 7) goto 4
call newerr(38h Buram - approximation equals function,
1 39, 4, 1)
goto 9
4 if (ier .ne. 8) goto 5
call newerr(
1 40h Buram - no improvement in approximation, 40, 5,
2 1)
goto 8
5 if (ier .ne. 9) goto 6
call newerr(30h Buram - reached 50 iterations, 30
1 , 6, 1)
goto 7
6 call eprint
7 continue
8 continue
9 continue
10 continue
11 call leave
return
end
subroutine burm1(npts, mesh, fn, maxitr, itol, m, n, p, q,
1 delk)
integer npts
integer maxitr, itol, m, n
real mesh(npts), fn(npts), p(1), q(1), delk
common /cstak/ dstak
double precision dstak(500)
integer istkgt, iexptr, j, idig, iflr, istak(1000)
integer enptr, qkptr, i1mach, npptr, nqptr
real abs, qlrg, float, ws(1000), r1mach
logical smonor
equivalence (dstak, istak)
equivalence (dstak, ws)
c Burm1 is a double precision subroutine which finds a
c a rational function which is the best approximation,
c in the uniform or minimax sense, to a given discrete
c function. The rational function is represented as
c the quotient of two polynomials each expanded in terms
c of Tchebychev polynomials. This routine starts from an
c initial approximation and terminates for one of four
c reasons: (1) the error curve equioscillates and the
c alternating extrema match to ITOL digits, (2) the number
c of iterations exceeds MAXITR, (3) the approximation
c cannot be improved, or (4) the approximation is essentially
c equal to the given discrete function.
c Input:
c npts - the number of mesh points.
c mesh - the array of mesh points.
c fn - the array of function values.
c maxitr - the maximum number of iterations.
c itol - the number of digits to which the extrema should match.
c m - the degree of the desired numerator polynomial.
c n - the degree of the desired denominator polynomial.
c p - the array of coefficients for the initial numerator.
c q - the array of coefficients for the initial denominator.
c Output:
c p - the array of coefficients for the numerator polynomial.
c q - the array of coefficients for the denominator polynomial.
c delk - the maximum error in the approximation.
c Error States (asterisk indicates recoverable):
c 1 - invalid degree
c 2 - too few mesh points
c 3 - mesh is not strictly monotone
c 4 - maxitr .lt. 0
c 5 - invalid accuracy request
c 6 - denominator is nonpositive
c 7* - approximation equals function
c 8* - no improvement in approximation
c 9* - reached maximum no. of iterations
call enter(1)
if (m .lt. 0 .or. n .lt. 0) call seterr(
1 23h Burm1 - invalid degree, 23, 1, 2)
if (npts .lt. m+n+2) call seterr(28h Burm1 - too few mesh points
1 , 28, 2, 2)
if (.not. smonor(mesh, npts, 1)) call seterr(
1 38h Burm1 - mesh is not strictly monotone, 38, 3, 2)
if (maxitr .lt. 0) call seterr(22h Burm1 - maxitr .lt. 0, 22, 4, 2
1 )
idig = iflr(r1mach(5)*float(i1mach(11)))
if (itol .lt. 1 .or. idig .lt. itol) call seterr(
1 33h Burm1 - invalid accuracy request, 36, 5, 2)
qlrg = abs(q(1))
j = 2
goto 2
1 j = j+1
2 if (j .gt. n+1) goto 3
if (qlrg .lt. abs(q(j))) qlrg = abs(q(j))
goto 1
3 if (qlrg .ne. 0.e0) goto 4
call seterr(35h Burm1 - denominator is nonpositive, 35, 6, 2)
goto 11
4 j = 1
goto 6
5 j = j+1
6 if (j .gt. n+1) goto 7
q(j) = q(j)/qlrg
goto 5
7 j = 1
goto 9
8 j = j+1
9 if (j .gt. m+1) goto 10
p(j) = p(j)/qlrg
goto 8
10 continue
11 npptr = istkgt(m+1, 3)
nqptr = istkgt(n+1, 3)
enptr = istkgt(npts, 3)
qkptr = istkgt(npts, 3)
iexptr = istkgt(npts, 2)
call b1rm1(npts, mesh, fn, maxitr, itol, m, n, p, q, delk, ws(
1 npptr), ws(nqptr), ws(enptr), ws(qkptr), istak(iexptr))
call leave
return
end
subroutine b1rm1(npts, x, fn, maxitr, itol, m, n, p, q,
1 delk, newp, newq, en, qk, iext)
integer npts
integer maxitr, itol, m, n, iext(npts)
real x(npts), fn(npts), p(1), q(1), delk, newp(1)
real newq(1), en(npts), qk(npts)
common /dfccom/ nitr
integer nitr
integer ier, nex, nerror, i, imin, imax
integer ilrg, lrgex
real bnd, abs, eps, delnew, r1mach
eps = r1mach(4)*10.0e0**itol
call extrmr(npts, fn, nex, iext, imax, imin, ilrg)
bnd = abs(fn(ilrg))*eps
call enqk(npts, x, fn, m, n, p, q, qk, en)
do 1 i = 1, npts
if (qk(i) .le. 0.0e0) call seterr(
1 35h Burm1 - denominator is nonpositive, 35, 6, 2)
1 continue
call extrmr(npts, en, nex, iext, imax, imin, ilrg)
delk = abs(en(ilrg))
delnew = delk
call movefr(m+1, p, newp)
call movefr(n+1, q, newq)
nitr = 0
goto 3
2 nitr = nitr+1
3 if (nitr .ge. maxitr) goto 6
c call Outpt3 (x,npts,p,q,delk,m,n,en,iext,nex)
if (delk .gt. bnd) goto 4
call seterr(38h Burm1 - approximation equals function, 39, 7
1 , 1)
return
c Test for optimal solution.
4 if (lrgex(npts, en, nex, iext, ilrg, itol) .ge. m+n+2) return
call lpstp(npts, x, fn, qk, delnew, m, n, newp, newq)
if (nerror(ier) .ne. 0) call erroff
call enqk(npts, x, fn, m, n, newp, newq, qk, en)
call extrmr(npts, en, nex, iext, imax, imin, ilrg)
delnew = abs(en(ilrg))
if (delk .gt. delnew) goto 5
call seterr(40h Burm1 - no improvement in approximation, 40,
1 8, 1)
return
5 call movefr(m+1, newp, p)
call movefr(n+1, newq, q)
delk = delnew
goto 2
6 call seterr(42h Burm1 - reached maximum no. of iterations, 42, 9
1 , 1)
return
end
subroutine enqk(npts, x, fn, m, n, p, q, qk, en)
integer npts
integer m, n
real x(npts), fn(npts), p(1), q(1), qk(npts), en(npts)
integer i
real pk, tchbp
c
c Subroutine Enqk computes en & Qk.
c en=error values at mesh points.
c Qk=value of denominator polynomial at mesh points.
c
if (npts .le. 0 .or. m .lt. 0 .or. n .lt. 0) call seterr(
1 22henQk-invalid dimension, 22, 1, 2)
do 1 i = 1, npts
qk(i) = tchbp(n, q, x(i), x(1), x(npts))
if (qk(i) .eq. 0.e0) call seterr(20henQk-divisor .eq. 0., 20, 2
1 , 2)
pk = tchbp(m, p, x(i), x(1), x(npts))
en(i) = (fn(i)*qk(i)-pk)/qk(i)
1 continue
return
end
integer function lrgex(npts, en, nex, iext, ilrg, tol)
integer nex, npts
integer iext(nex), ilrg, tol
real en(npts)
integer j, k, l
real abs, hold
c
c Function Lrgex finds the no. of error extrema with magnitudes
c within tolerance of magnitude of largest error.
c
if (npts .le. 0) call seterr(24hLrgex -invalid dimension, 24, 1, 2
1 )
if (nex .le. 0 .or. ilrg .le. 0) call seterr(
1 20hLrgex -invalid index, 20, 2, 2)
k = 0
do 1 j = 1, nex
l = iext(j)
hold = abs(en(ilrg))-abs(en(l))
if (hold .le. 10.**(-tol)*abs(en(ilrg))) k = k+1
1 continue
lrgex = k
return
end
subroutine lpstp(npts, mesh, fn, qk, delk, m, n, p, q)
integer npts
integer m, n
real mesh(npts), fn(npts), qk(npts), delk, p(1), q(1)
common /cstak/ dstak
double precision dstak(500)
integer istkgt, aptr, bptr, cptr, xptr, istak(1000)
real ws(1000)
equivalence (dstak, istak)
equivalence (dstak, ws)
c Lpstp defines the linear programming subproblem of the
c Differential Correction algorithm. It also provides
c the interface to the general purpose linear programming
c package.
c Input:
c npts - the number of mesh points.
c mesh - the array of mesh points.
c fn - the array of function values.
c Qk - the array of current denominator values.
c delk - the current minimax error.
c m - the degree of the numerator polynomial.
c n - the degree of the denominator polynomial.
c p - the current numerator polynomial.
c q - the current denominator polynomial.
c Output:
c p - the array of coefficients for the numerator polynomial.
c q - the array of coefficients for the denominator polynomial.
c Error States (asterisk indicates fatal):
c 1* - invalid degree
c 2* - too few mesh points
c 3* - nonpositive delk
c 4 - no improvement in the lp subproblem
call enter(1)
if (m .lt. 0 .or. n .lt. 0) call seterr(
1 23h Lpstp - invalid degree, 23, 1, 2)
if (npts .lt. m+n+2) call seterr(28h Lpstp - too few mesh points
1 , 28, 2, 2)
aptr = istkgt(3*npts+1, 3)
bptr = istkgt(2*(npts+n+1), 3)
cptr = istkgt(m+n+3, 3)
xptr = istkgt(m+n+3, 3)
call l9stp(npts, mesh, fn, qk, delk, m, n, p, q, ws(aptr), ws(
1 bptr), ws(cptr), ws(xptr))
call leave
return
end
subroutine l9stp(npts, mesh, fn, qk, delk, m, n, p, q, a, b,
1 c, x)
integer npts
integer m, n
real mesh(npts), fn(npts), qk(npts), delk, p(1), q(1)
real a(1), b(1), c(1), x(1)
common /difcom/ nptsc, mc, nc, i1, i2, i3, i4
integer nptsc, mc, nc, i1, i2, i3
integer i4
external difmt
integer ier, nerror, i, j, ierr, mm
integer nn
real abs, ctx, ctxnew, qlrg, float, r1mach
nptsc = npts
mc = m
nc = n
i1 = npts
i2 = i1+npts
i3 = i2+n+1
i4 = i3+n+1
mm = i4
nn = m+n+3
call movefr(n+1, q, x)
call movefr(m+1, p, x(n+2))
x(nn) = 0.e0
call setr(i2, 0.0e0, b)
call setr(i4-i2, -1.0e0, b(i2+1))
call setr(nn, 0.0e0, c)
c(nn) = -1.0e0
call movefr(npts, mesh, a)
call movefr(npts, fn, a(npts+1))
call movefr(npts, qk, a(2*npts+1))
if (delk .le. 0.0e0) call seterr(25h Lpstp - nonpositive delk, 25,
1 3, 2)
a(3*npts+1) = delk
ctx = 0.0e0
c Solve the LP problem: max C(T)X subject to AX >= B.
c The subroutine Difmt derives the matrix A from
c the data stored in the array A.
call lpph2(a, mm, nn, difmt, b, c, x, 4*mm, ctxnew)
if (nerror(ier) .ne. 0) call erroff
if (ctx .ge. ctxnew) goto 10
qlrg = 0.0e0
j = 1
goto 2
1 j = j+1
2 if (j .gt. n+1) goto 3
if (qlrg .lt. abs(x(j))) qlrg = abs(x(j))
goto 1
3 j = 1
goto 5
4 j = j+1
5 if (j .gt. n+1) goto 6
q(j) = x(j)/qlrg
goto 4
6 i = 0
j = n+2
goto 8
7 j = j+1
8 if (j .gt. m+n+2) goto 9
i = i+1
p(i) = x(j)/qlrg
goto 7
9 continue
goto 11
10 call seterr(44h Lpstp - no improvement in the lp subproblem,
1 44, 4, 1)
11 return
end
subroutine difmt(inprod, a, mm, nn, irow, x, dinprd)
integer nn
integer mm, irow
real a(1), x(nn), dinprd
logical inprod
common /difcom/ npts, m, n, i1, i2, i3, i4
integer npts, m, n, i1, i2, i3
integer i4
integer max0, irm1, irm2, irm3, j, zptr
integer jp, maxmn, fnptr, qzptr
real fct, delk, z, fn, fdelk, tchbp
real qz
c Difmt handles references by the LP routine to
c the matrix for the linear programming subproblem.
call enter(1)
if (mm .ne. i4 .or. nn .ne. m+n+3) call seterr(
1 26h Difmt - invalid dimension, 26, 1, 2)
if (irow .lt. 0 .or. mm .lt. irow) call seterr(
1 22h Difmt - invalid index, 22, 2, 2)
irm1 = irow-i1
irm2 = irow-i2
irm3 = irow-i3
if ((.not. inprod) .or. i2 .ge. irow) goto 3
if (i3 .ge. irow) goto 1
dinprd = -x(irm3)
goto 2
1 dinprd = x(irm2)
2 continue
goto 18
3 if (i2 .ge. irow) goto 6
call setr(nn, 0.0e0, x)
if (i3 .ge. irow) goto 4
x(irm3) = -1.0e0
goto 5
4 x(irm2) = 1.0e0
5 continue
goto 17
6 if (i1 .ge. irow) goto 7
fct = -1.0e0
zptr = irm1
goto 8
7 fct = 1.0e0
zptr = irow
8 z = a(zptr)
fnptr = zptr+npts
fn = a(fnptr)
qzptr = fnptr+npts
qz = a(qzptr)
delk = a(3*npts+1)
fdelk = fct*fn+delk
if (.not. inprod) goto 9
dinprd = fdelk*tchbp(n, x, z, a(1), a(npts))-fct*tchbp(m,
1 x(n+2), z, a(1), a(npts))+qz*x(nn)
goto 16
9 maxmn = max0(m, n)
call tchcf(z, a(1), a(npts), maxmn, x)
j = m+1
goto 11
10 j = j-1
11 if (1 .gt. j) goto 12
jp = j+n+1
x(jp) = (-fct)*x(j)
goto 10
12 j = 1
goto 14
13 j = j+1
14 if (j .gt. n+1) goto 15
x(j) = fdelk*x(j)
goto 13
15 x(nn) = qz
16 continue
17 continue
18 call leave
return
end
subroutine tchcf(x, a, b, deg, xx)
integer deg
real x, a, b, xx(1)
integer i
real twoxx
c
c Subroutine Tchcf computes the deg+1 Tchebycheff
c coefficients of the point x.
c
call enter(1)
if (deg .lt. 0) call seterr(21h Tchcf-invalid degree, 21, 1, 2)
xx(1) = 1.e0
if (deg .le. 0) goto 3
if (b .gt. a) goto 1
call seterr(23h Tchcf-invalid interval, 23, 2, 2)
goto 2
1 xx(2) = 2.e0*(x-(a+b)/2.e0)/(b-a)
cscale x to the interval (-1.e0,1.e0)
2 continue
3 if (deg .gt. 1) twoxx = 2.e0*xx(2)
i = 3
goto 5
4 i = i+1
5 if (i .gt. deg+1) goto 6
xx(i) = twoxx*xx(i-1)-xx(i-2)
goto 4
6 call leave
return
end
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.