C
C     Modified from the SMART package by J.H. Friedman, 10/10/84
C     Main change is to add spline smoothing modified from BRUTO,
C     calling code written for smooth.spline in S.
C
C     B.D. Ripley (ripley@stats.ox.ac.uk)  1994-7.
C
C
      subroutine smart(m,mu,p,q,n, w,x,y,ww,smod,nsmod,
     &     sp,nsp,dp,ndp,edf)

      integer m,mu,p,q,n, nsmod, nsp,ndp
      double precision x(p,n),y(q,n),w(n),ww(q),smod(nsmod),
     &     sp(nsp),edf(m),dp(ndp)
      smod(1)=m
      smod(2)=p
      smod(3)=q
      smod(4)=n
      call smart1(m,mu,p,q,n, w,x,y,ww, smod(6),smod(q+6),
     &     smod(q+7),smod(q+7+p*m),smod(q+7+m*(p+q)),
     &     smod(q+7+m*(p+q+n)),smod(q+7+m*(p+q+2*n)),
     &     sp,sp(q*n+1),sp(n*(q+15)+1),sp(n*(q+15)+q+1),
     &     dp,smod(5),edf)
      return
      end

      subroutine smart1(m,mu,p,q,n, w,x,y,ww, yb,ys,
     &     a,b,f,
     &     t,asr,
     &     r,sc,bt,g,
     &     dp,flm,edf)

      integer m,mu,p,q,n
      double precision w(n),x(p,n),y(*),ww(q), yb(q), ys
      double precision a(p,m),b(q,m),f(n,m),t(n,m), asr(15),asr1
      double precision r(q,n),sc(n,15),bt(q),g(p,3)
      double precision dp(*), flm,edf(m)
C                        ^^^ really (ndb) of  smart(.)
      integer i,j,l, lm
      double precision sw,s
c Common Vars
      double precision       span,alpha,big
      integer         ifl,lf
      common /pprpar/ ifl,lf,span,alpha,big

      double precision conv,            cutmin,fdel,cjeps
      integer              maxit,mitone,                  mitcj
      common /pprz01/ conv,maxit,mitone,cutmin,fdel,cjeps,mitcj

      sw=0d0
      do j=1,n
         sw=sw+w(j)
      end do
      do j=1,n
         do i=1,q
            r(i,j)=y(q*(j-1)+i)
         end do
      end do
      do i=1,q
         s=0d0
         do j=1,n
            s=s+w(j)*r(i,j)
         end do
         yb(i)=s/sw
      end do
c     yb is vector of means
      do j=1,n
        do i=1,q
          r(i,j)=r(i,j)-yb(i)
         end do
      end do
      ys=0.d0
      do i=1,q
         s=0.d0
         do j=1,n
            s=s+w(j)*r(i,j)**2
         end do
         ys=ys+ww(i)*s/sw
      end do
      if(ys .gt. 0d0) goto 311
c     ys is the overall standard deviation -- quit if zero
      return

 311  continue
      ys=sqrt(ys)
      s=1.d0/ys
      do j=1,n
         do i=1,q
            r(i,j)=r(i,j)*s
         end do
      end do

c     r is now standardized residuals
c     subfit adds up to m  terms one at time; lm is the number fitted.
      call subfit(m,p,q,n,w,sw,x,r,ww,lm,a,b,f,t,asr(1),sc,bt,g,dp,edf)
      if(lf.le.0) go to 9999
      call fulfit(lm,lf,p,q,n,w,sw,x,r,ww,a,b,f,t,asr,sc,bt,g,dp,edf)
C REPEAT
 371  continue
      do l=1,lm
        sc(l,1)=l+0.1d0
        s=0d0
        do i=1,q
           s=s+ww(i)*abs(b(i,l))
        end do
        sc(l,2)=-s
      end do
      call sort(sc(1,2),sc,1,lm)
      do j=1,n
         do i=1,q
            r(i,j)=y(q*(j-1)+i)
         end do
      end do

      do i=1,q
        do j=1,n
           r(i,j)=r(i,j)-yb(i)
           s=0.d0
           do l=1,lm
              s=s+b(i,l)*f(j,l)
           end do
          r(i,j)=r(i,j)/ys-s
         end do
      end do

      if(lm.le.mu) goto 9999
c back to integer:
      l=int(sc(lm,1))
      asr1=0d0
      do j=1,n
        do i=1,q
          r(i,j)=r(i,j)+b(i,l)*f(j,l)
          asr1=asr1+w(j)*ww(i)*r(i,j)**2
         end do
      end do

      asr1=asr1/sw
      asr(1)=asr1
      if(l .ge. lm) goto 591
      do i=1,p
         a(i,l)=a(i,lm)
      end do
      do i=1,q
         b(i,l)=b(i,lm)
      end do
      do j=1,n
         f(j,l)=f(j,lm)
         t(j,l)=t(j,lm)
      end do

 591  continue
      lm=lm-1
      call fulfit(lm,lf,p,q,n,w,sw,x,r,ww,a,b,f,t,asr,sc,bt,g,dp,edf)
      goto 371
C END REPEAT
 9999 continue
      flm=lm
      return
      end

      subroutine subfit(m,p,q,n,w,sw,x,r,ww,lm,a,b,f,t,asr,sc,
     &     bt,g,dp,edf)
c Args
      integer           m,p,q,n,            lm
      double precision w(n),sw, x(p,n),r(q,n),ww(q),a(p,m),b(q,m),
     &     f(n,m), t(n,m), asr(15), sc(n,15), bt(q), g(p,3), edf(m)
      double precision dp(*)
c Var
      integer i,j,l, iflsv
      double precision asrold
c Common Vars
      double precision       span,alpha,big
      integer         ifl,lf
      common /pprpar/ ifl,lf,span,alpha,big

      double precision conv,            cutmin,fdel,cjeps
      integer              maxit,mitone,                  mitcj
      common /pprz01/ conv,maxit,mitone,cutmin,fdel,cjeps,mitcj

      asr(1)=big
      lm=0
      do 100 l=1,m
         call rchkusr()
         lm=lm+1
         asrold=asr(1)
         call newb(lm,q,ww,b)
