      Subroutine GenericRegres(npoints,ny,y,nx,x,weity0,
     &weitx0,ndim0,beta_in_out,betamin0,betamax0,xmin0,xmax0,
     &iderivative,iregrestype0,shorty0,shortx0,fatbeta)
      implicit none
!iregrestype0=0, ordinary regression
!iregrestype0=1, orthogonal distance regression. Direct search methods
!  determine the shortest distance within the iteration
!iregrestype0=2, orthogonal distance regression. Direct search methods
!  expand the parameter vector to include x positions.
!iregrestype0=-1, implicit regression
!iderivative=0, no derivative provided
!iderivative=1, derivative provided
      include 'forgenericregres.h'
      integer npoints,ny,nx,iderivative,ndim0,iregrestype0
      double precision y(npoints,ny),x(npoints,nx),weity0(npoints,ny),
     &weitx0(npoints,nx),xmin0(npoints,nx),xmax0(npoints,nx),
     &beta_in_out(ndim0),betamin0(ndim0),betamax0(ndim0),
     &shorty0(npoints,ny),shortx0(npoints,nx),fatbeta
!
      integer i,j,INFO,ndim,k,n,i2,icompete,isitnaninf,nave
      double precision xtol,beta(ndim0+nx*npoints),
     &betacp(ndim0+nx*npoints),fatbetacp,beta0(ndim0+nx*npoints),
     &fatbeta0,ftol,gacontrol(12),ran2,ftol_relax,term1,term2,discount,
     &history(2000,ndim0+3),upper,lower,f1dim_generic,generic_pikaia
      parameter(xtol=1.0d-7,ftol=1.0d-7)
      external funkmin_generic,FCN_generic,f1dim_generic,generic_pikaia
!-----------------------------------------------------
      ndim=ndim0
      nxvars=nx
      nyvars=ny
      if((nx*npoints+ndim0).gt.1000)iregrestype0=0
      iregrestype=iregrestype0
      iknowder=iderivative
      nobs=npoints
      do i=1,npoints
        do j=1,nxvars
          xvars(i,j)=x(i,j)
          xmin(i,j)=xmin0(i,j)
          xmax(i,j)=xmax0(i,j)
          weitx0(i,j)=1.0d0
          weitx(i,j)=weitx0(i,j)
        enddo
        do j=1,nyvars
          yobs(i,j)=y(i,j)
          weity(i,j)=weity0(i,j)
        enddo
      enddo
      do i=1,ndim
        betamin(i)=betamin0(i)
        betamax(i)=betamax0(i)
        beta(i)=beta_in_out(i)
      enddo
      if(iregrestype.eq.2)iregrestype=1
c     gacontrol( 1) - number of individuals in a population (default
c                      is 100)
c     gacontrol( 2) - number of generations over which solution is
c                      to evolve (default is 500)
c     gacontrol( 3) - number of significant digits (i.e., number of
c                      genes) retained in chromosomal encoding (default
c                      is 6)  (Note: This number is limited by the
c                      machine floating point precision.  Most 32-bit
c                      floating point representations have only 6 full
c                      digits of precision.  To achieve greater preci-
c                      sion this routine could be converted to double
c                      precision, but note that this would also require
c                      a double precision random number generator, which
c                      likely would not have more than 9 digits of
c                      precision if it used 4-byte integers internally.)
c     gacontrol( 4) - crossover probability; must be  <= 1.0 (default
c                      is 0.85). If crossover takes place, either one
c                      or two splicing points are used, with equal
c                      probabilities
c     gacontrol( 5) - mutation mode; 1/2/3/4/5 (default is 2)
c                      1=one-point mutation, fixed rate
c                      2=one-point, adjustable rate based on fitness 
c                      3=one-point, adjustable rate based on distance
c                      4=one-point+creep, fixed rate
c                      5=one-point+creep, adjustable rate based on fitness
c                      6=one-point+creep, adjustable rate based on distance
c     gacontrol( 6) - initial mutation rate; should be small (default
c                      is 0.005) (Note: the mutation rate is the proba-
c                      bility that any one gene locus will mutate in
c                      any one generation.)
c     gacontrol( 7) - minimum mutation rate; must be >= 0.0 (default
c                      is 0.0005)
c     gacontrol( 8) - maximum mutation rate; must be <= 1.0 (default
c                      is 0.25)
c     gacontrol( 9) - relative fitness differential; range from 0
c                      (none) to 1 (maximum).  (default is 1.)
c     gacontrol(10) - reproduction plan; 1/2/3=Full generational
c                      replacement/Steady-state-replace-random/Steady-
c                      state-replace-worst (default is 3)
c     gacontrol(11) - elitism flag; 0/1=off/on (default is 0)
c                      (Applies only to reproduction plans 1 and 2)
c     gacontrol(12) - printed output 0/1/2=None/Minimal/Verbose
c                      (default is 0)
      idobounded=1
