Files
piscal/dataassim/math/optimization/cpnongradopt.f
T
2022-09-12 16:40:28 +00:00

248 lines
6.8 KiB
FortranFixed

subroutine cpnongradopt(ndim,funkmin,f1dim,beta,
& bmin,bmax,ftol,fatbeta)
implicit none
!
! This subroutine minimizes function funkmin to estimate ndim parameters
! using non-gradient based methods
!
integer ndim
double precision beta(1:ndim),bmin(1:ndim),
&bmax(1:ndim),ftol,fatbeta,f1dim
!
! ------------------ Inputs -----------------------------
! ndim: the total number of parameters to be estimated
! bmax: the maximum possible value of beta, used to determine the distance scaling factor
! bmin: the minimum possible value of beta, used to determine the distance scaling factor
! beta: initial guess, overwritten upon return
! ftol: tolerance for convergence
! fatbeta: the cost function valuate at beta, overwritten upon return
! funkmin is the name of the subroutine that computes the cost function
! f1dim: the one dimensional cost function
! ------------------ Outputs ----------------------------
! beta: The best parameters obtained
! fatbeta: the cost function value at beta
integer n,nn,mpamoeba,npamoeba,iredo,maxredo,ITMAX,
& icycle
parameter(maxredo=20,ITMAX=20000)
double precision fbest,xbest(1:ndim),
& xinidir(1:ndim,1:ndim),xbest0(1:ndim),
& pamoeba(1:ndim+1,1:ndim),famoeba(1:ndim+1)
external funkmin,f1dim
! End of declaration of variables
!---------------------------------------------------------------
icycle=0
1 iredo=0
3 do n=1,ndim
xbest(n)=beta(n)
do nn=1,ndim
xinidir(n,nn)=0.0d0
enddo
xinidir(n,n)=1.0d0
enddo
fbest=fatbeta
call cppowell(beta,xinidir(1:ndim,1:ndim),ndim,
&ndim,ftol,fatbeta,bmin,bmax,funkmin,f1dim,ITMAX)
if(fatbeta.gt.fbest)then
do n=1,ndim
beta(n)=xbest(n)
enddo
fatbeta=fbest
goto 10
endif
if((fbest-fatbeta).gt.ftol)then
if(iredo.gt.maxredo)goto 10
iredo=iredo+1
goto 3
endif
10 iredo=0
20 do n=1,ndim
xbest(n)=beta(n)
enddo
fbest=fatbeta
do nn=1,ndim
pamoeba(1,nn)=beta(nn)
enddo
famoeba(1)=fatbeta
do n=2,ndim+1
do nn=1,ndim
pamoeba(n,nn)=beta(nn)
enddo
if((bmax(n-1)-pamoeba(n,n-1))
& .gt.(pamoeba(n,n-1)-bmin(n-1)))then
pamoeba(n,n-1)=pamoeba(n,n-1)+
& (bmax(n-1)-pamoeba(n,n-1))*0.1d0
else
pamoeba(n,n-1)=pamoeba(n,n-1)-
& (pamoeba(n,n-1)-bmin(n-1))*0.1d0
endif
do nn=1,ndim
xbest0(nn)=pamoeba(n,nn)
enddo
call funkmin(ndim,xbest0,famoeba(n))
enddo
mpamoeba=ndim+1
npamoeba=ndim
call cpguamoeba(pamoeba(1:ndim+1,1:ndim),
& famoeba(1:ndim+1),mpamoeba,npamoeba,ndim,
& ftol,funkmin,ITMAX/20)
nn=1
do n=2,ndim+1
if(famoeba(n).lt.famoeba(nn))nn=n
enddo
fatbeta=famoeba(nn)
do n=1,ndim
beta(n)=pamoeba(nn,n)
if(beta(n).lt.bmin(n).or.beta(n).gt.bmax(n))then
do nn=1,ndim
beta(nn)=xbest(nn)
enddo
fatbeta=fbest
return
endif
enddo
if((fbest-fatbeta).gt.ftol)then
if(iredo.gt.maxredo)then
if(icycle.lt.maxredo)then
icycle=icycle+1
goto 1
else
return
endif
endif
iredo=iredo+1
goto 20
endif
return
end subroutine cpnongradopt
!&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
SUBROUTINE cpguamoeba(p,y,mp,np,ndim,ftol,funkmin,ITMAX)
implicit none
INTEGER iter,mp,ndim,np,NMAX,ITMAX
double precision ftol,p(mp,np),y(mp),TINY
PARAMETER (TINY=1.0d-20)
external funkmin
CU USES cpguamotry,funkmin
INTEGER i,ihi,ilo,inhi,j,m,n
double precision rtol,sum,swap,ysave,ytry,psum(ndim),
& cpguamotry,degen
iter=0
1 do 12 n=1,ndim
sum=0.0d0
do 11 m=1,ndim+1
sum=sum+p(m,n)
11 continue
psum(n)=sum
12 continue
2 ilo=1
if (y(1).gt.y(2)) then
ihi=1
inhi=2
else
ihi=2
inhi=1
endif
do 13 i=1,ndim+1
if(y(i).le.y(ilo)) ilo=i
if(y(i).gt.y(ihi)) then
inhi=ihi
ihi=i
else if(y(i).gt.y(inhi)) then
if(i.ne.ihi) inhi=i
endif
13 continue
rtol=2.0d0*dabs(y(ihi)-y(ilo))/
& (dabs(y(ihi))+dabs(y(ilo))+TINY)
if (rtol.lt.ftol) then
swap=y(1)
y(1)=y(ilo)
y(ilo)=swap
do 14 n=1,ndim
swap=p(1,n)
p(1,n)=p(ilo,n)
p(ilo,n)=swap
14 continue
return
endif
! check to see if the simplex is degenerate; if so, stop
degen=0.0d0
do i=1,mp
do m=i+1,mp
do n=1,np
if(dabs(p(m,n)-p(i,n)).gt.degen)then
degen=dabs(p(m,n)-p(i,n))
endif
enddo
enddo
enddo
if(degen.lt.ftol*ftol)then
swap=y(1)
y(1)=y(ilo)
y(ilo)=swap
do n=1,ndim
swap=p(1,n)
p(1,n)=p(ilo,n)
p(ilo,n)=swap
enddo
return
endif
if(iter.ge.ITMAX)return
iter=iter+2
ytry=cpguamotry(p,y,psum,mp,np,ndim,funkmin,ihi,-1.0d0)
if (ytry.le.y(ilo))then
ytry=cpguamotry(p,y,psum,mp,np,ndim,funkmin,ihi,2.0d0)
else if (ytry.ge.y(inhi)) then
ysave=y(ihi)
ytry=cpguamotry(p,y,psum,mp,np,ndim,funkmin,ihi,0.5d0)
if (ytry.ge.ysave) then
do 16 i=1,ndim+1
if(i.ne.ilo)then
do 15 j=1,ndim
psum(j)=0.5d0*(p(i,j)+p(ilo,j))
p(i,j)=psum(j)
15 continue
call funkmin(ndim,psum,y(i))
endif
16 continue
iter=iter+ndim
goto 1
endif
else
iter=iter-1
endif
goto 2
END
C (C) Copr. 1986-92 Numerical Recipes Software v%1jw#<0(9p#3.
DOUBLE PRECISION FUNCTION cpguamotry(p,y,psum,
& mp,np,ndim,funkmin,ihi,fac)
implicit none
INTEGER ihi,mp,ndim,np
double precision fac,p(mp,np),psum(np),y(mp)
EXTERNAL funkmin
CU USES funkmin
INTEGER j
double precision fac1,fac2,ytry,ptry(ndim)
fac1=(1.0d0-fac)/dble(ndim)
fac2=fac1-fac
do 11 j=1,ndim
ptry(j)=psum(j)*fac1-p(ihi,j)*fac2
11 continue
call funkmin(ndim,ptry,ytry)
if (ytry.lt.y(ihi)) then
y(ihi)=ytry
do 12 j=1,ndim
psum(j)=psum(j)-p(ihi,j)+ptry(j)
p(ihi,j)=ptry(j)
12 continue
endif
cpguamotry=ytry
return
END
C (C) Copr. 1986-92 Numerical Recipes Software v%1jw#<0(9p#3.
c#######################################################################