c does 'edf' mean 'edf(1)' or 'edf(l)'?
         call onetrm(0,p,q,n,w,sw,x,r,ww,a(1,lm),b(1,lm),
     &        f(1,lm),t(1,lm),asr(1),sc,g,dp,edf(1))
         do 20 j=1,n
            do 10 i=1,q
               r(i,j)=r(i,j)-b(i,lm)*f(j,lm)
 10         continue
 20      continue
         if(lm.eq.1) goto 100
         if(lf.gt.0) then
            if(lm.eq.m) return
            iflsv=ifl
            ifl=0
            call fulfit(lm,1,p,q,n,w,sw,x,r,ww,a,b,f,t,asr,sc,bt,
     &           g,dp, edf)
            ifl=iflsv
         endif
         if(asr(1).le.0d0.or.(asrold-asr(1))/asrold.lt.conv) return
100   continue
      return
      end

      subroutine fulfit(lm,lbf,p,q,n,w,sw,x,r,ww,a,b,f,t,
     &     asr,sc,bt,g,dp,edf)
c Args
      integer           lm,lbf,p,q,n
      double precision w(n),sw,x(p,n),r(q,n),ww(q),a(p,lm),b(q,lm),
     &     f(n,lm),t(n,lm),asr(1+lm), sc(n,15),bt(q),g(p,3), edf(lm)
      double precision dp(*)
c Var
      double precision asri, fsv, asrold
      integer i,j,iter,lp,isv
c Common Vars
      double precision       span,alpha,big
      integer         ifl,lf
      common /pprpar/ ifl,lf,span,alpha,big

      double precision conv,            cutmin,fdel,cjeps
      integer              maxit,mitone,                  mitcj
      common /pprz01/ conv,maxit,mitone,cutmin,fdel,cjeps,mitcj

      if(lbf.le.0) return
      asri=asr(1)
      fsv=cutmin
      isv=mitone
      if(lbf .lt. 3) then
         cutmin=1d0
         mitone=lbf-1
      endif
      iter=0
C Outer loop:
1000  continue
      asrold=asri
      iter=iter+1
      do 100 lp=1,lm
        do 10 i=1,q
           bt(i)=b(i,lp)
 10     continue
        do 20 i=1,p
           g(i,3)=a(i,lp)
 20     continue
        do 35 j=1,n
          do 30 i=1,q
             r(i,j)=r(i,j)+bt(i)*f(j,lp)
 30       continue
 35    continue

        call onetrm(1,p,q,n,w,sw,x,r,ww,g(1,3),bt,sc(1,14),sc(1,15),
     &            asri,sc,g,dp,edf(lp))
        if(asri .lt. asrold) then
           do 40 i=1,q
              b(i,lp)=bt(i)
 40        continue
           do 50 i=1,p
              a(i,lp)=g(i,3)
 50        continue
           do 60 j=1,n
              f(j,lp)=sc(j,14)
              t(j,lp)=sc(j,15)
 60        continue
        else
           asri=asrold
        endif
        do 85 j=1,n
          do 80 i=1,q
             r(i,j)=r(i,j)-b(i,lp)*f(j,lp)
 80       continue
 85    continue
100   continue
      if((iter .le. maxit) .and. ((asri .gt. 0d0)
     &     .and. ((asrold-asri)/asrold .ge. conv))) goto 1000
      cutmin=fsv
      mitone=isv
      if(ifl .gt. 0) then
         asr(1+lm) = asri
         asr(1) = asri
      endif
      return
      end

      subroutine onetrm(jfl,p,q,n,w,sw,x,y,ww,a,b,f,t,asr,
     &     sc,g,dp,edf)
c Args
      integer           jfl,p,q,n
      double precision w(n),sw, x(p,n),y(q,n),ww(q),a(p),b(q),f(n),t(n),
     &     asr, sc(n,13),g(p,2), edf
      double precision dp(*)
c Var
      double precision asrold,s
      integer i,j,iter
c Common Vars
      double precision       span,alpha,big
      integer         ifl,lf
      common /pprpar/ ifl,lf,span,alpha,big

      double precision conv,            cutmin,fdel,cjeps
      integer              maxit,mitone,                  mitcj
      common /pprz01/ conv,maxit,mitone,cutmin,fdel,cjeps,mitcj

      iter=0
      asr=big
C REPEAT
1000  continue
      iter=iter+1
      asrold=asr
      do j=1,n
         s=0d0
         do i=1,q
            s=s+ww(i)*b(i)*y(i,j)
         end do
         sc(j,13)=s
      end do
      call oneone(max0(jfl,iter-1),p,n,w,sw,sc(1,13),x,a,f,t,
     &                 asr,sc,g,dp,edf)
      do 31 i=1,q
        s=0d0
        do j=1,n
           s=s+w(j)*y(i,j)*f(j)
        end do
        b(i)=s/sw
 31   continue
      asr=0d0
      do 51 i=1,q
         s=0d0
         do j=1,n
            s=s+w(j)*(y(i,j)-b(i)*f(j))**2
         end do
         asr=asr+ww(i)*s/sw
 51   continue
      if((q .ne. 1) .and. (iter .le. maxit) .and. (asr .gt. 0d0)
     &      .and. (asrold-asr)/asrold .ge. conv) goto 1000
c has converged:
      return
      end

      subroutine oneone(ist,p,n, w,sw,y,x,a,f,t,asr,sc,g,dp,edf)
c Args
      integer           ist,p,n
      double precision w(n),sw,y(n),x(p,n),a(p),f(n),t(n),asr,
     &     sc(n,12), g(p,2), edf, dp(*)
c Var
      integer i,j,k,iter
      double precision sml, s,v,cut,asrold
