The R Project SVN R-packages

Rev

Rev 139 | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

cMM this is the original adapt code with one modification.
cMM instead of calling the external function "functn", a fixed
cMM external routine adphlp is always called, and passed a pointer
cMM to the external s function.
cMM                 Michael Meyer, October 1989.

      subroutine adapt(ndim,a,b,minpts,maxpts,eps,relerr,
     *     lenwrk,wrkstr,finest,ifail)
c***begin prologue adapt
c  adaptive multidimensional integration subroutine
c       author: A. C. Genz, Washington State University
c            19 March 1984
c**************  parameters for adapt  ********************************
c***** input parameters
c  ndim    number of variables, must exceed 1, but not exceed 20
c  a       real array of lower limits, with dimension ndim
c  b       real array of upper limits, with dimension ndim
c  minpts  minimum number of function evaluations to be allowed.
c      on the first call to adapt minpts should be set to a
c      non negative value (caution... minpts is altered by adapt).
c      It is possible to continue a calculation to greater accuracy
c      by calling adapt again by decreasing eps (described below)
c      and resetting minpts to any negative value.
c      minpts must not exceed maxpts.
c  maxpts  maximum number of function evaluations to be allowed,
c      which must be at least rulcls, where
c      rulcls =  2**ndim+2*ndim**2+6*ndim+1
c
c          for ndim =  2   3   4   5   6   7   8   9   10   12    15      20
c      maxpts >= rulcls = 25  45  73 113 173 269 433 729 1285 4457 33309 1049497
c
c     a SUGGESTED value for maxpts is 100 times the above values.
c
c  functn  externally declared user defined function to be integrated.
c      it must have parameters (ndim,z), where z is a real array
c      of dimension ndim.
cTSL this function has been replaced by the fixed function adhlp
c  eps     required relative accuracy
c  lenwrk  length of array wrkstr of working storage, the routine
c      needs (2*ndim+3)*(1+maxpts/rulcls)/2 for lenwrk if
c      maxpts function calls are used.
c      for guidance, if you set maxpts to 100*rulcls (see table
c      above) then acceptable values for lenwrk are
c
c        for ndim = 2    3    4    5    6    7    8     9
c        lenwrk =  357  561  1785 3417 6681 13209 26265 52377
c
c***** OUTPUT parameters
c
c  minpts  actual number of function evaluations used by adapt
c  wrkstr  real array of working storage of dimension (lenwrk).
c  relerr  estimated relative accuracy of finest
c  finest  estimated value of integral ["FINal ESTimate"]
c  ifail : return code
c
c   ifail=0 for normal exit, when estimated relative accuracy
c       relerr is less than eps with maxpts or less function
c       calls made.
c   ifail=1 if maxpts was too small for adapt to obtain the
c       required relative accuracy eps.
c       In this case adapt returns a value of finest
c       with estimated relative accuracy relerr.
c   ifail=2 if lenwrk too small for maxpts function calls.
c       In this case adapt returns a value of finest with
c       estimated accuracy relerr using the working storage
c       available, but relerr will be greater than eps.
c   ifail=3 if ndim < 2, ndim > 20,
c   ifail=4 if minpts > maxpts,
c   ifail=5 if maxpts < rulcls or other memory problems
c             (which will only be found later)
c***********************************************************************
c***end prologue adapt

      implicit none

C-- Arguments:
C      double precision functn
C      external functn

      integer ndim, minpts,maxpts, lenwrk, ifail
      double precision a(ndim), b(ndim), eps, relerr, wrkstr(lenwrk),
     &     finest

C-- Local Variables:
      double precision center(20), width(20)
      double precision errmin, rgnerr, rgnval, half, zero,one,two

      integer divaxo, divaxn, divflg, funcls, index1, index2,
     *     j, k,  maxcls, rgnstr, rulcls, sbrgns, sbtmpp, subrgn, subtmp

      data zero/0d0/, one/1d0/, two/2d0/

c Check arguments; fail w/ code '3' or '4'
      relerr=one
      funcls=0
      ifail=3
      if(ndim.lt.2 .or. ndim.gt.20) goto 990
      ifail=4
      if(minpts.gt.maxpts) goto 990
      ifail=5
c
c*****  initialisation of subroutine
c
      half=one/two
      rgnstr = 2*ndim+3
      errmin = zero
      maxcls = 2**ndim + 2*ndim**2 + 6*ndim+1
      maxcls = min0(maxcls,maxpts)
      divaxo=0
c
c*****  end subroutine initialisation

      if(minpts.lt.0) then