10    call funkmin_generic(ndim,beta,fatbeta)
      do i=1,ndim
        beta0(i)=beta(i)
        history(1,i)=beta(i)
      enddo
      fatbeta0=fatbeta
      history(1,ndim+1)=fatbeta
!entrance counter
      history(1,ndim+2)=1.0d0
!failure counter
      history(1,ndim+3)=0.0d0
!Is it a competition among different initial guesses?
      icompete=0
!j the total number of calls to nongradopt; k is the number of returns to the current best and reset
!to zero if a better minumum is found; n is the number of scouting points over the landscape of the cost function.
!The first initial guess provided by the user is always part of the set of scouting points.the rest consist of outcomes
!from calls to nongradopt if they are significantly different from the current best.
      j=0
      k=0
      n=1
      nave=1
      ftol_relax=ftol*1000.0d0
      discount=2.0d0
!relax the convergence criterion for scouting
30    fatbetacp=fatbeta
      do i=1,ndim
        betacp(i)=beta(i)
      enddo
      INFO=iregrestype
      call odr_leastsquare(ndim,FCN_generic,beta,nobs,
     &xvars(1:nobs,1:nxvars),nxvars,yobs(1:nobs,1:nyvars),
     &nyvars,weitx(1:nobs,1:nxvars),weity(1:nobs,1:nyvars),
     &iderivative,shortx(1:nobs,1:nxvars),
     &shorty(1:nobs,1:nyvars),fatbeta,INFO)
      call funkmin_generic(ndim,beta,fatbeta)
      if(isitnaninf(fatbeta).eq.1.or.fatbeta.gt.fatbetacp)then
        fatbeta=fatbetacp
        do i=1,ndim
          beta(i)=betacp(i)
        enddo
      else
        fatbetacp=fatbeta
        do i=1,ndim
          betacp(i)=beta(i)
        enddo
      endif
      call nongradopt(ndim,funkmin_generic,f1dim_generic,
     &beta,betamin,betamax,ftol_relax,fatbeta)
      if(isitnaninf(fatbeta).eq.1.or.fatbeta.gt.fatbetacp)then
        fatbeta=fatbetacp
        do i=1,ndim
          beta(i)=betacp(i)
        enddo
      endif
      if(fatbeta.gt.1.0d0)then
        term1=fatbeta*ftol_relax
      else
        term1=ftol_relax*10.0d0
      endif
      if(fatbeta.gt.fatbeta0)then
!failure
        if((fatbeta-fatbeta0).gt.term1)then
          if(icompete.eq.1)history(1,ndim+3)=history(1,ndim+3)+1.5d0
!even though fatbeta is much worse than fatbeta0, it is an output of optimization after all so
!include it in the set if it has not already been included in the set.
          i=1
          i2=1
40        if(dabs(history(i2,i)-beta(i)).gt.ftol_relax)then
            if(dabs(history(i2,ndim+1)-fatbeta).lt.term1)then
              history(i2,ndim+3)=history(i2,ndim+3)+1.0d0
              goto 60
            endif
            if(i2.ge.n)goto 50
            i2=i2+1
            i=1
            goto 40
          else
            if(i.ge.ndim)goto 60 
            i=i+1
            goto 40
          endif
50        n=n+1
          do i=1,ndim
            history(n,i)=beta(i)
          enddo
          history(n,ndim+1)=fatbeta
          history(n,ndim+2)=0.0d0
          history(n,ndim+3)=0.0d0
!use average only when there is imporvement
          nave=n
        else
!the difference is minimal even though fatbeta is larger than fatbeta0.
!Increment the counter for arriving at the same minimum.
          if(icompete.eq.1)history(1,ndim+3)=history(1,ndim+3)+1.0d0
          k=k+1
        endif
60      do i=1,ndim
          beta(i)=beta0(i)
        enddo
        fatbeta=fatbeta0
      else
!success
        if((fatbeta0-fatbeta).lt.term1)then
!negligible improvement. Increment the counter for arriving at the same minimum.
!no increment for the set of central initial guesses
          if(icompete.eq.1)history(1,ndim+3)=history(1,ndim+3)+0.5d0
          k=k+1
        else