c Common Vars
      double precision       span,alpha,big
      integer         ifl,lf
      common /pprpar/ ifl,lf,span,alpha,big

      double precision conv,            cutmin,fdel,cjeps
      integer              maxit,mitone,                  mitcj
      common /pprz01/ conv,maxit,mitone,cutmin,fdel,cjeps,mitcj

      sml=1d0/big
      if(ist .le. 0) then
        if(p .le. 1) a(1)=1d0
        do j=1,n
           sc(j,2)=1d0
        end do
        call pprdir(p,n,w,sw,y,x,sc(1,2),a,dp)
      endif
      s=0d0
      do i=1,p
         g(i,1)=0d0
         s=s+a(i)**2
      end do
      s=1d0/sqrt(s)
      do i=1,p
        a(i)=a(i)*s
      end do
      iter=0
      asr=big
      cut=1d0
C REPEAT -----------------------------
 100  continue
      iter=iter+1
      asrold=asr
C REPEAT [inner loop] -----
 60   continue
      s=0d0
      do i=1,p
        g(i,2)=a(i)+g(i,1)
        s=s+g(i,2)**2
      end do
      s=1.d0/sqrt(s)
      do i=1,p
        g(i,2)=g(i,2)*s
      end do
      do j=1,n
        sc(j,1)=j+0.1d0
        s=0.d0
        do i=1,p
          s=s+g(i,2)*x(i,j)
        end do
        sc(j,11)=s
      end do
      call sort(sc(1,11),sc,1,n)
      do j=1,n
        k=int(sc(j,1))
        sc(j,2)=y(k)
        sc(j,3)=max(w(k),sml)
      end do
c          supsmu(n,  x,         y,      w, iper,span,alpha,
      call supsmu(n,sc(1,11),sc(1,2),sc(1,3), 1, span,alpha,
     &     sc(1,12),sc(1,4), edf)
c             smo  , sc ,    edf)
      s=0d0
      do j=1,n
        s=s+sc(j,3)*(sc(j,2)-sc(j,12))**2
      end do
      s=s/sw
      if(s .lt. asr) goto 140
      cut=cut*0.5d0
      if(cut.lt.cutmin) goto 199
      do i=1,p
        g(i,1)=g(i,1)*cut
      end do
      go to 60
C     --------
 140  continue
      asr=s
      cut=1d0
      do i=1,p
        a(i)=g(i,2)
      end do
      do j=1,n
        k=int(sc(j,1))
        t(k)=sc(j,11)
        f(k)=sc(j,12)
      end do
      if(asr.le.0d0.or.(asrold-asr)/asrold.lt.conv) goto 199
      if(iter.gt.mitone.or.p.le.1) goto 199
      call pprder(n,sc(1,11),sc(1,12),sc(1,3),fdel,sc(1,4),sc(1,5))
      do j=1,n
        k=int(sc(j,1))
        sc(j,5)=y(j)-f(j)
        sc(k,6)=sc(j,4)
      end do
      call pprdir(p,n,w,sw,sc(1,5),x,sc(1,6),g,dp)

      goto 100
c--------------
 199   continue
c--------------
      s=0d0
      v=s
      do j=1,n
        s=s+w(j)*f(j)
      end do
      s=s/sw
      do j=1,n
        f(j)=f(j)-s
        v=v+w(j)*f(j)**2
      end do
      if(v .gt. 0d0) then
         v=1d0/sqrt(v/sw)
         do j=1,n
            f(j)=f(j)*v
         end do
      endif
      return
      end


      subroutine pprdir(p,n,w,sw,r,x,d,e,g)

      integer           p,n
      double precision      w(n),sw,r(n),x(p,n),d(n),e(p), g(*)

      double precision s
      integer i,j,k,l,m1,m2

      double precision conv,            cutmin,fdel,cjeps
      integer              maxit,mitone,                  mitcj
      common /pprz01/ conv,maxit,mitone,cutmin,fdel,cjeps,mitcj

      do 10 i=1,p
         s=0d0
         do j=1,n
            s=s+w(j)*d(j)*x(i,j)
         end do
         e(i)=s/sw
 10   continue
      k=0
      m1=p*(p+1)/2
      m2=m1+p
      do 20 j=1,p
         s=0d0
         do l=1,n
            s=s+w(l)*r(l)*(d(l)*x(j,l)-e(j))
         end do
         g(m1+j)=s/sw
         do i=1,j
            s=0d0
            do l=1,n
               s=s+w(l)*(d(l)*x(i,l)-e(i))*(d(l)*x(j,l)-e(j))
            end do
            k=k+1
            g(k)=s/sw
         end do
 20   continue
      call ppconj(p,g,g(m1+1),g(m2+1),cjeps,mitcj,g(m2+p+1))
      do i=1,p
         e(i)=g(m2+i)
      end do
      return
      end

      subroutine ppconj(p,g,c,x,eps,maxit,sc)
      integer p,maxit
      double precision g(*),c(p),x(p),eps,sc(p,4)

      integer i,j,im1,iter,nit
      double precision beta,h,s,alpha,t

      do 1 i=1,p
         x(i)=0d0
         sc(i,2)=0d0
 1    continue
      nit=0
C REPEAT
11321 continue
      nit=nit+1
      h=0d0
      beta=0d0
      do 11331 i=1,p
        sc(i,4)=x(i)
        s=g(i*(i-1)/2+i)*x(i)
        im1=i-1
        j=1
        goto 11343
11341   j=j+1
11343   if(j.gt.im1) goto 11342
        s=s+g(i*(i-1)/2+j)*x(j)
        goto 11341
11342   continue
        j=i+1
        goto 11353
11351   j=j+1
11353   if(j.gt.p) goto 11352
        s=s+g(j*(j-1)/2+i)*x(j)
        goto 11351
11352   continue
        sc(i,1)=s-c(i)
        h=h+sc(i,1)**2