c   on re-entry {with intact  lenwrk, wrkstr(1:lenwrk)} :
         sbrgns=wrkstr(lenwrk-1)
         goto 280
      endif

      do 30 j=1,ndim
     width(j)=(b(j)-a(j))*half
 30  center(j)=a(j)+width(j)
      finest=zero
      wrkstr(lenwrk)=zero
      divflg=1
      subrgn=rgnstr
      sbrgns=rgnstr

C-- REPEAT --- (outermost loop) -------
   40 call bsrl(ndim,center,width,maxcls,rulcls,
     *     errmin,rgnerr,rgnval,divaxo,divaxn)
      finest=finest+rgnval
      wrkstr(lenwrk)=wrkstr(lenwrk)+rgnerr
      funcls = funcls + rulcls
c
c*****  place results of basic rule into partially ordered list
c*****  according to subregion error

      if(divflg .eq. 0) then
c
c   *** when divflg=0 start at top of list and move down list tree to
c       find correct position for results from first half of recently
c       divided subregion
 200     subtmp=2*subrgn
     if(subtmp.le.sbrgns) then
        if(subtmp.ne.sbrgns) then
           sbtmpp=subtmp+rgnstr
           if(wrkstr(subtmp).lt.wrkstr(sbtmpp)) subtmp=sbtmpp
        endif
        if(rgnerr.lt.wrkstr(subtmp)) then
           do 220 k=1,rgnstr
          index1=subrgn-k+1
          index2=subtmp-k+1
          wrkstr(index1)=wrkstr(index2)
 220           continue
           subrgn=subtmp

           goto 200
        endif
     endif

      else
c
c   *** when divflg=1 start at bottom right branch and move up list
c       tree to find correct position for results from second half of
c       recently divided subregion
 230     subtmp=(subrgn/(rgnstr*2))*rgnstr
     if(subtmp.ge.rgnstr) then
        if(rgnerr.gt.wrkstr(subtmp)) then
           do 240 k=1,rgnstr
          index1=subrgn-k+1
          index2=subtmp-k+1
          wrkstr(index1)=wrkstr(index2)
 240           continue
           subrgn=subtmp
           goto 230
        endif
     endif
      endif

c**** store results (length= 2*ndim+3) of basic rule
c     in correct position in list:
  250 wrkstr(subrgn)=rgnerr
      wrkstr(subrgn-1)=rgnval
      wrkstr(subrgn-2)=divaxn
      do 260 j=1,ndim
    subtmp=subrgn-2*(j+1)
    wrkstr(subtmp+1)=center(j)
    wrkstr(subtmp)=width(j)
 260  continue

      if(divflg .eq. 0) then
c***  when divflg=0 prepare for second application of basic rule
     center(divaxo)=center(divaxo)+two*width(divaxo)
     sbrgns=sbrgns+rgnstr
     subrgn=sbrgns
     divflg=1
c***  loop back to apply basic rule to other half of subregion
     go to 40
      endif
c
c*****  end ordering and storage of basic rule results
c*****  make checks for possible termination of routine
c
  270 relerr=one
      if(wrkstr(lenwrk).le.zero) wrkstr(lenwrk)=zero
      if(dabs(finest).ne.zero) relerr=wrkstr(lenwrk)/dabs(finest)
      if(relerr.gt.one) relerr=one

      if(sbrgns+rgnstr .gt. lenwrk-2) ifail=2
c     MM: Note that rgnstr = 2*ndim+3, and lenwrk
c     --  lenwrk = (2*ndim + 3)* (1 + maxpts/rulcls)/2
c         where rulcls = 2^ndim + 2*ndim^2 + 6*ndim + 1
c         and   maxpts increases (for each .C() call from R)
      if(funcls+funcls*rgnstr/sbrgns.gt.maxpts) ifail=1
      if(relerr.lt.eps.and.funcls.ge.minpts) ifail=0
      if(ifail.lt.3) goto 990
c
c*****  prepare to use basic rule on each half of subregion with largest
c   error
  280 divflg=0
      subrgn=rgnstr
      subtmp = 2*sbrgns/rgnstr
      maxcls = maxpts/subtmp
      errmin = dabs(finest)*eps/dfloat(subtmp)
      wrkstr(lenwrk)=wrkstr(lenwrk)-wrkstr(subrgn)
      finest=finest-wrkstr(subrgn-1)
      divaxo=wrkstr(subrgn-2)
      do 290 j=1,ndim
    subtmp=subrgn-2*(j+1)
    center(j)=wrkstr(subtmp+1)
  290   width(j)=wrkstr(subtmp)
      width(divaxo)=width(divaxo)*half
      center(divaxo)=center(divaxo)-width(divaxo)
c
c*****  loop back to apply basic rule
c
      goto 40
c
c*****  termination point
c
  990 minpts=funcls
      wrkstr(lenwrk-1)=sbrgns
      return
      end