|
dimension rea(40)
dimension parvert(maxpar*(maxpar+1)),refl(maxpar),ssd(maxpar+1),
+ expa(maxpar),cont(maxpar),var((maxvar+1)*maxpoints),
+ par(maxpar),x(maxvar+1),center(maxpar)
c
sdconv = .false.
parconv = .true.
npar = maxpar
nvar = maxvar
npoints = 0
c
c initialize the random number generator
c
seed = 72767
xxx = rand(seed)
c
c testing to see if limits are exceeded.
c
if ((npar.gt.maxpar).or.(nvar.gt.(maxvar+1)).or.(npoints.gt.
+ maxpoints)) then
write (*,1001) npar,maxpar,nvar,maxvar,npoints,maxpoints
stop
end if
c
c reading the initial values for the parameters :
c
read(*,1002) line
call freeread(line,rea,nrea)
do i=1,npar
parvert(i)=rea(i)
end do
c
c reading all the values for the variables :
c
ymean=0.
ivar=0
10 read(*,1002,end=20) line
call freeread(line,rea,nrea)
if (nrea.ge.(nvar+1)) then
npoints=npoints+1
do j=1,(nvar+1)
ivar=ivar+1
var(ivar)=rea(j)
if (j.eq.(nvar+1)) ymean=ymean+var(nvar+1)
end do
endif
goto 10
20 continue
ymean=ymean/npoints
c
c generating the initial simplex :
c
c first two vertex at +10% of first par and +/- 10% of all
c others.
c
lastpar=npar
do i1=1,npar
i=i1*npar
do j=1,npar
parvert(i+j)=parvert(j)*(0.8+0.4*rand(0))
enddo
enddo
lastpar=npar*(npar+1)
c
c now that we have the initial vertex ready calculate the SSD for
c each. first loop over all vertex :
c
ncycles=-1
ibest=1
iworst=1
100 ncycles=ncycles+1
do i=1,(npar+1)
ssd(i)=0.
ifirstpar=(i-1)*npar
c
c transfer all parameters from PARVERT to PAR :
c
do j=1,npar
par(j)=parvert(ifirstpar+j)
end do
c
c now call stddev for each vertex
c
call stddev(par,var,ssd(i),x)
end do
c
c finding the best and worst vertex :
c
do i=1,npar+1
if (ssd(i).lt.ssd(ibest)) then
ibest=i
else
if (ssd(i).gt.ssd(iworst)) iworst=i
end if
end do
ifirstbest=(ibest-1)*npar
ifirstworst=(iworst-1)*npar
c
c at this point IWORST contains the index of the worst vertex,
c and IBEST that of the best.
c test for convergence in any cycle other than the first.
c
if (ncycles.ne.0) then
c
c first condition is in SSD of best, RMS.LE.0.01% of YMEAN
c
cond=abs(ymean/10000.)
rms=sqrt(ssd(ibest)/npoints)
if (rms.le.cond) sdconv=.true.
c
c also stop if best and worst vertex are within 0.001% of each other
c
parconv=.true.
do i=1,npar
i1=i*npar
do j=1,npar
if (parconv) then
test=parvert(i1+j)-parvert(j)
test=abs(100000.*test/parvert(j))
if (test.gt.1.0) parconv=.false.
endif
end do
end do
c
if ((parconv).or.(sdconv)) goto 999
endif
c
c reflect the worst vertex and obtain its SSD :
c
ifirstworst=(iworst-1)*npar
ifirstbest=(ibest-1)*npar
do j=1,npar
center(j)=0.
do i=1,(npar+1)
ifirstpar=(i-1)*npar
if (i.ne.iworst) center(j)=center(j)+
+ parvert(ifirstpar+j)
end do
center(j)=parvert(ifirstworst+j)-(center(j)/(npar))
refl(j)=parvert(ifirstworst+j)-(2.0*center(j))
end do
call stddev(refl,var,sdr,x)
c
c compare the reflexed vertex with the best :
c
if (sdr.le.ssd(ibest)) then
c
c test expanded
c
do i=1,npar
expa(i)=refl(i)-center(i)
end do
call stddev(expa,var,sde,x)
if (sde.le.sdr) then
c
c here if expanded better than reflected better than best
c
ssd(iworst)=sde
do i=1,npar
parvert(ifirstworst+i)=expa(i)
end do
goto 100
else
c
c here if expanded not better than reflected but reflected
c better than best
c
ssd(iworst)=sdr
do i=1,npar
parvert(ifirstworst+i)=refl(i)
end do
goto 100
end if
endif
c
c if reflected not better than best :
c
if (sdr.lt.ssd(iworst)) then
c
c if better than worst :
c
ssd(iworst)=sdr
do i=1,npar
parvert(ifirstworst+i)=refl(i)
end do
goto 100
else
c
c if worse than worst try contracted
c
do i=1,npar
cont(i)=parvert(ifirstworst+i)-(center(i)/2.)
end do
call stddev(cont,var,sdc,x)
if (sdc.le.ssd(iworst)) then
c
c here if contracted better than worst
c
ssd(iworst)=sdc
do i=1,npar
parvert(ifirstworst+i)=cont(i)
end do
goto 100
else
c
c no improvement, try shrinking
c
do i=1,(npar+1)
if (i.ne.ibest) then
ifp=(i-1)*npar
do j=1,npar
temp=parvert(ifp+j)
best=parvert(ifirstbest+j)
parvert(ifp+j)=temp-(0.5*(temp-best))
end do
end if
end do
goto 100
end if
end if
999 write (*,1003) ncycles
if (sdconv) write (*,1004)
if (parconv) write (*,1005)
write (*,'(1h )')
do j=1,npar
write (*,1006) j, parvert(ifirstbest+j)
end do
write (*,1007) rms,ssd(ibest)/npoints
c
c to build the format for table :
c
nvp3=nvar+3
if (nvp3.gt.9) write (mf,'(i2)') nvp3
if (nvp3.le.9) write (mf,'(i1)') nvp3
wf='(1x,'//mf//'(d9.3,1x))'
c
c to build the heading :
c
do i=1,132
hdng(i:i)=' '
end do
ihdng=2
do i=1,nvar
hdng(ihdng+3:ihdng+4)='x('
write (mf,'(i2)') i
hdng(ihdng+5:ihdng+6)=mf(1:2)
hdng(ihdng+7:ihdng+7)=')'
ihdng=ihdng+10
end do
hdng(ihdng+5:ihdng+5)='y'
ihdng=ihdng+10
hdng(ihdng+3:ihdng+7)='ycalc'
ihdng=ihdng+10
hdng(ihdng+4:ihdng+6)='dif'
ihdng=ihdng+6
write (*,'(a)') hdng(1:ihdng)
write (*,'(1h )')
c
reply='y'
if ((reply(1:1).eq.'Y').or.(reply(1:1).eq.'y')) then
do i=1,npar
par(i)=parvert(ifirstbest+i)
end do
do i=1,npoints
ifirstpoint=(i-1)*(nvar+1)
do j=1,(nvar+1)
x(j)=var(ifirstpoint+j)
end do
yc=ycalc(par,x)
dy=x(nvar+1)-yc
write (*,fmt=wf) (x(j),j=1,(nvar+1)),yc,dy
end do
end if
stop
1001 format (/,5x,'npar=',i3,' maxpar=',i3,'; nvar=',i3,' maxvar=',
+ i3,'; npoints=',i3,' maxpoints=',i3)
1002 format(a256)
1003 format (/,5x,'Convergence reached after',I4,' cycles',/)
1004 format (10x,'RMS less than 0.1% of mean Y')
1005 format (10x,'All the Vertex are within 0.01%')
1006 format (5x,'a(',i2,') = ',D13.5)
1007 format (/,10x,'RMS = ',D13.5,' Std Dev = ',D13.5,///)
end
c---------------------------------------------------------------------
subroutine stddev(par,var,sd,x)
c---------------------------------------------------------------------
c
c It will loop over all points and calculate the summation of the
c standard deviation for a given set of parameters.
c
implicit double precision(a-h,o-z)
common /nums/npar,nvar,npoints
dimension par(2),var(2),x(2)
sd=0.
c
c looping over all points :
c
do i=1,npoints
ifirstv=(i-1)*(nvar+1)
c
c transfering the variables from VAR to X :
c
do j=1,(nvar+1)
x(j)=var(ifirstv+j)
end do
c
c now calling the YCALC function to evaluate Y :
c
yc=ycalc(par,x)
dy=yc-x(nvar+1)
sd=sd+(dy*dy)
end do
return
end
c---------------------------------------------------------------------
double precision function ycalc(a,x)
c---------------------------------------------------------------------
c
c Evaluates YCALC for a given set of parameters and a set of
c variables.
c
implicit double precision(a-h,o-z)
dimension a(*),x(*)
c
c the definition of Y should be inserted here :
c
|