11331 continue
      if(h.le.0d0) return ! ----
      do iter=1,p
        do i=1,p
          sc(i,2)=beta*sc(i,2)-sc(i,1)
        end do
        t=0d0
        do 11381 i=1,p
          s=g(i*(i-1)/2+i)*sc(i,2)
          im1=i-1
          j=1
c        WHILE j <= i-1
11393     if(j.le.im1) then
             s=s+g(i*(i-1)/2+j)*sc(j,2)
             j=j+1
             goto 11393
          end if
c 11392   continue
          j=i+1
c        WHILE j <= p
11403     if(j.le.p) then
             s=s+g(j*(j-1)/2+i)*sc(j,2)
             j=j+1
             goto 11403
          end if
c 11402     continue
          sc(i,3)=s
          t=t+s*sc(i,2)
11381   continue
        alpha=h/t
        s=0d0
        do i=1,p
          x(i)=x(i)+alpha*sc(i,2)
          sc(i,1)=sc(i,1)+alpha*sc(i,3)
          s=s+sc(i,1)**2
        end do
        if(s.le.0d0) goto 11362
        beta=s/h
        h=s
      end do ! iter
11362 continue
      s=0d0
      do i=1,p
        s=dmax1(s,dabs(x(i)-sc(i,4)))
      end do
      if((s .ge. eps) .and. (nit .lt. maxit)) goto 11321
      return
      end

      subroutine pprder (n,x,s,w,fdel,d,sc)
      integer n
      double precision x(n),s(n),w(n), fdel, d(n),sc(n,3)

      integer i,j,bl,el,bc,ec,br,er
      double precision scale, del
c
c     unnecessary initialization of bl el ec to keep g77 -Wall happy
c
      bl = 0
      el = 0
      ec = 0
c
      if(x(n) .gt. x(1)) goto 11441
      do 11451 j=1,n
      d(j)=0d0
11451 continue
      return
11441 continue
      i=n/4
      j=3*i
      scale=x(j)-x(i)
11461 if(scale.gt.0d0) goto 11462
      if(j.lt.n) j=j+1
      if(i.gt.1) i=i-1
      scale=x(j)-x(i)
      goto 11461
11462 continue
      del=fdel*scale*2d0
      do 11471 j=1,n
      sc(j,1)=x(j)
      sc(j,2)=s(j)
      sc(j,3)=w(j)
11471 continue
      call pool (n,sc,sc(1,2),sc(1,3),del)
      bc=0
      br=bc
      er=br
11481 continue
      br=er+1
      er=br
11491 if(er .ge. n) goto 11492
      if(sc(br,1) .ne. sc(er+1,1)) goto 11511
      er=er+1
      goto 11521
11511 continue
      goto 11492
11521 continue
      goto 11491
11492 continue
      if(br .ne. 1) goto 11541
      bl=br
      el=er
      goto 11481
11541 continue
      if(bc .ne. 0) goto 11561
      bc=br
      ec=er
      do 11571 j=bl,el
      d(j)=(sc(bc,2)-sc(bl,2))/(sc(bc,1)-sc(bl,1))
11571 continue
      goto 11481
11561 continue
c sanity check needed for PR#13517
      if(br.gt.n) call rexit('br is too large')
      do 11581 j=bc,ec
      d(j)=(sc(br,2)-sc(bl,2))/(sc(br,1)-sc(bl,1))
11581 continue
      if(er .ne. n) goto 11601
      do 11611 j=br,er
      d(j)=(sc(br,2)-sc(bc,2))/(sc(br,1)-sc(bc,1))
11611 continue
      goto 11482
11601 continue
      bl=bc
      el=ec
      bc=br
      ec=er
      goto 11481
11482 continue
      return
      end

      subroutine pool (n,x,y,w,del)
      integer n
      double precision x(n),y(n),w(n),del

      integer i,bb,eb,br,er,bl,el
      double precision px, py, pw

      bb=0
      eb=bb
11621 if(eb.ge.n) goto 11622
      bb=eb+1
      eb=bb
11631 if(eb .ge. n) goto 11632
      if(x(bb) .ne. x(eb+1)) goto 11651
      eb=eb+1
      goto 11661
11651 continue
      goto 11632
11661 continue
      goto 11631
11632 continue
      if(eb .ge. n) goto 11681
      if(x(eb+1)-x(eb) .ge. del) goto 11701
      br=eb+1
      er=br
11711 if(er .ge. n) goto 11712
      if(x(er+1) .ne. x(br)) goto 11731
      er=er+1
      goto 11741
11731 continue
      goto 11712
11741 continue
      goto 11711
11712 continue
C avoid bounds error: this was .and. but order is not guaranteed
      if(er.lt.n) then
        if(x(er+1)-x(er).lt.x(eb+1)-x(eb)) goto 11621
      endif
      eb=er
      pw=w(bb)+w(eb)
      px=(x(bb)*w(bb)+x(eb)*w(eb))/pw
      py=(y(bb)*w(bb)+y(eb)*w(eb))/pw
      do 11751 i=bb,eb
      x(i)=px
      y(i)=py
      w(i)=pw
11751 continue
11701 continue
11681 continue
11761 continue
      if(bb.le.1) goto 11762
      if(x(bb)-x(bb-1).ge.del) goto 11762
      bl=bb-1
      el=bl
11771 if(bl .le. 1) goto 11772
      if(x(bl-1) .ne. x(el)) goto 11791
      bl=bl-1
      goto 11801
11791 continue
      goto 11772
11801 continue
      goto 11771
11772 continue
      bb=bl
      pw=w(bb)+w(eb)
      px=(x(bb)*w(bb)+x(eb)*w(eb))/pw
      py=(y(bb)*w(bb)+y(eb)*w(eb))/pw
      do 11811 i=bb,eb
      x(i)=px
      y(i)=py
      w(i)=pw
11811 continue
      goto 11761
11762 continue
      goto 11621