!reset the counter for arriving at a better minimum.
!Increment the set of central initial guesses
          if(dabs(discount-2.0d0).lt.ftol)then
            discount=dmax1(0.001d0,(fatbeta0-fatbeta)/1000.0d0)
          endif
          k=0
          n=n+1
          do i=1,ndim
            history(n,i)=beta(i)
          enddo
          history(n,ndim+1)=fatbeta
          history(n,ndim+2)=0.0d0
          history(n,ndim+3)=0.0d0
        endif
        do i=1,ndim
          beta0(i)=beta(i)
        enddo
        fatbeta0=fatbeta
      endif
      j=j+1
      if(j.lt.20.and.k.lt.2)then
        if(j.lt.10)then
          term1=0.01d0+dmin1(history(1,ndim+3)*0.025d0,0.9d0)
          history(1,ndim+2)=history(1,ndim+2)+1.0d0
          do i=1,ndim
            lower=history(1,i)-term1*(history(1,i)-betamin(i))
            upper=history(1,i)+term1*(betamax(i)-history(1,i))
            beta(i)=lower+ran2()*(upper-lower)
          enddo
          icompete=1
          goto 70
        endif
!try average
        if(n.gt.nave)then
          term1=1.0d0/(history(1,ndim+1)+1.0d-5)
          do i=2,n
            term1=term1+1.0d0/(history(i,ndim+1)+1.0d-5)
          enddo
          do i=1,ndim
            beta(i)=history(1,i)/(term1*(history(1,ndim+1)+1.0d-5))
            do icompete=2,n
              beta(i)=beta(i)+history(icompete,i)/
     &(term1*(history(icompete,ndim+1)+1.0d-5))
            enddo
          enddo
          nave=n
          icompete=0
          goto 70
        endif
!try different initial guesses
        if(ran2().gt.0.2d0)then
!guess around the best
          icompete=1
          term1=history(1,ndim+1)+
     &discount*history(1,ndim+2)*history(1,ndim+3)
          do i=2,n
            term2=history(i,ndim+1)+
     &discount*history(i,ndim+2)*history(i,ndim+3)
            if(term2.le.term1)then
              term1=term2
              do i2=1,ndim+3
                history(n+1,i2)=history(i,i2)
                history(i,i2)=history(1,i2)
                history(1,i2)=history(n+1,i2)
              enddo
            endif
          enddo
          term1=0.01d0+dmin1(history(1,ndim+2)*history(1,ndim+3)*
     &0.015d0,0.9d0)
          history(1,ndim+2)=history(1,ndim+2)+1.0d0
          do i=1,ndim
            lower=history(1,i)-term1*(history(1,i)-betamin(i))
            upper=history(1,i)+term1*(betamax(i)-history(1,i))
            beta(i)=lower+ran2()*(upper-lower)
          enddo
        else
!completely random guess
          do i=1,ndim
            beta(i)=betamin(i)+ran2()*(betamax(i)-betamin(i))
          enddo
          icompete=0
        endif
70      call funkmin_generic(ndim,beta,fatbeta)
        goto 30
      else
        if((ftol_relax-ftol).gt.ftol)then
          if(k.le.1)then
            n=n+1
            do i=1,ndim+3
              history(n,i)=history(1,i)
            enddo
            do i=1,ndim
              history(1,i)=beta(i)
            enddo
            history(1,ndim+1)=fatbeta
            history(1,ndim+2)=0.0d0
            history(1,ndim+3)=0.0d0
            do i=1,n
              do icompete=1,ndim
                betacp(icompete)=history(i,icompete)
              enddo
              fatbetacp=history(i,ndim+1)
              call RepeatCompassSearch(ndim,betacp,fatbetacp,
     &betamin,betamax,funkmin_generic,f1dim_generic,ftol_relax)
              call funkmin_generic(ndim,betacp,fatbetacp)
              if(isitnaninf(fatbetacp).eq.0.and.fatbetacp.lt.
     &fatbeta)then
                do icompete=1,ndim
                  beta(icompete)=betacp(icompete)
                enddo
                fatbeta=fatbetacp
              endif
            enddo
            do i=1,ndim
              beta0(i)=beta(i)
            enddo
            fatbeta0=fatbeta
            icompete=1
            j=0
          else
            icompete=0
          endif
          ftol_relax=ftol
          goto 30
        endif
      endif

      goto 110

      call RepeatCompassSearch(ndim,beta,fatbeta,
     &betamin,betamax,funkmin_generic,f1dim_generic,xtol)
      call funkmin_generic(ndim,beta,fatbeta)
      if(isitnaninf(fatbeta).eq.1.or.fatbeta.ge.fatbeta0)then