11622 continue
      return
      end

      subroutine newb(lm,q,ww,b)
      integer lm, q
      double precision ww(q),b(q,lm)

      integer i,lm1,l,l1
      double precision s,t,sml
c Common
      double precision       span,alpha,big
      integer         ifl,lf
      common /pprpar/ ifl,lf,span,alpha,big


      sml=1d0/big
      if(q .ne. 1) goto 11831
      b(1,lm)=1d0
      return
11831 continue
      if(lm .ne. 1) goto 11851
      do 11861 i=1,q
      b(i,lm)=i
11861 continue
      return
11851 continue
      lm1=lm-1
      do 11871 i=1,q
      b(i,lm)=0d0
11871 continue
      t=0d0
      do 11881 i=1,q
      s=0d0
      do 11891 l=1,lm1
      s=s+abs(b(i,l))
11891 continue
      b(i,lm)=s
      t=t+s
11881 continue
      do 11901 i=1,q
      b(i,lm)=ww(i)*(t-b(i,lm))
11901 continue
      l1=1
      if(lm.gt.q) l1=lm-q+1
      do 11911 l=l1,lm1
      s=0d0
      t=s
      do 11921 i=1,q
      s=s+ww(i)*b(i,lm)*b(i,l)
      t=t+ww(i)*b(i,l)**2
11921 continue
      s=s/sqrt(t)
      do 11931 i=1,q
      b(i,lm)=b(i,lm)-s*b(i,l)
11931 continue
11911 continue
      do 11941 i=2,q
      if(abs(b(i-1,lm)-b(i,lm)).gt.sml) return
11941 continue
      do 11951 i=1,q
      b(i,lm)=i
11951 continue
      return
      end

      block data bkppr

c Common Vars
      double precision       span,alpha,big
      integer         ifl,lf
      common /pprpar/ ifl,lf,span,alpha,big

      double precision conv,            cutmin,fdel,cjeps
      integer              maxit,mitone,                  mitcj
      common /pprz01/ conv,maxit,mitone,cutmin,fdel,cjeps,mitcj

      double precision  df, gcvpen
      integer                       ismethod
      logical                                 trace
      common /spsmooth/ df, gcvpen, ismethod, trace

c     NB: Several of these are modified by calls, but some are currently hard-wired *constant*
c         {even though they need not, e.g., {maxit, conv, fdel, cjeps, mitcj}

      data df, gcvpen, ismethod, trace /4d0, 1d0, 0, .false./
      data ifl,maxit, conv, mitone, cutmin, fdel
     &    / 6,  20,  .005_8,   20,   0.1_8, 0.02_8 /
      data span,alpha, big,   cjeps,  mitcj, lf
     &    / 0.0, 0.0, 1.0e20, 0.001_8,   1,   2 /
      end

      subroutine setppr(span1, alpha1, optlevel, ism, df1, gcvpen1)
c Put 'parameters' into Common blocks
      integer optlevel,ism
      double precision span1,alpha1, df1, gcvpen1

      double precision       span,alpha,big
      integer         ifl,lf
      common /pprpar/ ifl,lf,span,alpha,big

      double precision  df, gcvpen
      integer                       ismethod
      logical                                 trace
      common /spsmooth/ df, gcvpen, ismethod, trace

      span = span1
      lf = optlevel
      alpha = alpha1
      if(ism .ge. 0) then
         ismethod = ism
         trace = .false.
      else
         ismethod = -(ism+1)
         trace = .true.
      end if
      df = df1
      gcvpen = gcvpen1
      return
      end

      subroutine fsort(mu,n,f,t,sp)
c
      integer mu, n
      double precision f(n,mu),t(n,mu),sp(n,2)
c
      integer l,j,k

      do 100 l=1,mu
         do 10 j=1,n
            sp(j,1)=j+0.1d0
            sp(j,2)=f(j,l)
 10      continue
         call sort(t(1,l),sp,1,n)
         do 20 j=1,n
            k=int(sp(j,1))
            f(j,l)=sp(k,2)
 20      continue
 100  continue
      return
      end

      subroutine pppred(np,x,smod,y,sc)

      integer np
      double precision x(np,*),y(np,*),smod(*), sc(*)

      integer p,q, place,low,high, i,j,l,m,n,
     +     inp,ja,jb,jf,jt,jfl,jfh,jtl,jth, mu
      double precision ys, s, t

      m= int(smod(1)+0.1d0)
      p= int(smod(2)+0.1d0)
      q= int(smod(3)+0.1d0)
      n= int(smod(4)+0.1d0)
      mu=int(smod(5)+0.1d0)
      ys=smod(q+6)
      ja=q+6
      jb=ja+p*m
      jf=jb+m*q
      jt=jf+n*m
      call fsort(mu,n,smod(jf+1),smod(jt+1),sc)
      do 100 inp = 1, np
        ja=q+6
        jb=ja+p*m
        jf=jb+m*q
        jt=jf+n*m
        do i=1,q
          y(inp,i)=0d0
        end do
        do 91 l=1,mu
          s=0d0
          do j=1,p
            s=s+smod(ja+j)*x(inp,j)
          end do
          if(s .gt. smod(jt+1)) goto 12221
          place=1
          go to 12230
12221     continue
          if(s .lt. smod(jt+n)) goto 12251
          place=n
          go to 12230

12251     continue
          low=0
          high=n+1
C        WHILE
12261     if(low+1.ge.high) then ! 12262
             jfl=jf+low
             jfh=jf+high
             jtl=jt+low
             jth=jt+high
             t=smod(jfl)+(smod(jfh)-smod(jfl))*(s-smod(jtl))  /
     &            (smod(jth)-smod(jtl))
             go to 12300
          end if
          place=(low+high)/2
          t=smod(jt+place)
          if(s.eq.t) goto 12230
          if(s .lt. t) then
             high=place
          else
             low=place
          endif
          goto 12261
C        END
12230     continue
c----     --------
          t=smod(jf+place)
12300     continue
          do i=1,q
             y(inp,i)=y(inp,i)+smod(jb+i)*t
          end do
          ja=ja+p
          jb=jb+q
          jf=jf+n
          jt=jt+n
 91     continue
        do i=1,q
           y(inp,i)=ys*y(inp,i)+smod(i+5)
        end do
 100  continue
      return
      end

c Called from R's supsmu()
      subroutine setsmu (tr)
      integer tr

      double precision  df, gcvpen
      integer                       ismethod
      logical                                 trace
      common /spsmooth/ df, gcvpen, ismethod, trace

      ismethod = 0
      trace = tr .ne. 0
      return
      end

      subroutine supsmu (n,x,y,w,iper,span,alpha,smo,sc,edf)
c
c------------------------------------------------------------------
c
c super smoother (Friedman, 1984).
c
c version 10/10/84
c
c coded  and copywrite (c) 1984 by:
c
c                        Jerome H. Friedman
c                     department of statistics
c                               and
c                stanford linear accelerator center
c                        stanford university
c
c all rights reserved.
c
c
c input:
c    n : number of observations (x,y - pairs).
c    x(n) : ordered abscissa values.
c    y(n) : corresponding ordinate (response) values.
c    w(n) : weight for each (x,y) observation.
c    iper : periodic variable flag.
c       iper=1 => x is ordered interval variable.
c       iper=2 => x is a periodic variable with values
c                 in the range (0.0,1.0) and period 1.0.
c    span : smoother span (fraction of observations in window).
c           span=0.0 <=> "cv" : automatic (variable) span selection.
c    alpha : controls high frequency (small span) penality
c            used with automatic span selection (bass tone control).
c            (alpha.le.0.0 or alpha.gt.10.0 => no effect.)
c output:
c   smo(n) : smoothed ordinate (response) values.
c scratch:
c   sc(n,7) : internal working storage.
c
c note:
c    for small samples (n < 40) or if there are substantial serial
c    correlations between observations close in x - value, then
c    a prespecified fixed span smoother (span > 0) should be
c    used. reasonable span values are 0.2 to 0.4.
c
c------------------------------------------------------------------

c Args
      integer n, iper
      double precision x(n),y(n),w(n), smo(n),sc(n,7)
      double precision span, alpha, edf
c Var
      double precision sy,sw, a,h(n),f, scale,vsmlsq,resmin
      integer i,j, jper

      double precision  spans(3),    big,sml,eps
      common /spans/ spans  /consts/ big,sml,eps

      double precision  df, gcvpen
      integer                       ismethod
      logical                                 trace
      common /spsmooth/ df, gcvpen, ismethod, trace
c     Called from R's supsmu(),  ismethod = 0, always (but not when called from ppr)

      if (x(n).gt.x(1)) go to 30
c     x(n) <= x(1) :  boundary case:  smo[.] :=  weighted mean( y )
      sy=0d0
      sw=sy
      do j=1,n
         sy=sy+w(j)*y(j)
         sw=sw+w(j)
      end do
      a=0d0
      if (sw.gt.0d0) a=sy/sw
      do j=1,n
         smo(j)=a
      end do
      return

C     Normal Case
 30   continue
      if (ismethod .ne. 0) then ! possible only when called from ppr()
         call spline(n, x, y, w, smo, edf, sc)
      else
         i=n/4
         j=3*i
         scale=x(j)-x(i) ! = IQR(x)
 40      if (scale.gt.0d0) go to 50
         if (j.lt.n) j=j+1
         if (i.gt.1) i=i-1
         scale=x(j)-x(i)
         go to 40
 50      vsmlsq=(eps*scale)**2
         jper=iper
         if (iper.eq.2.and.(x(1).lt.0d0.or.x(n).gt.1d0)) jper=1
         if (jper.lt.1.or.jper.gt.2) jper=1
         if (span .gt. 0d0) then
            call smooth (n,x,y,w,span,jper,vsmlsq,smo,sc)
            return
         end if
C     else  "cv" (crossvalidation) from  three spans[]
         do 70 i=1,3
            call smooth (n,x,y,w,spans(i),jper,vsmlsq,
     &           sc(1,2*i-1),sc(1,7))
            call smooth (n,x,sc(1,7),w,spans(2),-jper,vsmlsq,
     &           sc(1,2*i),h)
 70      continue
         do 90 j=1,n
            resmin=big
            do 80 i=1,3
               if (sc(j,2*i).ge.resmin) go to 80
               resmin=sc(j,2*i)
               sc(j,7)=spans(i)
 80         continue
            if (alpha.gt.0d0 .and. alpha.le.10d0 .and.
     &           resmin.lt.sc(j,6) .and. resmin.gt.0d0)
     &           sc(j,7)= sc(j,7)+(spans(3)-sc(j,7)) *
     &                          max(sml,resmin/sc(j,6))**(10d0-alpha)
 90      continue

         call smooth (n,x,sc(1,7),w,spans(2),-jper,vsmlsq,sc(1,2),h)
         do 110 j=1,n
            if (sc(j,2).le.spans(1)) sc(j,2)=spans(1)
            if (sc(j,2).ge.spans(3)) sc(j,2)=spans(3)
            f=sc(j,2)-spans(2)
            if (f.ge.0d0) go to 100
            f=-f/(spans(2)-spans(1))
            sc(j,4)=(1d0-f)*sc(j,3)+f*sc(j,1)
            go to 110
 100        f=f/(spans(3)-spans(2))
            sc(j,4)=(1d0-f)*sc(j,3)+f*sc(j,5)
 110     continue
         call smooth (n,x,sc(1,4),w,spans(1),-jper,vsmlsq,smo,h)
         edf = 0
      endif
      return
      end

      subroutine smooth (n,x,y,w,span,iper,vsmlsq,smo,acvr)
c Args
      integer n, iper
      double precision x(n),y(n),w(n), span,vsmlsq, smo(n),acvr(n)
c Var
      integer i,j, in,out, jper,ibw,it, j0
      double precision xm,ym,var,cvar, fbw,fbo,xti,xto,tmp, a,h,sy,wt

c will use 'trace':
      double precision  df, gcvpen
      integer                       ismethod
      logical                                 trace
      common /spsmooth/ df, gcvpen, ismethod, trace

      xm=0d0
      ym=xm
      var=ym
      cvar=var
      fbw=cvar
      jper=iabs(iper)
      ibw=int(0.5d0*span*n+0.5d0)
      if (ibw.lt.2) ibw=2
      it=2*ibw+1
      if (it .gt. n) it = n
      do i=1,it
         j=i
         if (jper.eq.2) j=i-ibw-1
         if (j.ge.1) then
            xti=x(j)
         else ! if (j.lt.1) then
            j=n+j
            xti=x(j)-1d0
         end if
         wt=w(j)
         fbo=fbw
         fbw=fbw+wt
         if (fbw.gt.0d0) xm=(fbo*xm+wt*xti)/fbw
         if (fbw.gt.0d0) ym=(fbo*ym+wt*y(j))/fbw
         tmp=0d0
         if (fbo.gt.0d0) tmp=fbw*wt*(xti-xm)/fbo
         var =var +tmp*(xti-xm)
         cvar=cvar+tmp*(y(j)-ym)
      end do

      do 80 j=1,n
         out=j-ibw-1
         in=j+ibw
         if ((jper.ne.2) .and. (out.lt.1.or.in.gt.n)) go to 60
         if (out .lt. 1) then
            out=n+out
            xto=x(out)-1d0
            xti=x(in)
         else if (in .gt. n) then
            in=in-n
            xti=x(in)+1d0
            xto=x(out)
         else
            xto=x(out)
            xti=x(in)
         end if
         wt=w(out)
         fbo=fbw
         fbw=fbw-wt
         tmp=0d0
         if (fbw.gt.0d0) tmp=fbo*wt*(xto-xm)/fbw
         var = var-tmp*(xto-xm)
         cvar=cvar-tmp*(y(out)-ym)
         if (fbw.gt.0d0) xm=(fbo*xm-wt*xto)/fbw
         if (fbw.gt.0d0) ym=(fbo*ym-wt*y(out))/fbw
         wt=w(in)
         fbo=fbw
         fbw=fbw+wt
         if (fbw.gt.0d0) xm=(fbo*xm+wt*xti)/fbw
         if (fbw.gt.0d0) ym=(fbo*ym+wt*y(in))/fbw
         tmp=0d0
         if (fbo.gt.0d0) tmp=fbw*wt*(xti-xm)/fbo
         var = var+tmp*(xti-xm)
         cvar=cvar+tmp*(y(in)-ym)
 60      a=0d0
         if (var.gt.vsmlsq) a=cvar/var
         smo(j)=a*(x(j)-xm)+ym
         if (iper.gt.0) then
            h=0d0
            if (fbw.gt.0d0) h=1d0/fbw
            if (var.gt.vsmlsq) h=h+(x(j)-xm)**2/var
            a=1d0-w(j)*h
            if (a.gt.0d0) then
               acvr(j)=abs(y(j)-smo(j))/a
            else if (j.gt.1) then
               acvr(j)=acvr(j-1)
            else
               acvr(j)=0d0
            end if
         end if
 80   continue

      if(trace) call smoothprt(span, iper, var, cvar) ! -> ./ksmooth.c

c-- Recompute fitted values smo(j) as weighted mean for non-unique x(.) values:
      j=1
 90   j0=j
      sy=smo(j)*w(j)
      fbw=w(j)
      if (j.ge.n) go to 110
 100  if (x(j+1).le.x(j)) then
         j=j+1
         sy=sy+w(j)*smo(j)
         fbw=fbw+w(j)
         if (j.lt.n) go to 100
      end if
 110  if (j.gt.j0) then
         a=0d0
         if (fbw.gt.0d0) a=sy/fbw
         do i=j0,j
            smo(i)=a
         end do
      end if
      j=j+1
      if (j.le.n) go to 90
      return
      end


      block data bksupsmu
      double precision spans(3),    big,sml,eps
      common /spans/ spans /consts/ big,sml,eps

      data spans,               big,  sml,  eps
     &  /0.05_8, 0.2_8, 0.5, 1.0e20,1.0e-7,1.0e-3/
      end
c---------------------------------------------------------------
c
c this sets the compile time (default) values for various
c internal parameters :
c
c spans : span values for the three running linear smoothers.
c spans(1) : tweeter span.
c spans(2) : midrange span.
c spans(3) : woofer span.
c       (these span values should be changed only with care.)
c big : a large representable floating point number.
c sml : a small number. should be set so that (sml)**(10.0) does
c       not cause floating point underflow.
c eps : used to numerically stabilize slope calculations for
c       running linear fits.
c
c these parameter values can be changed by declaring the
c relevant labeled common in the main program and resetting
c them with executable statements.
c

c Only for  ppr(*, ismethod != 0):  Compute "smoothing" spline
c  (rather, a penalized regression spline with at most 15 (inner) knots):
c-----------------------------------------------------------------
c
      subroutine spline (n, x, y, w, smo, edf, sc)
c
c------------------------------------------------------------------
c
c input:
c    n : number of observations.
c    x(n) : ordered abscissa values.
c    y(n) : corresponding ordinate (response) values.
c    w(n) : weight for each (x,y) observation.
c work space:
c    sc(n,7) : used for dx(n), dy(n), dw(n), dsmo(n), lev(n)
c output:
c   smo(n) : smoothed ordinate (response) values.
c   edf : equivalent degrees of freedom
c
c------------------------------------------------------------------
c Args
      integer n
      double precision x(n), y(n), w(n), smo(n), edf, sc(n,7)

      call splineAA(n, x, y, w, smo, edf,
     +     sc(n,1), ! dx
     +     sc(n,2), ! dy
     +     sc(n,3), ! dw
     +     sc(n,4), ! dsmo
     +     sc(n,5)) ! lev

      return
      end


      subroutine splineAA(n, x, y, w, smo, edf, dx, dy, dw, dsmo, lev)
c
c  Workhorse of spline() above
c------------------------------------------------------------------
c
c Additional input variables (no extra output, work):
c     dx :
c     dy :
c     dw :
c     dsmo:
c     lev : "leverages", i.e., diagonal entries S_{i,i} of the smoother matrix

c
c------------------------------------------------------------------
c Args
      integer n
      double precision x(n), y(n), w(n), smo(n), edf,
     +     dx(n), dy(n), dw(n), dsmo(n), lev(n)
c Var
      double precision knot(29), coef(25), work((17+25)*25)
      double precision param(5), df1, lambda, crit, p, s
      integer iparms(4), i, nk, ip, ier

      double precision  df, gcvpen
      integer                       ismethod
      logical                                 trace
      common /spsmooth/ df, gcvpen, ismethod, trace

      do i = 1,n
        dx(i) = (x(i)-x(1))/(x(n)-x(1))
        dy(i) = y(i)
        dw(i) = w(i)
      end do
      nk = min(n,15)
      knot(1) = dx(1)
      knot(2) = dx(1)
      knot(3) = dx(1)
      knot(4) = dx(1)
      knot(nk+1) = dx(n)
      knot(nk+2) = dx(n)
      knot(nk+3) = dx(n)
      knot(nk+4) = dx(n)
      do i = 5, nk
         p = (n-1)*real(i-4)/real(nk-3)
         ip = int(p)
         p = p-ip
         knot(i) = (1-p)*dx(ip+1) + p*dx(ip+2)
      end do
c      call dblepr('knots', 5, knot, nk+4)
C     iparms(1:2) := (icrit, ispar)  for ./sbart.c
      if (ismethod .eq. 1) then
         iparms(1) = 3
         df1 = df
      else
         iparms(1) = 1
         df1 = 0d0
      endif
c
      iparms(2) = 0   ! ispar := 0 <==> estimate `spar'
      iparms(3) = 500 ! maxit = 500
      iparms(4) = 0   ! spar (!= lambda)
c
      param(1) = 0d0   ! = lspar : min{spar}
      param(2) = 1.5d0 ! = uspar : max{spar}
c     tol for 'spar' estimation:
      param(3) = 1d-2
c     'eps' (~= 2^-12 = sqrt(2^-24) ?= sqrt(machine eps)) in ./sbart.c :
      param(4) = .000244_8

      ier = 1
      call rbart(gcvpen,df1,dx,dy,dw,0.0d0,n,knot,nk,coef,dsmo,lev,
     &     crit,iparms,lambda,param, work,4,1,ier)
      if(ier .gt. 0) call intpr('spline(.) TROUBLE:', 18, ier, 1)
      do i = 1,n
         smo(i) = dsmo(i)
      end do
c      call dblepr('smoothed',8, dsmo, n)
      s = 0
      do i = 1, n
         s = s + lev(i)
      end do
      edf = s
      if(trace) call splineprt(df,gcvpen,ismethod, lambda, edf)
      return
      end


***********************************************************************

C=== This was 'sort()' in  gamfit's  mysort.f  [or sortdi() in sortdi.f ] :
C
C===  FIXME:  Translate to C and add to ../../../main/sort.c <<<<<
C
C     a[] is double precision because the caller reuses a double (sometimes v[] itself!)
      subroutine sort (v,a, ii,jj)
c
c     Puts into a the permutation vector which sorts v into
c     increasing order.  Only elements from ii to jj are considered.
c     Arrays iu(k) and il(k) permit sorting up to 2**(k+1)-1 elements
c
c     This is a modification of CACM algorithm #347 by R. C. Singleton,
c     which is a modified Hoare quicksort.
c
      integer ii,jj
      double precision v(*), a(jj)
c
      integer iu(20),il(20)
      integer t,tt, m,i,j,ij,k,l
      double precision vt, vtt

      m=1
      i=ii
      j=jj
 10   if (i.ge.j) go to 80
 20   k=i
      ij=(j+i)/2
      t=int(a(ij))
      vt=v(ij)
      if (v(i).le.vt) go to 30
      a(ij)=a(i)
      a(i)=t
      t=int(a(ij))
      v(ij)=v(i)
      v(i)=vt
      vt=v(ij)
 30   l=j
      if (v(j).ge.vt) go to 50
      a(ij)=a(j)
      a(j)=t
      t=int(a(ij))
      v(ij)=v(j)
      v(j)=vt
      vt=v(ij)
      if (v(i).le.vt) go to 50
      a(ij)=a(i)
      a(i)=t
      t=int(a(ij))
      v(ij)=v(i)
      v(i)=vt
      vt=v(ij)
      go to 50
 40   a(l)=a(k)
      a(k)=tt
      v(l)=v(k)
      v(k)=vtt
 50   l=l-1
      if (v(l).gt.vt) go to 50
      tt=int(a(l))
      vtt=v(l)
 60   k=k+1
      if (v(k).lt.vt) go to 60
      if (k.le.l) go to 40
      if (l-i.le.j-k) go to 70
      il(m)=i
      iu(m)=l
      i=k
      m=m+1
      go to 90
 70   il(m)=k
      iu(m)=j
      j=l
      m=m+1
      go to 90
 80   m=m-1
      if (m.eq.0) return
      i=il(m)
      j=iu(m)
 90   if (j-i.gt.10) go to 20
      if (i.eq.ii) go to 10
      i=i-1
 100  i=i+1
      if (i.eq.j) go to 80
      t=int(a(i+1))
      vt=v(i+1)
      if (v(i).le.vt) go to 100
      k=i
 110  a(k+1)=a(k)
      v(k+1)=v(k)
      k=k-1
      if (vt.lt.v(k)) go to 110
      a(k+1)=t
      v(k+1)=vt
      go to 100
      end