!if RepeatCompassSearch cannot improve, we end the search
        do i=1,ndim
          beta(i)=beta0(i)
        enddo
        fatbeta=fatbeta0
        goto 110
      endif
      do i=1,12
        gacontrol(i)=-1.0d0
      enddo
      gacontrol(1)=250.0d0
      gacontrol(2)=5000.0d0
      gacontrol(3)=8.0d0
      do i=1,ndim
        beta0(i)=(beta(i)-betamin(i))/(betamax(i)-betamin(i))
      enddo
      fatbeta0=fatbeta
      call pikaia(generic_pikaia,ndim,gacontrol,beta0,fatbeta0,j)
      fatbeta0=1.0d+100
      if(j.eq.0)then
        do i=1,ndim
          beta0(i)=betamin(i)+beta0(i)*(betamax(i)-betamin(i))
        enddo
        call funkmin_generic(ndim,beta0,fatbeta0)
      endif
80    if(isitnaninf(fatbeta0).eq.1.or.fatbeta0.gt.fatbeta)then
        fatbeta0=fatbeta
        do i=1,ndim
          beta0(i)=beta(i)
        enddo
      else
        do i=1,ndim
          beta(i)=beta0(i)
        enddo
        fatbeta=fatbeta0
      endif
!
      INFO=iregrestype
      call odr_leastsquare(ndim,FCN_generic,beta,nobs,
     &xvars(1:nobs,1:nxvars),nxvars,yobs(1:nobs,1:nyvars),
     &nyvars,weitx(1:nobs,1:nxvars),weity(1:nobs,1:nyvars),
     &iderivative,shortx(1:nobs,1:nxvars),
     &shorty(1:nobs,1:nyvars),fatbeta,INFO)
      call funkmin_generic(ndim,beta,fatbeta)
      if(isitnaninf(fatbeta).eq.1.or.fatbeta.gt.fatbeta0)then
        do i=1,ndim
          beta(i)=beta0(i)
        enddo
        fatbeta=fatbeta0
      endif
      iregrestype=iregrestype0
      if(iregrestype.eq.2)then
        do i=1,npoints
          do j=1,nx
            ndim=ndim+1
            beta(ndim)=shortx(i,j)
            betamin(ndim)=xmin0(i,j)
            betamax(ndim)=xmax0(i,j)
            if(beta(ndim).lt.betamin(ndim).or.
     &beta(ndim).gt.betamax(ndim))then
              beta(ndim)=x(i,j)
            endif
          enddo
        enddo
        call funkmin_generic(ndim,beta,fatbeta)
      endif
      j=0
100   j=j+1
      fatbeta0=fatbeta
      do i=1,ndim
        beta0(i)=beta(i)
      enddo
      call nongradopt(ndim,funkmin_generic,
     &f1dim_generic,beta,betamin,betamax,ftol,fatbeta)
      call funkmin_generic(ndim,beta,fatbeta)
      if(isitnaninf(fatbeta).eq.1.or.fatbeta.ge.fatbeta0)then
        fatbeta=fatbeta0
        do i=1,ndim
          beta(i)=beta0(i)
        enddo
        goto 110
      endif
      fatbetacp=fatbeta
      do i=1,ndim
        betacp(i)=beta(i)
      enddo
      call RepeatCompassSearch(ndim,betacp,fatbetacp,
     &betamin,betamax,funkmin_generic,f1dim_generic,xtol)
      call funkmin_generic(ndim,betacp,fatbetacp)
      if(isitnaninf(fatbetacp).eq.1.or.fatbetacp.ge.fatbeta)then
        goto 110
      else
        fatbeta=fatbetacp
        do i=1,ndim
          beta(i)=betacp(i)
        enddo
      endif
      if(j.ge.2.or.fatbeta.eq.fatbeta0)goto 110
      if(dabs(fatbeta0-fatbeta).gt.ftol)then
        do i=1,ndim
          betacp(i)=beta(i)-beta0(i)
          beta0(i)=beta(i)
        enddo
        fatbeta0=fatbeta
        call linmin(beta,betamin,betamax,betacp,ndim,
     &f1dim_generic,fatbeta)
        call funkmin_generic(ndim,beta,fatbeta)
        if(isitnaninf(fatbeta).eq.0.and.fatbeta.lt.fatbeta0)goto 100
        fatbeta=fatbeta0
        do i=1,ndim
          beta(i)=beta0(i)
        enddo
      endif
110   call funkmin_generic(ndim,beta,fatbeta)
      do i=1,ndim0
        beta_in_out(i)=beta(i)
      enddo
      do i=1,npoints
        do j=1,nyvars
          shorty0(i,j)=shorty(i,j)
        enddo
        do j=1,nxvars
          shortx0(i,j)=shortx(i,j)
        enddo
      enddo
      return
      end subroutine GenericRegres
!$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$
