【算法】02 SCE-UA简介及源代码

基本原理

SCE-UA算法是Qingyun Duan(段青云)、Soroosh Sorooshian 和Vijai Gupta等开发的一个具有复合优化策略的优化算法(Duan等,1992)。具体原理可以参考文献[1-3],以下图片摘录自王书功博士在《水文模型参数估计方法及参数估计不确定性研究》2.2.2.3章节(P101-108)中的介绍[5]。这里的CCE算法步骤分解不清楚,应当参考文献[2]。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

参考文献

[1]Duan, Q., Sorooshian, S., and Gupta, V. (1992), Effective and efficient global optimization for conceptual rainfall-runoff models, Water Resour. Res., 28( 4), 1015– 1031, doi:10.1029/91WR02985.
[2]Duan, Q.Y., Gupta, V.K. & Sorooshian, S. Shuffled complex evolution approach for effective and efficient global minimization. J Optim Theory Appl 76, 501–521 (1993). https://doi.org/10.1007/BF00939380
[3]Duan, Q., Sorooshian, S., & Gupta, V. K. (1994). Optimal use of the SCE-UA global optimization method for calibrating watershed models. Journal of Hydrology, 158(3-4), 265-284. https://doi.org/10.1016/0022-1694(94)90057-4
[4]王书功. 水文模型参数估计方法及参数估计不确定性研究[M]. 河南:黄河水利出版社,2010.
[5]王书功. 水文模型参数估计方法及参数估计不确定性研究[D]. 北京:中国科学院研究生院,2006.

原始代码

以下代码仅供参考,都无法成功运行。
可以成功运行的C++代码,请从我的另一篇博客《【算法】03 SCE-UA算法C++实现》下载

博客作者简介

很高兴认识您!
我叫卢家波,河海大学水文学及水资源博士研究生,研究兴趣为高效洪水淹没预测、洪水灾害预警、机器学习、替代模型和降阶模型。
变化环境下,极端洪水事件多发,我希望能通过研究为水灾害防御做出贡献,为人民服务。
欢迎交流讨论和研究合作,vx Jiabo_Lu
主页 https://lujiabo98.github.io
简历 https://lujiabo98.github.io/file/CV_JiaboLu_zh.pdf
博客 https://blog.csdn.net/weixin_43012724?type=blog
来信请说明博客标题及链接,谢谢。

源码

sceua.for

      SUBROUTINE SCEUA(A,AF,BL,BU,NOPT,MAXN,KSTOP,PCENTO,ISEED,
     &                 NGS,NPG,NPS,NSPL,MINGS,INIFLG,IPRINT)
C
C
C  SHUFFLED COMPLEX EVOLUTION METHOD FOR GLOBAL OPTIMIZATION
C     -- VERSION 2.1
C
C  BY QINGYUN DUAN
C  DEPARTMENT OF HYDROLOGY & WATER RESOURCES
C  UNIVERSITY OF ARIZONA, TUCSON, AZ 85721
C  (602) 621-9360, EMAIL: DUAN@HWR.ARIZONA.EDU
C
C  WRITTEN IN OCTOBER 1990.
C  REVISED IN AUGUST 1991
C  REVISED IN APRIL 1992
C
C  STATEMENT BY AUTHOR:
C  --------------------
C
C     THIS GENERAL PURPOSE GLOBAL OPTIMIZATION PROGRAM IS DEVELOPED AT
C     THE DEPARTMENT OF HYDROLOGY & WATER RESOURCES OF THE UNIVERSITY
C     OF ARIZONA.  FURTHER INFORMATION REGARDING THE SCE-UA METHOD CAN
C     BE OBTAINED FROM DR. Q. DUAN, DR. S. SOROOSHIAN OR DR. V.K. GUPTA
C     AT THE ADDRESS AND PHONE NUMBER LISTED ABOVE.  WE REQUEST ALL
C     USERS OF THIS PROGRAM MAKE PROPER REFERENCE TO THE PAPER ENTITLED
C     'EFFECTIVE AND EFFICIENT GLOBAL OPTIMIZATION FOR CONCEPTUAL
C     RAINFALL-RUNOFF MODELS' BY DUAN, Q., S. SOROOSHIAN, AND V.K. GUPTA,
C     WATER RESOURCES RESEARCH, VOL 28(4), PP.1015-1031, 1992.
C
C
C  LIST OF INPUT ARGUEMENT VARIABLES
C
C     A(.) = INITIAL PARAMETER SET
C     BL(.) = LOWER BOUND ON PARAMETERS
C     BU(.) = UPPER BOUND ON PARAMETERS
C     NOPT = NUMBER OF PARAMETERS TO BE OPTIMIZED
C
C
C  LIST OF SCE ALGORITHMIC CONTROL PARAMETERS:
C
C     NGS = NUMBER OF COMPLEXES IN THE INITIAL POPULATION
C     NPG = NUMBER OF POINTS IN EACH COMPLEX
C     NPT = TOTAL NUMBER OF POINTS IN INITIAL POPULATION (NPT=NGS*NPG)
C     NPS = NUMBER OF POINTS IN A SUB-COMPLEX
C     NSPL = NUMBER OF EVOLUTION STEPS ALLOWED FOR EACH COMPLEX BEFORE
C         COMPLEX SHUFFLING
C     MINGS = MINIMUM NUMBER OF COMPLEXES REQUIRED, IF THE NUMBER OF
C         COMPLEXES IS ALLOWED TO REDUCE AS THE OPTIMIZATION PROCEEDS
C     ISEED = INITIAL RANDOM SEED
C     INIFLG = FLAG ON WHETHER TO INCLUDE THE INITIAL POINT IN POPULATION
C         = 0, NOT INCLUDED
C         = 1, INCLUDED
C     IPRINT = FLAG FOR CONTROLLING PRINT-OUT AFTER EACH SHUFFLING LOOP
C         = 0, PRINT INFORMATION ON THE BEST POINT OF THE POPULATION
C         = 1, PRINT INFORMATION ON EVERY POINT OF THE POPULATION
C
C
C  CONVERGENCE CHECK PARAMETERS
C
C     MAXN = MAX NO. OF TRIALS ALLOWED BEFORE OPTIMIZATION IS TERMINATED
C     KSTOP = NUMBER OF SHUFFLING LOOPS IN WHICH THE CRITERION VALUE MUST
C         CHANG BY THE GIVEN PERCENTAGE BEFORE OPTIMIZATION IS TERMINATED
C     PCENTO = PERCENTAGE BY WHICH THE CRITERION VALUE MUST CHANGE IN
C         GIVEN NUMBER OF SHUFFLING LOOPS
C     IPCNVG = FLAG INDICATING WHETHER PARAMETER CONVERGENCE IS REACHED
C         (I.E., CHECK IF GNRNG IS LESS THAN 0.001)
C         = 0, PARAMETER CONVERGENCE NOT SATISFIED
C         = 1, PARAMETER CONVERGENCE SATISFIED
C
C
C  LIST OF LOCAL VARIABLES
C     X(.,.) = COORDINATES OF POINTS IN THE POPULATION
C     XF(.) = FUNCTION VALUES OF X(.,.)
C     XX(.) = COORDINATES OF A SINGLE POINT IN X
C     CX(.,.) = COORDINATES OF POINTS IN A COMPLEX
C     CF(.) = FUNCTION VALUES OF CX(.,.)
C     S(.,.) = COORDINATES OF POINTS IN THE CURRENT SIMPLEX
C     SF(.) = FUNCTION VALUES OF S(.,.)
C     BESTX(.) = BEST POINT AT CURRENT SHUFFLING LOOP
C     BESTF = FUNCTION VALUE OF BESTX(.)
C     WORSTX(.) = WORST POINT AT CURRENT SHUFFLING LOOP
C     WORSTF = FUNCTION VALUE OF WORSTX(.)
C     XNSTD(.) = STANDARD DEVIATION OF PARAMETERS IN THE POPULATION
C     GNRNG = NORMALIZED GEOMETRIC MEAN OF PARAMETER RANGES
C     LCS(.) = INDICES LOCATING POSITION OF S(.,.) IN X(.,.)
C     BOUND(.) = BOUND ON ITH VARIABLE BEING OPTIMIZED
C     NGS1 = NUMBER OF COMPLEXES IN CURRENT POPULATION
C     NGS2 = NUMBER OF COMPLEXES IN LAST POPULATION
C     ISEED1 = CURRENT RANDOM SEED
C     CRITER(.) = VECTOR CONTAINING THE BEST CRITERION VALUES OF THE LAST
C         10 SHUFFLING LOOPS
C
      CHARACTER*4 XNAME(16)
C
C  ARRAYS FROM THE INPUT DATA
      DIMENSION A(16),BL(16),BU(16)
C
C  LOCAL ARRAYS
      DIMENSION X(2000,16),XX(16),BESTX(16),WORSTX(16),XF(2000)
      DIMENSION S(50,16),SF(50),LCS(50),CX(2000,16),CF(2000)
      DIMENSION XNSTD(16),BOUND(16),CRITER(20),UNIT(16)
C
      COMMON/IOPARS/ICNTRL,IOUT,IDAT,IWBAL,ISCE,IPE,IPC,IDET
C
      DATA XNAME /'  X1','  X2','  X3','  X4','  X5','  X6','  X7',
     &'  X8','  X9',' X10',' X11',' X12',' X13',' X14',' X15',' X16'/
C
C  INITIALIZE VARIABLES
      WRITE(ISCE,400)
  400 FORMAT(//,2X,50(1H=),/,2X,'ENTER THE SHUFFLED COMPLEX EVOLUTION',
     &       ' GLOBAL SEARCH',/,2X,50(1H=))
      WRITE(*,400)
      NLOOP = 0
      LOOP = 0
      IGS = 0
C
C  INITIALIZE RANDOM SEED TO A NEGATIVE INTEGER
      ISEED1 = -ABS(ISEED)
C
C  COMPUTE THE TOTAL NUMBER OF POINTS IN INITIAL POPUALTION
      NPT = NGS * NPG
      NGS1 = NGS
      NPT1 = NPT
C
C  COMPUTE THE BOUND FOR PARAMETERS BEING OPTIMIZED
      DO J = 1, NOPT
        BOUND(J) = BU(J) - BL(J)
        UNIT(J) = 1.0
      END DO
C
C  COMPUTE THE FUNCTION VALUE OF THE INITIAL POINT
      FA = FUNCTN(NOPT,A)
C
C  PRINT THE INITIAL POINT AND ITS CRITERION VALUE
      WRITE(ISCE,500)
      WRITE(*,   500)
      WRITE(ISCE,510) (XNAME(J),J=1,NOPT)
      WRITE(*,   510) (XNAME(J),J=1,NOPT)
      WRITE(ISCE,520) FA,(A(J),J=1,NOPT)
      WRITE(*,   520) FA,(A(J),J=1,NOPT)
      IF (MAXN .EQ. 1) GO TO 10000
C
C  GENERATE AN INITIAL SET OF NPT1 POINTS IN THE PARAMETER SPACE
C  IF INIFLG IS EQUAL TO 1, SET X(1,.) TO INITIAL POINT A(.)
      IF (INIFLG .EQ. 1) THEN
        DO J = 1, NOPT
          X(1,J) = A(J)
        END DO
        XF(1) = FA
C
C  ELSE, GENERATE A POINT RANDOMLY AND SET IT EQUAL TO X(1,.)
      ELSE
        CALL GETPNT(NOPT,1,ISEED1,XX,BL,BU,UNIT,BL)
        DO J=1, NOPT
          X(1,J) = XX(J)
        END DO
        XF(1) = FUNCTN(NOPT,XX)
      END IF
      ICALL = 1
      IF (ICALL .GE. MAXN) GO TO 9000
C
C  GENERATE NPT1-1 RANDOM POINTS DISTRIBUTED UNIFORMLY IN THE PARAMETER
C  SPACE, AND COMPUTE THE CORRESPONDING FUNCTION VALUES
      DO I = 2, NPT1
        CALL GETPNT(NOPT,1,ISEED1,XX,BL,BU,UNIT,BL)
        DO J = 1, NOPT
          X(I,J) = XX(J)
        END DO
        XF(I) = FUNCTN(NOPT,XX)
        ICALL = ICALL + 1
        IF (ICALL .GE. MAXN) THEN
          NPT1 = I
          GO TO 45
        END IF
      END DO
C
C  ARRANGE THE POINTS IN ORDER OF INCREASING FUNCTION VALUE
   45 CALL SORT(NPT1,NOPT,X,XF)
C
C  RECORD THE BEST AND WORST POINTS
      DO J = 1, NOPT
        BESTX(J) = X(1,J)
        WORSTX(J) = X(NPT1,J)
      END DO
      BESTF = XF(1)
      WORSTF = XF(NPT1)
C
C  COMPUTE THE PARAMETER RANGE FOR THE INITIAL POPULATION
      CALL PARSTT(NPT1,NOPT,X,XNSTD,BOUND,GNRNG,IPCNVG)
C
C  PRINT THE RESULTS FOR THE INITIAL POPULATION
      WRITE(ISCE,600)
      WRITE(*,   600)
      WRITE(ISCE,610) (XNAME(J),J=1,NOPT)
      WRITE(*,   610) (XNAME(J),J=1,NOPT)
      WRITE(ISCE,630) NLOOP,ICALL,NGS1,BESTF,WORSTF,GNRNG,
     &               (BESTX(J),J=1,NOPT)
      WRITE(*,   630) NLOOP,ICALL,NGS1,BESTF,WORSTF,GNRNG,
     &               (BESTX(J),J=1,NOPT)
      IF (IPRINT .EQ. 1) THEN
        WRITE(ISCE,650) NLOOP
        DO I = 1, NPT1
          WRITE(ISCE,660) XF(I),GNRNG,(X(I,J),J=1,NOPT)
        END DO
      END IF
C
      IF (ICALL .GE. MAXN) GO TO 9000
      IF (IPCNVG .EQ. 1) GO TO 9200
C
C  BEGIN THE MAIN LOOP ----------------
 1000 CONTINUE
      NLOOP = NLOOP + 1
C
C  BEGIN LOOP ON COMPLEXES
      DO 3000 IGS = 1, NGS1
C
C  ASSIGN POINTS INTO COMPLEXES
      DO K1 = 1, NPG
        K2 = (K1-1) * NGS1 + IGS
        DO J = 1, NOPT
          CX(K1,J) = X(K2,J)
        END DO
        CF(K1) = XF(K2)
      END DO
C
C  BEGIN INNER LOOP - RANDOM SELECTION OF SUB-COMPLEXES ---------------
      DO 2000 LOOP = 1, NSPL
C
C  CHOOSE A SUB-COMPLEX (NPS POINTS) ACCORDING TO A LINEAR
C  PROBABILITY DISTRIBUTION
      IF (NPS .EQ. NPG) THEN
        DO K = 1, NPS
          LCS(K) = K
        END DO
        GO TO 85
      END IF
C
      RAND = RAN1(ISEED1)
      LCS(1) = 1 + INT(NPG + 0.5 - SQRT( (NPG+.5)**2 -
     &         NPG * (NPG+1) * RAND ))
      DO K = 2, NPS
   60   RAND = RAN1(ISEED1)
        LPOS = 1 + INT(NPG + 0.5 - SQRT((NPG+.5)**2 -
     &         NPG * (NPG+1) * RAND ))
        DO K1 = 1, K-1
          IF (LPOS .EQ. LCS(K1)) GO TO 60
        END DO
        LCS(K) = LPOS
      END DO
C
C  ARRANGE THE SUB-COMPLEX IN ORDER OF INCEASING FUNCTION VALUE
      CALL SORT1(NPS,LCS)
C
C  CREATE THE SUB-COMPLEX ARRAYS
   85 DO K = 1, NPS
        DO J = 1, NOPT
          S(K,J) = CX(LCS(K),J)
        END DO
        SF(K) = CF(LCS(K))
      END DO
C
C  USE THE SUB-COMPLEX TO GENERATE NEW POINT(S)
      CALL CCE(NOPT,NPS,S,SF,BL,BU,XNSTD,ICALL,MAXN,ISEED1)
C
C  IF THE SUB-COMPLEX IS ACCEPTED, REPLACE THE NEW SUB-COMPLEX
C  INTO THE COMPLEX
      DO K = 1, NPS
        DO J = 1, NOPT
          CX(LCS(K),J) = S(K,J)
        END DO
        CF(LCS(K)) = SF(K)
      END DO
C
C  SORT THE POINTS
      CALL SORT(NPG,NOPT,CX,CF)
C
C  IF MAXIMUM NUMBER OF RUNS EXCEEDED, BREAK OUT OF THE LOOP
      IF (ICALL .GE. MAXN) GO TO 2222
C
C  END OF INNER LOOP ------------
 2000 CONTINUE
 2222 CONTINUE
C
C  REPLACE THE NEW COMPLEX INTO ORIGINAL ARRAY X(.,.)
      DO K1 = 1, NPG
        K2 = (K1-1) * NGS1 + IGS
        DO J = 1, NOPT
          X(K2,J) = CX(K1,J)
        END DO
        XF(K2) = CF(K1)
      END DO
      IF (ICALL .GE. MAXN) GO TO 3333
C
C  END LOOP ON COMPLEXES
 3000 CONTINUE
C
C  RE-SORT THE POINTS
 3333 CALL SORT(NPT1,NOPT,X,XF)
C
C  RECORD THE BEST AND WORST POINTS
      DO J = 1, NOPT
        BESTX(J) = X(1,J)
        WORSTX(J) = X(NPT1,J)
      END DO
      BESTF = XF(1)
      WORSTF = XF(NPT1)
C
C  TEST THE POPULATION FOR PARAMETER CONVERGENCE
      CALL PARSTT(NPT1,NOPT,X,XNSTD,BOUND,GNRNG,IPCNVG)
C
C  PRINT THE RESULTS FOR CURRENT POPULATION
      WRITE(ISCE,630) NLOOP,ICALL,NGS1,BESTF,WORSTF,GNRNG,
     &               (BESTX(J),J=1,NOPT)
      WRITE(*,630) NLOOP,ICALL,NGS1,BESTF,WORSTF,GNRNG,
     &               (BESTX(J),J=1,NOPT)
      IF (IPRINT .EQ. 1) THEN
        WRITE(ISCE,650) NLOOP
        DO I = 1, NPT1
          WRITE(ISCE,660) XF(I),GNRNG,(X(I,J),J=1,NOPT)
        END DO
      END IF
C
C  TEST IF MAXIMUM NUMBER OF FUNCTION EVALUATIONS EXCEEDED
      IF (ICALL .GE. MAXN) GO TO 9000
C
C  COMPUTE THE COUNT ON SUCCESSIVE LOOPS W/O FUNCTION IMPROVEMENT
      CRITER(20) = BESTF
      IF (NLOOP .LT. (KSTOP+1)) GO TO 132
      DENOMI = ABS(CRITER(20-KSTOP) + CRITER(20)) / 2.
      TIMEOU = ABS(CRITER(20-KSTOP) - CRITER(20)) / DENOMI
      IF (TIMEOU .LT. PCENTO) GO TO 9100
  132 CONTINUE
      DO L = 1, 19
        CRITER(L) = CRITER(L+1)
      END DO
C
C  IF POPULATION IS CONVERGED INTO A SUFFICIENTLY SMALL SPACE
      IF (IPCNVG .EQ. 1) GO TO 9200
C
C  NONE OF THE STOPPING CRITERIA IS SATISFIED, CONTINUE SEARCH
C
C  CHECK FOR COMPLEX NUMBER REDUCTION
      IF (NGS1 .GT .MINGS) THEN
        NGS2 = NGS1
        NGS1 = NGS1 - 1
        NPT1 = NGS1 * NPG
        CALL COMP(NOPT,NPT1,NGS1,NGS2,NPG,X,XF,CX,CF)
      END IF
C
C  END OF MAIN LOOP -----------
      GO TO 1000
C
C  SEARCH TERMINATED
 9000 CONTINUE
      WRITE(ISCE,800) MAXN,LOOP,IGS,NLOOP
      WRITE(*,800) MAXN,LOOP,IGS,NLOOP
      GO TO 9999
 9100 CONTINUE
      WRITE(ISCE,810) PCENTO*100.,KSTOP
      WRITE(*,810) PCENTO*100.,KSTOP
      GO TO 9999
 9200 WRITE(ISCE,820) GNRNG*100.
      WRITE(*,820) GNRNG*100.
 9999 CONTINUE
C
C  PRINT THE FINAL PARAMETER ESTIMATE AND ITS FUNCTION VALUE
      WRITE(ISCE,830)
      WRITE(ISCE,510) (XNAME(J),J=1,NOPT)
      WRITE(ISCE,520) BESTF,(BESTX(J),J=1,NOPT)
      WRITE(*,830)
      WRITE(*,510) (XNAME(J),J=1,NOPT)
      WRITE(*,520) BESTF,(BESTX(J),J=1,NOPT)
      AF = BESTF
      DO J = 1, NOPT
        A(J) = BESTX(J)
      END DO
10000 CONTINUE
C
C  END OF SUBROUTINE SCEUA
      RETURN
  500 FORMAT(//,'*** PRINT THE INITIAL POINT AND ITS CRITERION ',
     &       'VALUE ***')
  510 FORMAT(/,' CRITERION',16(3X,A4,3X),/1X,80(1H-))
  520 FORMAT(F8.3,17G10.3)
  600 FORMAT(//,1X,'*** PRINT THE RESULTS OF THE SCE SEARCH ***')
  610 FORMAT(/,1X,'LOOP',1X,'TRIALS',1X,'COMPLXS',1X,'BEST F',1X,
     &       'WORST F',1X,'PAR RNG',1X,16(3X,A4,3X))
  630 FORMAT(I5,1X,I5,3X,I5,3F8.3,17(G10.3))
  650 FORMAT(/,1X,'POPULATION AT LOOP ',I3,/,1X,22(1H-))
  660 FORMAT(F8.3,17(G10.3))
  800 FORMAT(//,1X,'*** OPTIMIZATION SEARCH TERMINATED BECAUSE THE',
     &       ' LIMIT ON THE MAXIMUM',/,5X,'NUMBER OF TRIALS ',I5,
     &       ' EXCEEDED.  SEARCH WAS STOPPED AT',/,5X,'SUB-COMPLEX ',
     &       I3,' OF COMPLEX ',I3,' IN SHUFFLING LOOP ',I3,' ***')
  810 FORMAT(//,1X,'*** OPTIMIZATION TERMINATED BECAUSE THE CRITERION',
     &       ' VALUE HAS NOT CHANGED ',/,5X,F5.2,' PERCENT IN',I3,
     &       ' SHUFFLING LOOPS ***')
  820 FORMAT(//,1X,'*** OPTIMIZATION TERMINATED BECAUSE THE POPULATION',
     &       ' HAS CONVERGED INTO ',/,4X,F5.2,' PERCENT OF THE',
     &       ' FEASIBLE SPACE ***')
  830 FORMAT(//,'*** PRINT THE FINAL PARAMETER ESTIMATE AND ITS',
     &       ' CRITERION VALUE ***')
      END
C
C
C
C====================================================================
      SUBROUTINE CCE(NOPT,NPS,S,SF,BL,BU,XNSTD,ICALL,MAXN,ISEED)
C
C  ALGORITHM GENERATE A NEW POINT(S) FROM A SUB-COMPLEX
C
C  SUB-COMPLEX VARIABLES
      PARAMETER (C1=0.8,C2=0.4)
      DIMENSION S(50,16),SF(50),BU(16),BL(16),XNSTD(16)
C
C  LIST OF LOCAL VARIABLES
C    SB(.) = THE BEST POINT OF THE SIMPLEX
C    SW(.) = THE WORST POINT OF THE SIMPLEX
C    W2(.) = THE SECOND WORST POINT OF THE SIMPLEX
C    FW = FUNCTION VALUE OF THE WORST POINT
C    CE(.) = THE CENTROID OF THE SIMPLEX EXCLUDING WO
C    SNEW(.) = NEW POINT GENERATED FROM THE SIMPLEX
C    IVIOL = FLAG INDICATING IF CONSTRAINTS ARE VIOLATED
C          = 1 , YES
C          = 0 , NO
C
      DIMENSION SW(16),SB(16),CE(16),SNEW(16)
C
C  EQUIVALENCE OF VARIABLES FOR READABILTY OF CODE
      N = NPS
      M = NOPT
      ALPHA = 1.0
      BETA = 0.5
C
C  IDENTIFY THE WORST POINT WO OF THE SUB-COMPLEX S
C  COMPUTE THE CENTROID CE OF THE REMAINING POINTS
C  COMPUTE STEP, THE VECTOR BETWEEN WO AND CE
C  IDENTIFY THE WORST FUNCTION VALUE FW
      DO J = 1, M
        SB(J) = S(1,J)
        SW(J) = S(N,J)
        CE(J) = 0.0
        DO I = 1, N-1
          CE(J) = CE(J) + S(I,J)
        END DO
        CE(J) = CE(J)/DBLE(N-1)
      END DO
      FW = SF(N)
C
C  COMPUTE THE NEW POINT SNEW
C
C  FIRST TRY A REFLECTION STEP
      DO J = 1, M
        SNEW(J) = CE(J) + ALPHA * (CE(J) - SW(J))
      END DO
C
C  CHECK IF SNEW SATISFIES ALL CONSTRAINTS
      CALL CHKCST(NOPT,SNEW,BL,BU,IBOUND)
C
C
C  SNEW IS OUTSIDE THE BOUND,
C  CHOOSE A POINT AT RANDOM WITHIN FEASIBLE REGION ACCORDING TO
C  A NORMAL DISTRIBUTION WITH BEST POINT OF THE SUB-COMPLEX
C  AS MEAN AND STANDARD DEVIATION OF THE POPULATION AS STD
      IF (IBOUND .GE. 1) CALL GETPNT(NOPT,2,ISEED,SNEW,BL,BU,XNSTD,SB)
C
C
C  COMPUTE THE FUNCTION VALUE AT SNEW
      FNEW = FUNCTN(NOPT,SNEW)
      ICALL = ICALL + 1
C
C  COMPARE FNEW WITH THE WORST FUNCTION VALUE FW
C
C  FNEW IS LESS THAN FW, ACCEPT THE NEW POINT SNEW AND RETURN
      IF (FNEW .LE. FW) GO TO 2000
      IF (ICALL .GE. MAXN) GO TO 3000
C
C
C  FNEW IS GREATER THAN FW, SO TRY A CONTRACTION STEP
      DO J = 1, M
        SNEW(J) = CE(J) - BETA * (CE(J) - SW(J))
      END DO
C
C  COMPUTE THE FUNCTION VALUE OF THE CONTRACTED POINT
      FNEW = FUNCTN(NOPT,SNEW)
      ICALL = ICALL + 1
C
C  COMPARE FNEW TO THE WORST VALUE FW
C  IF FNEW IS LESS THAN OR EQUAL TO FW, THEN ACCEPT THE POINT AND RETURN
      IF (FNEW .LE. FW) GO TO 2000
      IF (ICALL .GE. MAXN) GO TO 3000
C
C
C  IF BOTH REFLECTION AND CONTRACTION FAIL, CHOOSE ANOTHER POINT
C  ACCORDING TO A NORMAL DISTRIBUTION WITH BEST POINT OF THE SUB-COMPLEX
C  AS MEAN AND STANDARD DEVIATION OF THE POPULATION AS STD
 1000 CALL GETPNT(NOPT,2,ISEED,SNEW,BL,BU,XNSTD,SB)
C
C  COMPUTE THE FUNCTION VALUE AT THE RANDOM POINT
      FNEW = FUNCTN(NOPT,SNEW)
      ICALL = ICALL + 1
C
C
C  REPLACE THE WORST POINT BY THE NEW POINT
 2000 CONTINUE
      DO J = 1, M
        S(N,J) = SNEW(J)
      END DO
      SF(N) = FNEW
 3000 CONTINUE
C
C  END OF SUBROUTINE CCE
      RETURN
      END
C
C
C
C===================================================================
      SUBROUTINE GETPNT(NOPT,IDIST,ISEED,X,BL,BU,STD,XI)
C
C     THIS SUBROUTINE GENERATES A NEW POINT WITHIN FEASIBLE REGION
C
C     X(.) = NEW POINT
C     XI(.) = FOCAL POINT
C     BL(.) = LOWER BOUND
C     BU(.) = UPPER BOUND
C     STD(.) = STANDARD DEVIATION OF PROBABILITY DISTRIBUTION
C     IDIST = PROBABILITY FLAG
C           = 1 - UNIFORM DISTRIBUTION
C           = 2 - GAUSSIAN DISTRIBUTION
C
      DIMENSION X(16),BL(16),BU(16),STD(16),XI(16)
C
    1 DO J=1, NOPT
    2   IF (IDIST .EQ. 1) RAND = RAN1(ISEED)
        IF (IDIST .EQ. 2) RAND = GASDEV(ISEED)
        X(J) = XI(J) + STD(J) * RAND * (BU(J) - BL(J))
C
C     CHECK EXPLICIT CONSTRAINTS
C        
        CALL CHKCST(1,X(J),BL(J),BU(J),IBOUND)
        IF (IBOUND .GE. 1) GO TO 2
      END DO
C
C     CHECK IMPLICIT CONSTRAINTS
C      
      CALL CHKCST(NOPT,X,BL,BU,IBOUND)
      IF (IBOUND .GE. 1) GO TO 1
C
      RETURN
      END
C
C
C
C===================================================================
      SUBROUTINE PARSTT(NPT,NOPT,X,XNSTD,BOUND,GNRNG,IPCNVG)      
C
C  SUBROUTINE CHECKING FOR PARAMETER CONVERGENCE
      DIMENSION X(2000,16),XMAX(16),XMIN(16)
      DIMENSION XMEAN(16),XNSTD(16),BOUND(16)
      PARAMETER (DELTA = 1.0D-20,PEPS=1.0D-3)
C
C  COMPUTE MAXIMUM, MINIMUM AND STANDARD DEVIATION OF PARAMETER VALUES
      GSUM = 0.D0
      DO K = 1, NOPT
        XMAX(K) = -1.0D+20
        XMIN(K) = 1.0D+20
        XSUM1 = 0.D0
        XSUM2 = 0.D0
        DO I = 1, NPT
          XMAX(K) = AMAX1(X(I,K), XMAX(K))
          XMIN(K) = AMIN1(X(I,K), XMIN(K))
          XSUM1 = XSUM1 + X(I,K)
          XSUM2 = XSUM2 + X(I,K)*X(I,K)
        END DO
        XMEAN(K) = XSUM1 / NPT
        XNSTD(K) = (XSUM2 / NPT - XMEAN(K)*XMEAN(K))
        IF (XNSTD(K) .LE. DELTA) XNSTD(K) = DELTA
        XNSTD(K) = SQRT(XNSTD(K))
        XNSTD(K) = XNSTD(K) / BOUND(K)
        GSUM = GSUM + LOG( DELTA + (XMAX(K)-XMIN(K))/BOUND(K) )
      END DO
      GNRNG = EXP(GSUM/NOPT)
C
C  CHECK IF NORMALIZED STANDARD DEVIATION OF PARAMETER IS <= EPS
      IPCNVG = 0
      IF (GNRNG .LE. PEPS) THEN
        IPCNVG = 1
      END IF
C
C  END OF SUBROUTINE PARSTT
      RETURN
      END
C
C
C
C====================================================================
      SUBROUTINE COMP(N,NPT,NGS1,NGS2,NPG,A,AF,B,BF)      
C
C
C  THIS SUBROUTINE REDUCE INPUT MATRIX A(N,NGS2*NPG) TO MATRIX
C  B(N,NGS1*NPG) AND VECTOR AF(NGS2*NPG) TO VECTOR BF(NGS1*NPG)
      DIMENSION A(2000,16),AF(2000),B(2000,16),BF(2000)
      DO IGS=1, NGS1
        DO IPG=1, NPG
          K1=(IPG-1)*NGS2 + IGS
          K2=(IPG-1)*NGS1 + IGS
          DO I=1, N
            B(K2,I) = A(K1,I)
          END DO
          BF(K2) = AF(K1)
        END DO
      END DO
C
      DO J=1, NPT
        DO I=1, N
          A(J,I) = B(J,I)
        END DO
        AF(J) = BF(J)
      END DO
C
C  END OF SUBROUTINE COMP
      RETURN
      END
C
C
C
C===================================================================
      SUBROUTINE SORT(N,M,RB,RA)      
C
C
C  SORTING SUBROUTINE ADAPTED FROM "NUMERICAL RECIPES"
C  BY W.H. PRESS ET AL., PP. 233-234
C
C  LIST OF VARIABLES
C     RA(.) = ARRAY TO BE SORTED
C     RB(.,.) = ARRAYS ORDERED CORRESPONDING TO REARRANGEMENT OF RA(.)
C     WK(.,.), IWK(.) = LOCAL VARIBLES
C
      DIMENSION RA(2000),RB(2000,16),WK(2000,16),IWK(2000)
C
      CALL INDEXX(N, RA, IWK)
      DO 11 I = 1, N
      WK(I,1) = RA(I)
   11 CONTINUE
      DO 12 I = 1, N
      RA(I) = WK(IWK(I),1)
   12 CONTINUE
      DO 14 J = 1, M
      DO 13 I = 1, N
      WK(I,J) = RB(I,J)
   13 CONTINUE
   14 CONTINUE
      DO 16 J = 1, M
      DO 15 I = 1, N
      RB(I,J) = WK(IWK(I),J)
   15 CONTINUE
   16 CONTINUE
C
C  END OF SUBROUTINE SORT
      RETURN
      END
C
C
C===========================================================
      SUBROUTINE SORT1(N,RA)      
C
C
C  SORTING SUBROUTINE ADAPTED FROM "NUMERICAL RECIPES"
C  BY W.H. PRESS ET AL., PP. 231
C
C  LIST OF VARIABLES
C     RA(.) = INTEGER ARRAY TO BE SORTED
C
      DIMENSION RA(N)
C
      INTEGER RA, RRA
C
      L = (N / 2) + 1
      IR = N
   10 CONTINUE
      IF (L .GT. 1) THEN
      L = L - 1
      RRA = RA(L)
      ELSE
      RRA = RA(IR)
      RA(IR) = RA(1)
      IR = IR - 1
      IF (IR .EQ. 1) THEN
      RA(1) = RRA
      RETURN
      END IF
      END IF
      I = L
      J = L + L
   20 IF (J .LE. IR) THEN
      IF (J .LT. IR) THEN
      IF (RA(J) .LT. RA(J + 1)) J = J + 1
      END IF
      IF (RRA .LT. RA(J)) THEN
      RA(I) = RA(J)
      I = J
      J = J + J
      ELSE
      J = IR + 1
      END IF
      GOTO 20
      END IF
      RA(I) = RRA
      GOTO 10
C
C  END OF SUBROUTINE SORT1
      END
C
C
C
C=======================================================
      SUBROUTINE INDEXX(N, ARRIN, INDX)      
C
C
C  THIS SUBROUTINE IS FROM "NUMERICAL RECIPES" BY PRESS ET AL.
      DIMENSION ARRIN(N), INDX(N)
C
      DO 11 J = 1, N
      INDX(J) = J
   11 CONTINUE
      L = (N / 2) + 1
      IR = N
   10 CONTINUE
      IF (L .GT. 1) THEN
      L = L - 1
      INDXT = INDX(L)
      Q = ARRIN(INDXT)
      ELSE
      INDXT = INDX(IR)
      Q = ARRIN(INDXT)
      INDX(IR) = INDX(1)
      IR = IR - 1
      IF (IR .EQ. 1) THEN
      INDX(1) = INDXT
      RETURN
      END IF
      END IF
      I = L
      J = L + L
   20 IF (J .LE. IR) THEN
      IF (J .LT. IR) THEN
      IF (ARRIN(INDX(J)) .LT. ARRIN(INDX(J + 1))) J = J + 1
      END IF
      IF (Q .LT. ARRIN(INDX(J))) THEN
      INDX(I) = INDX(J)
      I = J
      J = J + J
      ELSE
      J = IR + 1
      END IF
      GOTO 20
      END IF
      INDX(I) = INDXT
      GOTO 10
C
C  END OF SUBROUTINE INDEXX
      END
C
C
C
C==============================================================
      REAL FUNCTION RAN1(IDUM)
C
C
C  THIS SUBROUTINE IS FROM "NUMERICAL RECIPES" BY PRESS ET AL.
      DIMENSION R(97)
      PARAMETER (M1 = 259200, IA1 = 7141, IC1 = 54773, RM1 =
     &3.8580247E-6)
      PARAMETER (M2 = 134456, IA2 = 8121, IC2 = 28411, RM2 =
     &7.4373773E-6)
      PARAMETER (M3 = 243000, IA3 = 4561, IC3 = 51349)
      SAVE
      DATA IFF / 0 /
      IF ((IDUM .LT. 0) .OR. (IFF .EQ. 0)) THEN
      IFF = 1
      IX1 = MOD(IC1 - IDUM,M1)
      IX1 = MOD((IA1 * IX1) + IC1,M1)
      IX2 = MOD(IX1,M2)
      IX1 = MOD((IA1 * IX1) + IC1,M1)
      IX3 = MOD(IX1,M3)
      DO 11 J = 1, 97
      IX1 = MOD((IA1 * IX1) + IC1,M1)
      IX2 = MOD((IA2 * IX2) + IC2,M2)
      R(J) = (DBLE(IX1) + (DBLE(IX2) * RM2)) * RM1
   11 CONTINUE
      IDUM = 1
      END IF
      IX1 = MOD((IA1 * IX1) + IC1,M1)
      IX2 = MOD((IA2 * IX2) + IC2,M2)
      IX3 = MOD((IA3 * IX3) + IC3,M3)
      J = 1 + ((97 * IX3) / M3)
      IF ((J .GT. 97) .OR. (J .LT. 1)) PAUSE
      RAN1 = R(J)
      R(J) = (DBLE(IX1) + (DBLE(IX2) * RM2)) * RM1
C
C  END OF SUBROUTINE RAN1
      RETURN
      END
C
C
C
C===============================================================
      FUNCTION GASDEV(IDUM)
C
C
C  THIS SUBROUTINE IS FROM "NUMERICAL RECIPES" BY PRESS ET AL.
      COMMON /GASBLK/ ISET
      DATA ISET / 0 /
      IF (ISET .EQ. 0) THEN
    1 V1 = (2. * RAN1(IDUM)) - 1.
      V2 = (2. * RAN1(IDUM)) - 1.
      R = (V1 ** 2) + (V2 ** 2)
      IF (R .GE. 1.) GOTO 1
      FAC = SQRT(- ((2. * LOG(R)) / R))
      GSET = V1 * FAC
      GASDEV = V2 * FAC
      ISET = 1
      ELSE
      GASDEV = GSET
      ISET = 0
      END IF
C
C  END OF SUBROUTINE GASDEV
      RETURN
      END

scein.for

      SUBROUTINE SCEIN(NOPT,MAXN,KSTOP,PCENTO,ISEED,
     &                 NGS,NPG,NPS,NSPL,MINGS,INIFLG,IPRINT)
C
C
C   THIS SUBROUTINE READS AND PRINTS THE INPUT VARIABLES FOR
C   SHUFFLED COMPLEX EVOLUTION METHOD FOR GLOBAL OPTIMIZATION
C     -- VERSION 2.1
C
C   WRITTEN BY QINGYUN DUAN - UNIVERSITY OF ARIZONA, APRIL 1992
C
C
      CHARACTER*10 PCNTRL,DEFLT,USRSP
      CHARACTER*4 REDUC,INITL,YSFLG,NOFLG
      COMMON/IOPARS/ICNTRL,IOUT,IDAT,IWBAL,ISCE,IPE,IPC,IDET
C
      DATA DEFLT/' DEFAULT  '/
      DATA USRSP/'USER SPEC.'/
      DATA YSFLG/'YES '/
      DATA NOFLG/'NO  '/
C
      IERROR = 0
      IWARN = 0
      WRITE(ISCE,700)
  700 FORMAT(10X,'SHUFFLED COMPLEX EVOLUTION GLOBAL OPTIMIZATION',
     &       /,10X,46(1H=))
C
C
C  READ THE SCE CONTROL PARAMETERS
      IDEFLT = 0
      READ (ICNTRL,*)
      READ (ICNTRL,800) MAXN,KSTOP,PCENTO,NGS,ISEED,IDEFLT
  800 FORMAT(2I5,F5.2,3I5)
      IF (ISEED .EQ. 0) ISEED = 1969
C
C
C  IF IDEFLT IS EQUAL TO 1, READ THE SCE CONTROL PARAMETERS
      IF (IDEFLT .EQ. 1) THEN
        READ(ICNTRL,810) NPG,NPS,NSPL,MINGS,INIFLG,IPRINT
  810   FORMAT(6I5)
        PCNTRL = USRSP
        IF (NPG .EQ. 0) NPG = 2*NOPT + 1
        IF (NPS .EQ. 0) NPS = NOPT + 1
        IF (NSPL .EQ. 0) NSPL = NPG
        IF (MINGS .EQ. 0) MINGS = NGS
      ELSE
        READ(ICNTRL,*)
        PCNTRL = DEFLT
      END IF
C
C
C  IF IDEFLT IS EQUAL TO 0, SET THE SCE CONTROL PARAMETERS TO
C  THE DEFAULT VALUES
      IF (IDEFLT .EQ. 0) THEN
        NPG = 2*NOPT + 1
        NPS = NOPT + 1
        NSPL = NPG
        MINGS = NGS
        INIFLG = 0
        IPRINT = 0
      END IF
C
C
C  CHECK IF THE SCE CONTROL PARAMETERS ARE VALID
      IF (NGS .LT. 1 .OR. NGS .GE. 1320) THEN
        WRITE(ISCE,900) NGS
  900   FORMAT(//,1X,'**ERROR** NUMBER OF COMPLEXES IN INITIAL ',
     *         ' POPULATION ',I5,' IS NOT A VALID CHOICE')
        IERROR = IERROR + 1
      END IF
C
      IF (KSTOP .LT. 0 .OR. KSTOP .GE. 10) THEN
        WRITE(ISCE,901) KSTOP
  901   FORMAT(//,1X,'**WARNING** THE NUMBER OF SHUFFLING LOOPS IN',
     *  ' WHICH THE CRITERION VALUE MUST CHANGE ',/,13X,'SHOULD BE',
     *  ' GREATER THAN 0 AND LESS THAN 10.  ','KSTOP = ',I2,
     *  ' WAS SPECIFIED.'/,13X,'BUT KSTOP = 5 WILL BE USED INSTEAD.')
        IWARN = IWARN + 1
        KSTOP=5
      END IF
C
      IF (MINGS .LT. 1 .OR. MINGS .GT. NGS) THEN
        WRITE(ISCE,902) MINGS
  902   FORMAT(//,1X,'**WARNING** THE MINIMUM NUMBER OF COMPLEXES ',
     *         I2,' IS NOT A VALID CHOICE. SET IT TO DEFAULT')
        IWARN = IWARN + 1
        MINGS = NGS
      END IF
C
      IF (NPG .LT. 2 .OR. NPG .GT. 1320/MAX(NGS,1)) THEN
        WRITE(ISCE,903) NPG
  903   FORMAT(//,1X,'**WARNING** THE NUMBER OF POINTS IN A COMPLEX ',
     *         I4,' IS NOT A VALID CHOICE, SET IT TO DEFAULT')
        IWARN = IWARN + 1
        NPG = 2*NOPT+1
      END IF
C
      IF (NPS.LT.2 .OR. NPS.GT.NPG .OR. NPS.GT.50) THEN
        WRITE(ISCE,904) NPS
  904   FORMAT(//,1X,'**WARNING** THE NUMBER OF POINTS IN A SUB-',
     *  'COMPLEX ',I4,' IS NOT A VALID CHOICE, SET IT TO DEFAULT')
        IWARN = IWARN + 1
        NPS = NOPT + 1
      END IF
C
      IF (NSPL .LT. 1) THEN
        WRITE(ISCE,905) NSPL
  905   FORMAT(//,1X,'**WARNING** THE NUMBER OF EVOLUTION STEPS ',
     *         'TAKEN IN EACH COMPLEX BEFORE SHUFFLING ',I4,/,13X,
     *         'IS NOT A VALID CHOICE, SET IT TO DEFAULT')
        IWARN = IWARN + 1
        NSPL = NPG
      END IF
C
C  COMPUTE THE TOTAL NUMBER OF POINTS IN INITIAL POPULATION
      NPT = NGS * NPG
C
      IF (NPT .GT. 1320) THEN
        WRITE(ISCE,906) NPT
  906   FORMAT(//,1X,'**WARNING** THE NUMBER OF POINTS IN INITIAL ',
     *         'POPULATION ',I5,' EXCEED THE POPULATION LIMIT,',/,13X,
     *         'SET NGS TO 2, AND NPG, NPS AND NSPL TO DEFAULTS')
        IWARN = IWARN + 1
        NGS = 2
        NPG = 2*NOPT + 1
        NPS = NOPT + 1
        NSPL = NPG
      END IF
C
C  PRINT OUT THE TOTAL NUMBER OF ERROR AND WARNING MESSAGES
      IF (IERROR .GE. 1) WRITE(ISCE,907) IERROR
  907 FORMAT(//,1X,'*** TOTAL NUMBER OF ERROR MESSAGES IS ',I2)
C
      IF (IWARN .GE. 1) WRITE(ISCE,908) IWARN
  908 FORMAT(//,1X,'*** TOTAL NUMBER OF WARNING MESSAGES IS ',I2)
C
      IF (MINGS .LT. NGS) THEN
        REDUC = YSFLG
      ELSE
        REDUC = NOFLG
      END IF
C
      IF (INIFLG .NE. 0) THEN
        INITL = YSFLG
      ELSE
        INITL = NOFLG
      END IF
C
C
C  PRINT SHUFFLED COMPLEX EVOLUTION OPTIMIZATION OPTIONS
  104 WRITE(ISCE,910)
  910 FORMAT(//,2X,'SCE CONTROL',5X,'MAX TRIALS',5X,
     &'REQUIRED IMPROVEMENT',5X,'RANDOM',/,3X,'PARAMETER',8X,
     &'ALLOWED',6X,'PERCENT',4X,'NO. LOOPS',6X,'SEED',/,
     &2X,11(1H-),5X,10(1H-),5X,7(1H-),4X,9(1H-),5X,6(1H-))
C
      PCENTA=PCENTO*100.
      WRITE(ISCE,912) PCNTRL,MAXN,PCENTA,KSTOP,ISEED
  912 FORMAT(3X,A10,7X,I5,10X,F3.1,9X,I2,9X,I5)
      WRITE(ISCE,914) NGS,NPG,NPT,NPS,NSPL
  914 FORMAT(//,18X,'SCE ALGORITHM CONTROL PARAMETERS',/,18X,32(1H=),
     &//,2X,'NUMBER OF',5X,'POINTS PER',5X,'POINTS IN',6X,'POINTS PER',
     &4X,'EVOL. STEPS',/,2X,'COMPLEXES',6X,'COMPLEX',6X,'INI. POPUL.',
     &5X,'SUB-COMPLX',4X,'PER COMPLEX',/,2X,9(1H-),5X,10(1H-),4X,
     &11(1H-),5X,10(1H-),4X,11(1H-),5X,/,2X,5(I5,10X))
      WRITE(ISCE,915) REDUC,MINGS,INITL
  915 FORMAT(//,15X,'COMPLX NO.',5X,'MIN COMPLEX',5X,'INI. POINT',/,
     &15X,'REDUCTION',6X,'NO. ALLOWED',6X,'INCLUDED',/,
     &15X,10(1H-),5X,11(1H-),5X,10(1H-),/,18X,A4,6X,I8,13X,A4)
      IF (IERROR .GE. 1) THEN
      WRITE(ISCE,922)
  922 FORMAT(//,'*** THE OPTIMIZATION SEARCH IS NOT CONDUCTED BECAUSE',
     &       ' OF INPUT DATA ERROR ***')
      STOP
      END IF
C
C  END OF SUBROUTINE SCEIN
      RETURN
      END

翻译

以下代码仅供参考,都无法成功运行。
笔者根据源码翻译如下:
sceua.for

      SUBROUTINE SCEUA(A,AF,BL,BU,NOPT,MAXN,KSTOP,PCENTO,ISEED,
     &                 NGS,NPG,NPS,NSPL,MINGS,INIFLG,IPRINT)
C
C
C  洗牌复形演化算法(全局优化)
C     ——版本2.1
C  
C  作者:段青云
C  亚利桑那州图森市亚利桑那大学
C  水文与水资源系 AZ 85721
C  (602) 621-9360, 邮箱: DUAN@HWR.ARIZONA.EDU
C
C  写于1990年10月
C  1991年8月修改
C  1992年4月修改
C
C  作者声明:
C  --------------------
C
C     该通用全局优化程序由亚利桑那大学水文与水资源系开发。 
C     有关SCE-UA方法的更多信息
C     可以根据上面列出的地址和电话号码
C     咨询段青云博士、S. SOROOSHIAN博士或V.K. GUPTA博士。
C     我们要求本程序的所有用户正确引用论文:
C     Duan, Q., Sorooshian, S., and Gupta, V. (1992), 
C     Effective and efficient global optimization 
C     for conceptual rainfall-runoff models, 
C     Water Resour. Res., 28(4), 1015–1031, doi:10.1029/91WR02985.
C
C
C  输入参数变量列表
C
C     A(.) = 初始参数集
C     BL(.) = 参数下限
C     BU(.) = 参数上限
C     NOPT = 待优化的参数数量
C
C
C  SCE算法控制参数列表:
C
C     NGS = 初始种群中的复形数量
C     NPG = 每个复形中的点的个数
C     NPT = 初始种群中的总点数(NPT=NGS*NPG)
C     NPS = 子复形中的点数
C     NSPL = 复形洗牌前每个复形
C            允许的进化步骤数
C     MINGS = 如果在优化过程中允许减少复形的数量,
C             则需要最少的复形数量
C     ISEED = 初始随机种子
C     INIFLG = 标记是否将初始点包括在种群中
C         = 0, 不包括
C         = 1, 包括
C     IPRINT = 用于控制每个洗牌循环后的打印输出的标志
C         = 0, 打印关于种群最佳点的信息
C         = 1, 打印关于种群每个点的信息
C
C
C  收敛检查参数
C
C     MAXN = 优化终止前允许的最大试验次数
C     KSTOP = 在终止优化之前,
C             标准值必须改变给定百分比的洗牌循环数
C     PCENTO = 给定数量的随机循环中,
C              标准值必须改变的百分比
C     IPCNVG = 指示是否达到参数收敛的标志
C             (即,检查 GNRNG 是否小于 0.001)
C         = 0, 参数收敛不满足
C         = 1, 参数收敛满足
C
C
C  局部变量列表
C     X(.,.) = 种群中点的坐标
C     XF(.) = X(.,.)的函数值
C     XX(.) = X中单点的坐标
C     CX(.,.) = 复形中点的坐标
C     CF(.) = CX(.,.)的函数值
C     S(.,.) = 当前单纯形中点的坐标
C     SF(.) = S(.,.)的函数值
C     BESTX(.) = 当前洗牌循环的最佳点
C     BESTF = BESTX(.)的函数值
C     WORSTX(.) = 当前洗牌循环的最坏点
C     WORSTF = WORSTX(.)的函数值
C     XNSTD(.) = 种群中参数的标准差
C     GNRNG = 参数范围的归一化几何平均值
C     LCS(.) = 索引定位S(.,.)在 X(.,.)中的位置
C     BOUND(.) = 优化变量的约束
C     NGS1 = 当前种群中的复形数量
C     NGS2 = 前一种群中的复形数量
C     ISEED1 = 当前随机种子
C     CRITER(.) = 包含最近10个洗牌循环的
C                 最佳标准值的向量
C
      CHARACTER*4 XNAME(16)
C
C  来自输入数据的数组
      DIMENSION A(16),BL(16),BU(16)
C
C  局部数组
      DIMENSION X(2000,16),XX(16),BESTX(16),WORSTX(16),XF(2000)
      DIMENSION S(50,16),SF(50),LCS(50),CX(2000,16),CF(2000)
      DIMENSION XNSTD(16),BOUND(16),CRITER(20),UNIT(16)
C
      COMMON/IOPARS/ICNTRL,IOUT,IDAT,IWBAL,ISCE,IPE,IPC,IDET
C
      DATA XNAME /'  X1','  X2','  X3','  X4','  X5','  X6','  X7',
     &'  X8','  X9',' X10',' X11',' X12',' X13',' X14',' X15',' X16'/
C
C  初始化变量
      WRITE(ISCE,400)
  400 FORMAT(//,2X,50(1H=),/,2X,'ENTER THE SHUFFLED COMPLEX EVOLUTION',
     &       ' GLOBAL SEARCH',/,2X,50(1H=))
      WRITE(*,400)
      NLOOP = 0
      LOOP = 0
      IGS = 0
C
C  初始化随机种子为负整数
      ISEED1 = -ABS(ISEED)
C
C  计算在初始种群中的总点数
      NPT = NGS * NPG
      NGS1 = NGS
      NPT1 = NPT
C
C  计算待优化参数约束范围
      DO J = 1, NOPT
        BOUND(J) = BU(J) - BL(J)
        UNIT(J) = 1.0
      END DO
C
C  计算初始点函数值
      FA = FUNCTN(NOPT,A)
C
C  打印初始点及其标准值
      WRITE(ISCE,500)
      WRITE(*,   500)
      WRITE(ISCE,510) (XNAME(J),J=1,NOPT)
      WRITE(*,   510) (XNAME(J),J=1,NOPT)
      WRITE(ISCE,520) FA,(A(J),J=1,NOPT)
      WRITE(*,   520) FA,(A(J),J=1,NOPT)
      IF (MAXN .EQ. 1) GO TO 10000
C
C  在NPT1点的参数空间内生成一个初始集合
C  如果INIFLG等于1,设置X(1,.)为初始点A(.)
      IF (INIFLG .EQ. 1) THEN
        DO J = 1, NOPT
          X(1,J) = A(J)
        END DO
        XF(1) = FA
C
C  否则,随机生成一个点并设置其等于X(1,.)
      ELSE
        CALL GETPNT(NOPT,1,ISEED1,XX,BL,BU,UNIT,BL)
        DO J=1, NOPT
          X(1,J) = XX(J)
        END DO
        XF(1) = FUNCTN(NOPT,XX)
      END IF
      ICALL = 1
      IF (ICALL .GE. MAXN) GO TO 9000
C
C  生成在参数空间均匀分布的NPT1-1个随机点,
C  并计算对应的函数值
      DO I = 2, NPT1
        CALL GETPNT(NOPT,1,ISEED1,XX,BL,BU,UNIT,BL)
        DO J = 1, NOPT
          X(I,J) = XX(J)
        END DO
        XF(I) = FUNCTN(NOPT,XX)
        ICALL = ICALL + 1
        IF (ICALL .GE. MAXN) THEN
          NPT1 = I
          GO TO 45
        END IF
      END DO
C
C  按函数值递增的顺序排列点
   45 CALL SORT(NPT1,NOPT,X,XF)
C
C  记录最好和最差的点
      DO J = 1, NOPT
        BESTX(J) = X(1,J)
        WORSTX(J) = X(NPT1,J)
      END DO
      BESTF = XF(1)
      WORSTF = XF(NPT1)
C
C  计算初始种群的参数范围
      CALL PARSTT(NPT1,NOPT,X,XNSTD,BOUND,GNRNG,IPCNVG)
C
C  打印初始种群的结果
      WRITE(ISCE,600)
      WRITE(*,   600)
      WRITE(ISCE,610) (XNAME(J),J=1,NOPT)
      WRITE(*,   610) (XNAME(J),J=1,NOPT)
      WRITE(ISCE,630) NLOOP,ICALL,NGS1,BESTF,WORSTF,GNRNG,
     &               (BESTX(J),J=1,NOPT)
      WRITE(*,   630) NLOOP,ICALL,NGS1,BESTF,WORSTF,GNRNG,
     &               (BESTX(J),J=1,NOPT)
      IF (IPRINT .EQ. 1) THEN
        WRITE(ISCE,650) NLOOP
        DO I = 1, NPT1
          WRITE(ISCE,660) XF(I),GNRNG,(X(I,J),J=1,NOPT)
        END DO
      END IF
C
      IF (ICALL .GE. MAXN) GO TO 9000
      IF (IPCNVG .EQ. 1) GO TO 9200
C
C  开始主循环 ----------------
 1000 CONTINUE
      NLOOP = NLOOP + 1
C
C  在复形上开始循环
      DO 3000 IGS = 1, NGS1
C
C  为复形分配点
      DO K1 = 1, NPG
        K2 = (K1-1) * NGS1 + IGS
        DO J = 1, NOPT
          CX(K1,J) = X(K2,J)
        END DO
        CF(K1) = XF(K2)
      END DO
C
C  开始内循环 - 子复形的随机选择 ---------------
      DO 2000 LOOP = 1, NSPL
C
C  根据线性概率分布
C  选择子复形(NPS个点)
      IF (NPS .EQ. NPG) THEN
        DO K = 1, NPS
          LCS(K) = K
        END DO
        GO TO 85
      END IF
C
      RAND = RAN1(ISEED1)
      LCS(1) = 1 + INT(NPG + 0.5 - SQRT( (NPG+.5)**2 -
     &         NPG * (NPG+1) * RAND ))
      DO K = 2, NPS
   60   RAND = RAN1(ISEED1)
        LPOS = 1 + INT(NPG + 0.5 - SQRT((NPG+.5)**2 -
     &         NPG * (NPG+1) * RAND ))
        DO K1 = 1, K-1
          IF (LPOS .EQ. LCS(K1)) GO TO 60
        END DO
        LCS(K) = LPOS
      END DO
C
C  按照函数值递增的顺序排列子复形
      CALL SORT1(NPS,LCS)
C
C  创建子复形数组
   85 DO K = 1, NPS
        DO J = 1, NOPT
          S(K,J) = CX(LCS(K),J)
        END DO
        SF(K) = CF(LCS(K))
      END DO
C
C  使用子复形生成新点
      CALL CCE(NOPT,NPS,S,SF,BL,BU,XNSTD,ICALL,MAXN,ISEED1)
C
C  如果子复形被接受,
C  将新的子复形更换到复形中
      DO K = 1, NPS
        DO J = 1, NOPT
          CX(LCS(K),J) = S(K,J)
        END DO
        CF(LCS(K)) = SF(K)
      END DO
C
C  排序点
      CALL SORT(NPG,NOPT,CX,CF)
C
C  如果超过最大运行次数,则跳出循环
      IF (ICALL .GE. MAXN) GO TO 2222
C
C  结束内循环 ------------
 2000 CONTINUE
 2222 CONTINUE
C
C  将新复形替换为原始数组 X(.,.)
      DO K1 = 1, NPG
        K2 = (K1-1) * NGS1 + IGS
        DO J = 1, NOPT
          X(K2,J) = CX(K1,J)
        END DO
        XF(K2) = CF(K1)
      END DO
      IF (ICALL .GE. MAXN) GO TO 3333
C
C  结束复形循环
 3000 CONTINUE
C
C  对点重新排序
 3333 CALL SORT(NPT1,NOPT,X,XF)
C
C  记录最好和最坏的点
      DO J = 1, NOPT
        BESTX(J) = X(1,J)
        WORSTX(J) = X(NPT1,J)
      END DO
      BESTF = XF(1)
      WORSTF = XF(NPT1)
C
C  测试种群的参数收敛性
      CALL PARSTT(NPT1,NOPT,X,XNSTD,BOUND,GNRNG,IPCNVG)
C
C  打印当前种群的结果
      WRITE(ISCE,630) NLOOP,ICALL,NGS1,BESTF,WORSTF,GNRNG,
     &               (BESTX(J),J=1,NOPT)
      WRITE(*,630) NLOOP,ICALL,NGS1,BESTF,WORSTF,GNRNG,
     &               (BESTX(J),J=1,NOPT)
      IF (IPRINT .EQ. 1) THEN
        WRITE(ISCE,650) NLOOP
        DO I = 1, NPT1
          WRITE(ISCE,660) XF(I),GNRNG,(X(I,J),J=1,NOPT)
        END DO
      END IF
C
C  测试是否超过了函数评估次数的最大值
      IF (ICALL .GE. MAXN) GO TO 9000
C
C  计算无函数改进的连续循环次数
      CRITER(20) = BESTF
      IF (NLOOP .LT. (KSTOP+1)) GO TO 132
      DENOMI = ABS(CRITER(20-KSTOP) + CRITER(20)) / 2.
      TIMEOU = ABS(CRITER(20-KSTOP) - CRITER(20)) / DENOMI
      IF (TIMEOU .LT. PCENTO) GO TO 9100
  132 CONTINUE
      DO L = 1, 19
        CRITER(L) = CRITER(L+1)
      END DO
C
C  如果种群聚集到一个足够小的空间
      IF (IPCNVG .EQ. 1) GO TO 9200
C
C  不满足任何停止标准,继续搜索
C
C  检查复形数量减少
      IF (NGS1 .GT .MINGS) THEN
        NGS2 = NGS1
        NGS1 = NGS1 - 1
        NPT1 = NGS1 * NPG
        CALL COMP(NOPT,NPT1,NGS1,NGS2,NPG,X,XF,CX,CF)
      END IF
C
C  结束主循环 -----------
      GO TO 1000
C
C  搜索终止
 9000 CONTINUE
      WRITE(ISCE,800) MAXN,LOOP,IGS,NLOOP
      WRITE(*,800) MAXN,LOOP,IGS,NLOOP
      GO TO 9999
 9100 CONTINUE
      WRITE(ISCE,810) PCENTO*100.,KSTOP
      WRITE(*,810) PCENTO*100.,KSTOP
      GO TO 9999
 9200 WRITE(ISCE,820) GNRNG*100.
      WRITE(*,820) GNRNG*100.
 9999 CONTINUE
C
C  打印最终参数估计及其函数值
      WRITE(ISCE,830)
      WRITE(ISCE,510) (XNAME(J),J=1,NOPT)
      WRITE(ISCE,520) BESTF,(BESTX(J),J=1,NOPT)
      WRITE(*,830)
      WRITE(*,510) (XNAME(J),J=1,NOPT)
      WRITE(*,520) BESTF,(BESTX(J),J=1,NOPT)
      AF = BESTF
      DO J = 1, NOPT
        A(J) = BESTX(J)
      END DO
10000 CONTINUE
C
C  子程序SCEUA结束
      RETURN
  500 FORMAT(//,'*** PRINT THE INITIAL POINT AND ITS CRITERION ',
     &       'VALUE ***')
  510 FORMAT(/,' CRITERION',16(3X,A4,3X),/1X,80(1H-))
  520 FORMAT(F8.3,17G10.3)
  600 FORMAT(//,1X,'*** PRINT THE RESULTS OF THE SCE SEARCH ***')
  610 FORMAT(/,1X,'LOOP',1X,'TRIALS',1X,'COMPLXS',1X,'BEST F',1X,
     &       'WORST F',1X,'PAR RNG',1X,16(3X,A4,3X))
  630 FORMAT(I5,1X,I5,3X,I5,3F8.3,17(G10.3))
  650 FORMAT(/,1X,'POPULATION AT LOOP ',I3,/,1X,22(1H-))
  660 FORMAT(F8.3,17(G10.3))
  800 FORMAT(//,1X,'*** OPTIMIZATION SEARCH TERMINATED BECAUSE THE',
     &       ' LIMIT ON THE MAXIMUM',/,5X,'NUMBER OF TRIALS ',I5,
     &       ' EXCEEDED.  SEARCH WAS STOPPED AT',/,5X,'SUB-COMPLEX ',
     &       I3,' OF COMPLEX ',I3,' IN SHUFFLING LOOP ',I3,' ***')
  810 FORMAT(//,1X,'*** OPTIMIZATION TERMINATED BECAUSE THE CRITERION',
     &       ' VALUE HAS NOT CHANGED ',/,5X,F5.2,' PERCENT IN',I3,
     &       ' SHUFFLING LOOPS ***')
  820 FORMAT(//,1X,'*** OPTIMIZATION TERMINATED BECAUSE THE POPULATION',
     &       ' HAS CONVERGED INTO ',/,4X,F5.2,' PERCENT OF THE',
     &       ' FEASIBLE SPACE ***')
  830 FORMAT(//,'*** PRINT THE FINAL PARAMETER ESTIMATE AND ITS',
     &       ' CRITERION VALUE ***')
      END
C
C
C
C====================================================================
      SUBROUTINE CCE(NOPT,NPS,S,SF,BL,BU,XNSTD,ICALL,MAXN,ISEED)
C
C  该算法从子复形生成新点
C
C  子复形变量
      PARAMETER (C1=0.8,C2=0.4)
      DIMENSION S(50,16),SF(50),BU(16),BL(16),XNSTD(16)
C
C  局部变量列表
C    SB(.) = 单纯形的最佳点
C    SW(.) = 单纯形的最坏点WO(WORST POINT,简称WO)
C    W2(.) = 单纯形的第二最坏点
C    FW = 最坏点的函数值
C    CE(.) = 单纯形排除最坏点(WO)的质心
C    SNEW(.) = 从单纯形生成的新点
C    IVIOL = 指示是否违反约束的标志
C          = 1 , YES
C          = 0 , NO
C
      DIMENSION SW(16),SB(16),CE(16),SNEW(16)
C
C  代码可读性变量的等价性
      N = NPS
      M = NOPT
      ALPHA = 1.0
      BETA = 0.5
C
C  确定子复形S的最坏点WO
C  计算剩余点的质心CE(CENTROID,简称CE)
C  计算步长,最坏点WO和质心CE之间的向量
C  确定最坏的函数值FW(The worst function value,简称FW)
      DO J = 1, M
        SB(J) = S(1,J)
        SW(J) = S(N,J)
        CE(J) = 0.0
        DO I = 1, N-1
          CE(J) = CE(J) + S(I,J)
        END DO
        CE(J) = CE(J)/DBLE(N-1)
      END DO
      FW = SF(N)
C
C  计算新点SNEW
C
C  首先尝试反射步骤
      DO J = 1, M
        SNEW(J) = CE(J) + ALPHA * (CE(J) - SW(J))
      END DO
C
C  检查是否SNEW满足所有约束
      CALL CHKCST(NOPT,SNEW,BL,BU,IBOUND)
C
C
C  SNEW在界外,
C  按正态分布在可行区域内随机选择一个点,
C  子复形的最佳点作为种群的均值
C  标准差作为STD
      IF (IBOUND .GE. 1) CALL GETPNT(NOPT,2,ISEED,SNEW,BL,BU,XNSTD,SB)
C
C
C  计算SNEW点的函数值FNEW
      FNEW = FUNCTN(NOPT,SNEW)
      ICALL = ICALL + 1
C
C  将FNEW与最差函数值FW进行比较
C
C  FNEW小于FW,接受新点SNEW并返回
      IF (FNEW .LE. FW) GO TO 2000
      IF (ICALL .GE. MAXN) GO TO 3000
C
C
C  FNEW大于FW,所以尝试收缩步骤
      DO J = 1, M
        SNEW(J) = CE(J) - BETA * (CE(J) - SW(J))
      END DO
C
C  计算收缩点的函数值FNEW
      FNEW = FUNCTN(NOPT,SNEW)
      ICALL = ICALL + 1
C
C  将FNEW与最差值FW进行比较
C  如果FNEW小于或等于FW,则接受该点并返回
      IF (FNEW .LE. FW) GO TO 2000
      IF (ICALL .GE. MAXN) GO TO 3000
C
C
C  如果反射和收缩都失败,
C  则根据正态分布选择另一个点,
C  子复形的最佳点作为种群的平均值并且标准偏差作为STD
 1000 CALL GETPNT(NOPT,2,ISEED,SNEW,BL,BU,XNSTD,SB)
C
C  计算随机点的函数值
      FNEW = FUNCTN(NOPT,SNEW)
      ICALL = ICALL + 1
C
C
C  用新点替换最坏点
 2000 CONTINUE
      DO J = 1, M
        S(N,J) = SNEW(J)
      END DO
      SF(N) = FNEW
 3000 CONTINUE
C
C  子程序CCE结束
      RETURN
      END
C
C
C
C===================================================================
      SUBROUTINE GETPNT(NOPT,IDIST,ISEED,X,BL,BU,STD,XI)
C
C     该子程序在可行区域内生成一个新点
C
C     X(.) = 新点
C     XI(.) = 焦点
C     BL(.) = 下限
C     BU(.) = 上限
C     STD(.) = 概率分布的标准差
C     IDIST = 概率标志
C           = 1 - 均匀分布
C           = 2 - 高斯分布即正态分布
C
      DIMENSION X(16),BL(16),BU(16),STD(16),XI(16)
C
    1 DO J=1, NOPT
    2   IF (IDIST .EQ. 1) RAND = RAN1(ISEED)
        IF (IDIST .EQ. 2) RAND = GASDEV(ISEED)
        X(J) = XI(J) + STD(J) * RAND * (BU(J) - BL(J))
C
C     检查显式约束
C        
        CALL CHKCST(1,X(J),BL(J),BU(J),IBOUND)
        IF (IBOUND .GE. 1) GO TO 2
      END DO
C
C     检查隐式约束
C      
      CALL CHKCST(NOPT,X,BL,BU,IBOUND)
      IF (IBOUND .GE. 1) GO TO 1
C
      RETURN
      END
C
C
C
C===================================================================
      SUBROUTINE PARSTT(NPT,NOPT,X,XNSTD,BOUND,GNRNG,IPCNVG)      
C
C  参数收敛的检查子程序
      DIMENSION X(2000,16),XMAX(16),XMIN(16)
      DIMENSION XMEAN(16),XNSTD(16),BOUND(16)
      PARAMETER (DELTA = 1.0D-20,PEPS=1.0D-3)
C
C  计算参数值的最大值、最小值和标准差
      GSUM = 0.D0
      DO K = 1, NOPT
        XMAX(K) = -1.0D+20
        XMIN(K) = 1.0D+20
        XSUM1 = 0.D0
        XSUM2 = 0.D0
        DO I = 1, NPT
          XMAX(K) = AMAX1(X(I,K), XMAX(K))
          XMIN(K) = AMIN1(X(I,K), XMIN(K))
          XSUM1 = XSUM1 + X(I,K)
          XSUM2 = XSUM2 + X(I,K)*X(I,K)
        END DO
        XMEAN(K) = XSUM1 / NPT
        XNSTD(K) = (XSUM2 / NPT - XMEAN(K)*XMEAN(K))
        IF (XNSTD(K) .LE. DELTA) XNSTD(K) = DELTA
        XNSTD(K) = SQRT(XNSTD(K))
        XNSTD(K) = XNSTD(K) / BOUND(K)
        GSUM = GSUM + LOG( DELTA + (XMAX(K)-XMIN(K))/BOUND(K) )
      END DO
      GNRNG = EXP(GSUM/NOPT)
C
C  检查参数的标准化标准差是否 <= EPS
      IPCNVG = 0
      IF (GNRNG .LE. PEPS) THEN
        IPCNVG = 1
      END IF
C
C  子程序PARSTT结束
      RETURN
      END
C
C
C
C====================================================================
      SUBROUTINE COMP(N,NPT,NGS1,NGS2,NPG,A,AF,B,BF)      
C
C
C  此子程序将输入矩阵 A(N,NGS2*NPG) 减少到矩阵 B(N,NGS1*NPG) 
C  并将向量 AF(NGS2*NPG) 减少到向量 BF(NGS1*NPG)
      DIMENSION A(2000,16),AF(2000),B(2000,16),BF(2000)
      DO IGS=1, NGS1
        DO IPG=1, NPG
          K1=(IPG-1)*NGS2 + IGS
          K2=(IPG-1)*NGS1 + IGS
          DO I=1, N
            B(K2,I) = A(K1,I)
          END DO
          BF(K2) = AF(K1)
        END DO
      END DO
C
      DO J=1, NPT
        DO I=1, N
          A(J,I) = B(J,I)
        END DO
        AF(J) = BF(J)
      END DO
C
C  子程序COMP结束
      RETURN
      END
C
C
C
C===================================================================
      SUBROUTINE SORT(N,M,RB,RA)      
C
C
C  改编自“数字食谱”("NUMERICAL RECIPES")的排序子程序
C  由 W.H. PRESS等人,PP. 233-234
C
C  变量列表
C     RA(.) = 要排序的数组
C     RB(.,.) = 对应于 RA(.) 重排的阵列排序
C     WK(.,.), IWK(.) = 局部变量
C
      DIMENSION RA(2000),RB(2000,16),WK(2000,16),IWK(2000)
C
      CALL INDEXX(N, RA, IWK)
      DO 11 I = 1, N
      WK(I,1) = RA(I)
   11 CONTINUE
      DO 12 I = 1, N
      RA(I) = WK(IWK(I),1)
   12 CONTINUE
      DO 14 J = 1, M
      DO 13 I = 1, N
      WK(I,J) = RB(I,J)
   13 CONTINUE
   14 CONTINUE
      DO 16 J = 1, M
      DO 15 I = 1, N
      RB(I,J) = WK(IWK(I),J)
   15 CONTINUE
   16 CONTINUE
C
C  子程序SORT结束
      RETURN
      END
C
C
C===========================================================
      SUBROUTINE SORT1(N,RA)      
C
C
C  改编自“数字食谱”("NUMERICAL RECIPES")的排序子程序
C  由 W.H. PRESS等人,PP. 231
C
C  变量列表
C     RA(.) = 要排序的整数数组
C
      DIMENSION RA(N)
C
      INTEGER RA, RRA
C
      L = (N / 2) + 1
      IR = N
   10 CONTINUE
      IF (L .GT. 1) THEN
      L = L - 1
      RRA = RA(L)
      ELSE
      RRA = RA(IR)
      RA(IR) = RA(1)
      IR = IR - 1
      IF (IR .EQ. 1) THEN
      RA(1) = RRA
      RETURN
      END IF
      END IF
      I = L
      J = L + L
   20 IF (J .LE. IR) THEN
      IF (J .LT. IR) THEN
      IF (RA(J) .LT. RA(J + 1)) J = J + 1
      END IF
      IF (RRA .LT. RA(J)) THEN
      RA(I) = RA(J)
      I = J
      J = J + J
      ELSE
      J = IR + 1
      END IF
      GOTO 20
      END IF
      RA(I) = RRA
      GOTO 10
C
C  子程序SORT1结束
      END
C
C
C
C=======================================================
      SUBROUTINE INDEXX(N, ARRIN, INDX)      
C
C
C  该子程序来自W.H. PRESS等人的“数字食谱”("NUMERICAL RECIPES")。
      DIMENSION ARRIN(N), INDX(N)
C
      DO 11 J = 1, N
      INDX(J) = J
   11 CONTINUE
      L = (N / 2) + 1
      IR = N
   10 CONTINUE
      IF (L .GT. 1) THEN
      L = L - 1
      INDXT = INDX(L)
      Q = ARRIN(INDXT)
      ELSE
      INDXT = INDX(IR)
      Q = ARRIN(INDXT)
      INDX(IR) = INDX(1)
      IR = IR - 1
      IF (IR .EQ. 1) THEN
      INDX(1) = INDXT
      RETURN
      END IF
      END IF
      I = L
      J = L + L
   20 IF (J .LE. IR) THEN
      IF (J .LT. IR) THEN
      IF (ARRIN(INDX(J)) .LT. ARRIN(INDX(J + 1))) J = J + 1
      END IF
      IF (Q .LT. ARRIN(INDX(J))) THEN
      INDX(I) = INDX(J)
      I = J
      J = J + J
      ELSE
      J = IR + 1
      END IF
      GOTO 20
      END IF
      INDX(I) = INDXT
      GOTO 10
C
C  子程序SORT1结束
      END
C
C
C
C==============================================================
      REAL FUNCTION RAN1(IDUM)
C
C
C  该子程序来自W.H. PRESS等人的“数字食谱”。
      DIMENSION R(97)
      PARAMETER (M1 = 259200, IA1 = 7141, IC1 = 54773, RM1 =
     &3.8580247E-6)
      PARAMETER (M2 = 134456, IA2 = 8121, IC2 = 28411, RM2 =
     &7.4373773E-6)
      PARAMETER (M3 = 243000, IA3 = 4561, IC3 = 51349)
      SAVE
      DATA IFF / 0 /
      IF ((IDUM .LT. 0) .OR. (IFF .EQ. 0)) THEN
      IFF = 1
      IX1 = MOD(IC1 - IDUM,M1)
      IX1 = MOD((IA1 * IX1) + IC1,M1)
      IX2 = MOD(IX1,M2)
      IX1 = MOD((IA1 * IX1) + IC1,M1)
      IX3 = MOD(IX1,M3)
      DO 11 J = 1, 97
      IX1 = MOD((IA1 * IX1) + IC1,M1)
      IX2 = MOD((IA2 * IX2) + IC2,M2)
      R(J) = (DBLE(IX1) + (DBLE(IX2) * RM2)) * RM1
   11 CONTINUE
      IDUM = 1
      END IF
      IX1 = MOD((IA1 * IX1) + IC1,M1)
      IX2 = MOD((IA2 * IX2) + IC2,M2)
      IX3 = MOD((IA3 * IX3) + IC3,M3)
      J = 1 + ((97 * IX3) / M3)
      IF ((J .GT. 97) .OR. (J .LT. 1)) PAUSE
      RAN1 = R(J)
      R(J) = (DBLE(IX1) + (DBLE(IX2) * RM2)) * RM1
C
C  子程序RAN1结束
      RETURN
      END
C
C
C
C===============================================================
      FUNCTION GASDEV(IDUM)
C
C
C  该子程序来自W.H. PRESS等人的“数字食谱”。
      COMMON /GASBLK/ ISET
      DATA ISET / 0 /
      IF (ISET .EQ. 0) THEN
    1 V1 = (2. * RAN1(IDUM)) - 1.
      V2 = (2. * RAN1(IDUM)) - 1.
      R = (V1 ** 2) + (V2 ** 2)
      IF (R .GE. 1.) GOTO 1
      FAC = SQRT(- ((2. * LOG(R)) / R))
      GSET = V1 * FAC
      GASDEV = V2 * FAC
      ISET = 1
      ELSE
      GASDEV = GSET
      ISET = 0
      END IF
C
C  子程序GASDEV结束
      RETURN
      END



scein.for

      SUBROUTINE SCEIN(NOPT,MAXN,KSTOP,PCENTO,ISEED,
     &                 NGS,NPG,NPS,NSPL,MINGS,INIFLG,IPRINT)
C
C
C   此子程序读取并打印用于全局优化的
C   洗牌复形演化方法的输入变量
C     ——版本2.1
C
C   作者:段青云 - 亚利桑那大学,1992年4月
C
C
      CHARACTER*10 PCNTRL,DEFLT,USRSP
      CHARACTER*4 REDUC,INITL,YSFLG,NOFLG
      COMMON/IOPARS/ICNTRL,IOUT,IDAT,IWBAL,ISCE,IPE,IPC,IDET
C
      DATA DEFLT/' DEFAULT  '/
      DATA USRSP/'USER SPEC.'/
      DATA YSFLG/'YES '/
      DATA NOFLG/'NO  '/
C
      IERROR = 0
      IWARN = 0
      WRITE(ISCE,700)
  700 FORMAT(10X,'SHUFFLED COMPLEX EVOLUTION GLOBAL OPTIMIZATION',
     &       /,10X,46(1H=))
C
C
C  读入SCE控制参数
      IDEFLT = 0
      READ (ICNTRL,*)
      READ (ICNTRL,800) MAXN,KSTOP,PCENTO,NGS,ISEED,IDEFLT
  800 FORMAT(2I5,F5.2,3I5)
      IF (ISEED .EQ. 0) ISEED = 1969
C
C
C  如果IDEFLT等于1,读入SCE控制参数
      IF (IDEFLT .EQ. 1) THEN
        READ(ICNTRL,810) NPG,NPS,NSPL,MINGS,INIFLG,IPRINT
  810   FORMAT(6I5)
        PCNTRL = USRSP
        IF (NPG .EQ. 0) NPG = 2*NOPT + 1
        IF (NPS .EQ. 0) NPS = NOPT + 1
        IF (NSPL .EQ. 0) NSPL = NPG
        IF (MINGS .EQ. 0) MINGS = NGS
      ELSE
        READ(ICNTRL,*)
        PCNTRL = DEFLT
      END IF
C
C
C  如果IDEFLT等于0,
C  则将SCE控制参数设置为默认值
      IF (IDEFLT .EQ. 0) THEN
        NPG = 2*NOPT + 1
        NPS = NOPT + 1
        NSPL = NPG
        MINGS = NGS
        INIFLG = 0
        IPRINT = 0
      END IF
C
C
C  检查SCE控制参数是否有效
      IF (NGS .LT. 1 .OR. NGS .GE. 1320) THEN
        WRITE(ISCE,900) NGS
  900   FORMAT(//,1X,'**ERROR** NUMBER OF COMPLEXES IN INITIAL ',
     *         ' POPULATION ',I5,' IS NOT A VALID CHOICE')
        IERROR = IERROR + 1
      END IF
C
      IF (KSTOP .LT. 0 .OR. KSTOP .GE. 10) THEN
        WRITE(ISCE,901) KSTOP
  901   FORMAT(//,1X,'**WARNING** THE NUMBER OF SHUFFLING LOOPS IN',
     *  ' WHICH THE CRITERION VALUE MUST CHANGE ',/,13X,'SHOULD BE',
     *  ' GREATER THAN 0 AND LESS THAN 10.  ','KSTOP = ',I2,
     *  ' WAS SPECIFIED.'/,13X,'BUT KSTOP = 5 WILL BE USED INSTEAD.')
        IWARN = IWARN + 1
        KSTOP=5
      END IF
C
      IF (MINGS .LT. 1 .OR. MINGS .GT. NGS) THEN
        WRITE(ISCE,902) MINGS
  902   FORMAT(//,1X,'**WARNING** THE MINIMUM NUMBER OF COMPLEXES ',
     *         I2,' IS NOT A VALID CHOICE. SET IT TO DEFAULT')
        IWARN = IWARN + 1
        MINGS = NGS
      END IF
C
      IF (NPG .LT. 2 .OR. NPG .GT. 1320/MAX(NGS,1)) THEN
        WRITE(ISCE,903) NPG
  903   FORMAT(//,1X,'**WARNING** THE NUMBER OF POINTS IN A COMPLEX ',
     *         I4,' IS NOT A VALID CHOICE, SET IT TO DEFAULT')
        IWARN = IWARN + 1
        NPG = 2*NOPT+1
      END IF
C
      IF (NPS.LT.2 .OR. NPS.GT.NPG .OR. NPS.GT.50) THEN
        WRITE(ISCE,904) NPS
  904   FORMAT(//,1X,'**WARNING** THE NUMBER OF POINTS IN A SUB-',
     *  'COMPLEX ',I4,' IS NOT A VALID CHOICE, SET IT TO DEFAULT')
        IWARN = IWARN + 1
        NPS = NOPT + 1
      END IF
C
      IF (NSPL .LT. 1) THEN
        WRITE(ISCE,905) NSPL
  905   FORMAT(//,1X,'**WARNING** THE NUMBER OF EVOLUTION STEPS ',
     *         'TAKEN IN EACH COMPLEX BEFORE SHUFFLING ',I4,/,13X,
     *         'IS NOT A VALID CHOICE, SET IT TO DEFAULT')
        IWARN = IWARN + 1
        NSPL = NPG
      END IF
C
C  计算初始种群中的总点数
      NPT = NGS * NPG
C
      IF (NPT .GT. 1320) THEN
        WRITE(ISCE,906) NPT
  906   FORMAT(//,1X,'**WARNING** THE NUMBER OF POINTS IN INITIAL ',
     *         'POPULATION ',I5,' EXCEED THE POPULATION LIMIT,',/,13X,
     *         'SET NGS TO 2, AND NPG, NPS AND NSPL TO DEFAULTS')
        IWARN = IWARN + 1
        NGS = 2
        NPG = 2*NOPT + 1
        NPS = NOPT + 1
        NSPL = NPG
      END IF
C
C  打印错误和警告消息的总数
      IF (IERROR .GE. 1) WRITE(ISCE,907) IERROR
  907 FORMAT(//,1X,'*** TOTAL NUMBER OF ERROR MESSAGES IS ',I2)
C
      IF (IWARN .GE. 1) WRITE(ISCE,908) IWARN
  908 FORMAT(//,1X,'*** TOTAL NUMBER OF WARNING MESSAGES IS ',I2)
C
      IF (MINGS .LT. NGS) THEN
        REDUC = YSFLG
      ELSE
        REDUC = NOFLG
      END IF
C
      IF (INIFLG .NE. 0) THEN
        INITL = YSFLG
      ELSE
        INITL = NOFLG
      END IF
C
C
C  打印洗牌复形演化优化选项
  104 WRITE(ISCE,910)
  910 FORMAT(//,2X,'SCE CONTROL',5X,'MAX TRIALS',5X,
     &'REQUIRED IMPROVEMENT',5X,'RANDOM',/,3X,'PARAMETER',8X,
     &'ALLOWED',6X,'PERCENT',4X,'NO. LOOPS',6X,'SEED',/,
     &2X,11(1H-),5X,10(1H-),5X,7(1H-),4X,9(1H-),5X,6(1H-))
C
      PCENTA=PCENTO*100.
      WRITE(ISCE,912) PCNTRL,MAXN,PCENTA,KSTOP,ISEED
  912 FORMAT(3X,A10,7X,I5,10X,F3.1,9X,I2,9X,I5)
      WRITE(ISCE,914) NGS,NPG,NPT,NPS,NSPL
  914 FORMAT(//,18X,'SCE ALGORITHM CONTROL PARAMETERS',/,18X,32(1H=),
     &//,2X,'NUMBER OF',5X,'POINTS PER',5X,'POINTS IN',6X,'POINTS PER',
     &4X,'EVOL. STEPS',/,2X,'COMPLEXES',6X,'COMPLEX',6X,'INI. POPUL.',
     &5X,'SUB-COMPLX',4X,'PER COMPLEX',/,2X,9(1H-),5X,10(1H-),4X,
     &11(1H-),5X,10(1H-),4X,11(1H-),5X,/,2X,5(I5,10X))
      WRITE(ISCE,915) REDUC,MINGS,INITL
  915 FORMAT(//,15X,'COMPLX NO.',5X,'MIN COMPLEX',5X,'INI. POINT',/,
     &15X,'REDUCTION',6X,'NO. ALLOWED',6X,'INCLUDED',/,
     &15X,10(1H-),5X,11(1H-),5X,10(1H-),/,18X,A4,6X,I8,13X,A4)
      IF (IERROR .GE. 1) THEN
      WRITE(ISCE,922)
  922 FORMAT(//,'*** THE OPTIMIZATION SEARCH IS NOT CONDUCTED BECAUSE',
     &       ' OF INPUT DATA ERROR ***')
      STOP
      END IF
C
C  子程序SCEIN结束
      RETURN
      END


参考代码

以下代码仅供参考,都无法成功运行。

Python版本

#-------------------------------------------------------------------------------
# Name:        SCE_Python_shared version
# This is the implementation for the SCE algorithm,
# written by Q.Duan, 9/2004 - converted to python by Van Hoey S.2011
#-------------------------------------------------------------------------------
## Refer to paper:
##  'EFFECTIVE AND EFFICIENT GLOBAL OPTIMIZATION FOR CONCEPTUAL
##  RAINFALL-RUNOFF MODELS' BY DUAN, Q., S. SOROOSHIAN, AND V.K. GUPTA,
##  WATER RESOURCES RESEARCH, VOL 28(4), PP.1015-1031, 1992.

import random
import numpy as np
from ..test_functions import functn
import matplotlib.pyplot as plt
import pickle
import warnings
warnings.filterwarnings("ignore")

################################################################################
##  Sampling called from SCE
################################################################################

def SampleInputMatrix(nrows,npars,bu,bl,iseed,distname='randomUniform'):
    '''
    Create input parameter matrix for nrows simulations,
    for npars with bounds ub and lb (np.array from same size)
    distname gives the initial sampling distribution (currently one for all parameters)

    returns np.array
    '''
    np.random.seed(iseed)
    x = np.zeros((nrows,npars))
    bound = bu - bl
    for i in range(nrows):
        x[i,:] = bl + np.random.rand(1,npars)*bound
    return x

def cceua(s,sf,bl,bu,icall,iseed,file=None):
    #  This is the subroutine for generating a new point in a simplex
    nps,nopt=s.shape
    n = nps
    m = nopt
    alpha = 1.0
    beta = 0.5

    # Assign the best and worst points:
    sb=s[0,:]
    fb=sf[0]
    sw=s[-1,:]
    fw=sf[-1]

    if file != None:
        model = open(file, 'rb')
        functn = pickle.load(model)  
        model.close()
    
    # Compute the centroid of the simplex excluding the worst point:
    ce= np.mean(s[:-1,:],axis=0)

    # Attempt a reflection point
    snew = SampleInputMatrix(1,nopt,bu,bl,iseed,distname='randomUniform')
    snew[0] = ce + alpha*(ce-sw)

    # Check if is outside the bounds:
    ibound=0
    s1=snew[0]-bl
    idx=(s1<0).nonzero()
    if idx[0].size <> 0:
        ibound=1

    s1=bu-snew[0]
    idx=(s1<0).nonzero()
    if idx[0].size <> 0:
        ibound=2

    if ibound >= 1:
        snew = SampleInputMatrix(1,nopt,bu,bl,iseed,distname='randomUniform')

    global functn
    fnew = functn.predict(snew)[0]
    icall += 1

    # Reflection failed; now attempt a contraction point:
    if fnew > fw:
        snew[0] = sw + beta * (ce-sw)
        fnew = functn.predict(snew)[0]
        icall += 1

    # Both reflection and contraction have failed, attempt a random point;
        if fnew > fw:
            snew = SampleInputMatrix(1,nopt,bu,bl,iseed,distname='randomUniform')
            fnew = functn.predict(snew)[0]
            icall += 1

    # END OF CCE
    return snew[0],fnew,icall


def sceua(bl,bu,pf,ngs,file=None,plot=True):
# This is the subroutine implementing the SCE algorithm,
# written by Q.Duan, 9/2004 - converted to python by Van Hoey S.2011

    # Initialize SCE parameters:
    nopt=len(bl)
    npg=2*nopt+1
    nps=nopt+1
    nspl=npg
    npt=npg*ngs
    bound=bu-bl
    maxn=3000
    kstop=10
    pcento=0.1
    peps=0.001
    iseed=0
    iniflg=0
    ngs=2

    if file != None:
        model = open(file, 'rb')
        functn = pickle.load(model)
        model.close()
    
    # Create an initial population to fill array x(npt,nopt):
    x = SampleInputMatrix(npt,nopt,bu,bl,iseed,distname='randomUniform')
    if iniflg==1:
        x[0,:]=x0

    nloop=0
    icall=0
    xf=np.zeros(npt)
    global functn
    xf=functn.predict(x)
    for i in range(npt):
        icall += 1
    f0=xf[0]

    # Sort the population in order of increasing function values;
    idx = np.argsort(xf)
    xf = np.sort(xf)
    x=x[idx,:]

    # Record the best and worst points;
    bestx=x[0,:]
    bestf=xf[0]
    worstx=x[-1,:]
    worstf=xf[-1]

    BESTF=bestf
    BESTX=bestx
    ICALL=icall

    # Compute the standard deviation for each parameter
    xnstd=np.std(x,axis=0)

    # Computes the normalized geometric range of the parameters
    gnrng=np.exp(np.mean(np.log((np.max(x,axis=0)-np.min(x,axis=0))/bound)))

    print 'The Initial Loop: 0'
    print ' BESTF:  %f ' %bestf
    print ' BESTX:  '
    print bestx
    print ' WORSTF:  %f ' %worstf
    print ' WORSTX: '
    print worstx
    print '     '

    # Check for convergency;
    if icall >= maxn:
        print '*** OPTIMIZATION SEARCH TERMINATED BECAUSE THE LIMIT'
        print 'ON THE MAXIMUM NUMBER OF TRIALS '
        print maxn
        print 'HAS BEEN EXCEEDED.  SEARCH WAS STOPPED AT TRIAL NUMBER:'
        print icall
        print 'OF THE INITIAL LOOP!'

    if gnrng < peps:
        print 'THE POPULATION HAS CONVERGED TO A PRESPECIFIED SMALL PARAMETER SPACE'

    # Begin evolution loops:
    nloop = 0
    criter=[]
    criter_change=1e+5

    while icall<maxn and gnrng>peps and criter_change>pcento:
        nloop+=1

        # Loop on complexes (sub-populations);
        for igs in range(ngs):
            # Partition the population into complexes (sub-populations);
            cx=np.zeros((npg,nopt))
            cf=np.zeros((npg))

            k1=np.array(range(npg))
            k2=k1*ngs+igs
            cx[k1,:] = x[k2,:]
            cf[k1] = xf[k2]

            # Evolve sub-population igs for nspl steps:
            for loop in range(nspl):

                # Select simplex by sampling the complex according to a linear
                # probability distribution
                lcs=np.array([0]*nps)
                lcs[0] = 1
                for k3 in range(1,nps):
                    for i in range(1000):
##                        lpos = 1 + int(np.floor(npg+0.5-np.sqrt((npg+0.5)**2 - npg*(npg+1)*random.random())))
                        lpos = int(np.floor(npg+0.5-np.sqrt((npg+0.5)**2 - npg*(npg+1)*random.random())))
##                        idx=find(lcs(1:k3-1)==lpos)
                        idx=(lcs[0:k3]==lpos).nonzero()  #check of element al eens gekozen
                        if idx[0].size == 0:
                            break

                    lcs[k3] = lpos
                lcs.sort()

                # Construct the simplex:
                s = np.zeros((nps,nopt))
                s=cx[lcs,:]
                sf = cf[lcs]

                snew,fnew,icall=cceua(s,sf,bl,bu,icall,iseed,file)

                # Replace the worst point in Simplex with the new point:
                s[-1,:] = snew
                sf[-1] = fnew

                # Replace the simplex into the complex;
                cx[lcs,:] = s
                cf[lcs] = sf

                # Sort the complex;
                idx = np.argsort(cf)
                cf = np.sort(cf)
                cx=cx[idx,:]

            # End of Inner Loop for Competitive Evolution of Simplexes
            #end of Evolve sub-population igs for nspl steps:

            # Replace the complex back into the population;
            x[k2,:] = cx[k1,:]
            xf[k2] = cf[k1]

        # End of Loop on Complex Evolution;

        # Shuffled the complexes;
        idx = np.argsort(xf)
        xf = np.sort(xf)
        x=x[idx,:]

        PX=x
        PF=xf

        # Record the best and worst points;
        bestx=x[0,:]
        bestf=xf[0]
        worstx=x[-1,:]
        worstf=xf[-1]

        BESTX = np.append(BESTX,bestx, axis=0)
        BESTF = np.append(BESTF,bestf)
        ICALL = np.append(ICALL,icall)

        # Compute the standard deviation for each parameter
        xnstd=np.std(x,axis=0)

        # Computes the normalized geometric range of the parameters
        gnrng=np.exp(np.mean(np.log((np.max(x,axis=0)-np.min(x,axis=0))/bound)))

        print 'Evolution Loop: %d  - Trial - %d' %(nloop,icall)
        print ' BESTF:  %f ' %bestf
        print ' BESTX:  '
        print bestx
        print ' WORSTF:  %f ' %worstf
        print ' WORSTX: '
        print worstx
        print '     '

        # Check for convergency;
        if icall >= maxn:
            print '*** OPTIMIZATION SEARCH TERMINATED BECAUSE THE LIMIT'
            print 'ON THE MAXIMUM NUMBER OF TRIALS '
            print maxn
            print 'HAS BEEN EXCEEDED.'

        if gnrng < peps:
            print 'THE POPULATION HAS CONVERGED TO A PRESPECIFIED SMALL PARAMETER SPACE'

        criter=np.append(criter,bestf)

        if nloop >= kstop:
            criter_change= np.abs(criter[nloop-1]-criter[nloop-kstop])*100
            criter_change= criter_change/np.mean(np.abs(criter[nloop-kstop:nloop]))
            if criter_change < pcento:
                print 'THE BEST POINT HAS IMPROVED IN LAST %d LOOPS BY LESS THAN THE THRESHOLD %f' %(kstop,pcento)
                print 'CONVERGENCY HAS ACHIEVED BASED ON OBJECTIVE FUNCTION CRITERIA!!!'

    # End of the Outer Loops
    print 'SEARCH WAS STOPPED AT TRIAL NUMBER: %d' %icall
    print 'NORMALIZED GEOMETRIC RANGE = %f'  %gnrng
    print 'THE BEST POINT HAS IMPROVED IN LAST %d LOOPS BY %f' %(kstop,criter_change)

    #reshape BESTX
    BESTX=BESTX.reshape(BESTX.size/nopt,nopt)

    if plot:
        fig = plt.figure()
        ax1 = plt.subplot(111)
        l1 = ax1.plot(BESTX)
        ax1.legend((l1),(pf['names']), shadow=True)
        # plt.title('Trace of the different parameters')
        plt.xlabel('Evolution Loop')
        plt.ylabel('Normalized Parameters\' value')

        fig = plt.figure()
        ax2 = plt.subplot(111)
        ax2.plot(BESTF)
        plt.title('Trace of model value')
        plt.xlabel('Evolution Loop')
        plt.ylabel('Model value')

        plt.show()

    # END of Subroutine sceua
    return bestx,bestf,BESTX,BESTF,ICALL

MATLAB版本

以下代码仅供参考,都无法成功运行。

%
% Copyright (c) 2015, Mostapha Kalami Heris & Yarpiz (www.yarpiz.com)
% All rights reserved. Please read the "LICENSE" file for license terms.
%
% Project Code: YPEA110
% Project Title: Implementation of Shuffled Complex Evolution (SCE-UA)
% Publisher: Yarpiz (www.yarpiz.com)
% 
% Developer: Mostapha Kalami Heris (Member of Yarpiz Team)
% 
% Cite as:
% Mostapha Kalami Heris, Shuffled Complex Evolution in MATLAB (URL: https://yarpiz.com/80/ypea110-shuffled-complex-evolution), Yarpiz, 2015.
% 
% Contact Info: sm.kalami@gmail.com, info@yarpiz.com
%

clc;
clear;
close all;

%% Problem Definition

% Objective Function
CostFunction = @(x) Sphere(x);

nVar = 10;              % Number of Unknown Variables
VarSize = [1 nVar];     % Unknown Variables Matrix Size

VarMin = -10;           % Lower Bound of Unknown Variables
VarMax = 10;           % Upper Bound of Unknown Variables


%% SCE-UA Parameters

MaxIt = 500;        % Maximum Number of Iterations

nPopComplex = 10;                       % Complex Size
nPopComplex = max(nPopComplex, nVar+1); % Nelder-Mead Standard

nComplex = 5;                   % Number of Complexes
nPop = nComplex*nPopComplex;    % Population Size

I = reshape(1:nPop, nComplex, []);

% CCE Parameters
cce_params.q = max(round(0.5*nPopComplex), 2);   % Number of Parents
cce_params.alpha = 3;   % Number of Offsprings
cce_params.beta = 5;    % Maximum Number of Iterations
cce_params.CostFunction = CostFunction;
cce_params.VarMin = VarMin;
cce_params.VarMax = VarMax;

%% Initialization

% Empty Individual Template
empty_individual.Position = [];
empty_individual.Cost = [];

% Initialize Population Array
pop = repmat(empty_individual, nPop, 1);

% Initialize Population Members
for i = 1:nPop
    pop(i).Position = unifrnd(VarMin, VarMax, VarSize);
    pop(i).Cost = CostFunction(pop(i).Position);
end

% Sort Population
pop = SortPopulation(pop);

% Update Best Solution Ever Found
BestSol = pop(1);

% Initialize Best Costs Record Array
BestCosts = nan(MaxIt, 1);

%% SCE-UA Main Loop

for it = 1:MaxIt
    
    % Initialize Complexes Array
    Complex = cell(nComplex, 1);
    
    % Form Complexes and Run CCE
    for j = 1:nComplex
        % Complex Formation
        Complex{j} = pop(I(j, :));
        
        % Run CCE
        Complex{j} = RunCCE(Complex{j}, cce_params);
        
        % Insert Updated Complex into Population
        pop(I(j, :)) = Complex{j};
    end
    
    % Sort Population
    pop = SortPopulation(pop);
    
    % Update Best Solution Ever Found
    BestSol = pop(1);
    
    % Store Best Cost Ever Found
    BestCosts(it) = BestSol.Cost;
    
    % Show Iteration Information
    disp(['Iteration ' num2str(it) ': Best Cost = ' num2str(BestCosts(it))]);
    
end

%% Results

figure;
%plot(BestCosts, 'LineWidth', 2);
semilogy(BestCosts, 'LineWidth', 2);
xlabel('Iteration');
ylabel('Best Cost');
grid on;

C++版本

以下代码仅供参考,都无法成功运行。
SCEUA.h

/******************************************************************************
File      : SCEUA.h
Author    : L. Shawn Matott - Converted from Origincal SCEUA Fortran code
Copyright : 2009, L. Shawn Matott
The SCE-UA method is a general purpose global optimization
program.  It was originally developed by Dr. Qingyun Duan as part
of his doctoral dissertation work at the Department of Hydrology
and Water Resources, University of Arizona, Tucson, AZ 85721, USA. 
The dissertation is entitled "A Global Optimization Strategy for
Efficient and Effective Calibration of Hydrologic Models".  The
program has since been modified to make it easier for use on
problems of users' interests.  The algorithm has been described
in detail in an article entitled "Effective and Efficient Global
Optimization for Conceptual Rainfall-Runoff Models", Water Resources
Research, Vol 28(4), pp.1015-1031, 1992; and in an article entitled
"A Shuffled Complex Evolution Approach for Effective and Efficient
Global Minimization" by Q. Duan, V.K. Gupta and S. Sorooshian,
Journal of Optimization Theory and its Applications, Vol 76(3), 
pp 501-521, 1993.  A paper entitled "Optimal Use of the SCE-UA Global
Optimization Method for Calibrating Watershed Models", by Q. Duan,
S. Sorooshian, & V.K. Gupta, Journal of Hydrology, Vol.158, 265-284,
1994, discussed how to use the SCE-UA Method in an efficient and 
effective manner.
Input Summary for the SCEUA algorithm (adapted from original Fortran-based
description):
==========================================================================
variable   type     description
MAXN       integer  Maximum number of trials allowed before
                    optimization is terminated.  The purpose of
                    MAXN is to stop an optimization search before
                    too much computer time is expended.  MAXN
                    should be set large enough so that optimization
                    is generally completed before MAXN trials are
                    performed. Recommended value is 10,000 (increase or
                    decrease as necessary).
---> this parameter is called m_Budget within Ostrich
KSTOP      integer  Number of shuffling loops in which the 
                    criterion must improve by the specified
                    percentage or else optimization will be
                    terminated. Recommended value: 5.
---> this parameter is called m_Kstop within Ostrich
PCENTO     double   Percentage by which the criterion value must
                    change in the specified number of shuffling 
                    loops or else optimization is terminated
                    (Use decimal equivalent: Percentage/100).
                    Recommended value: 0.01.
---> this parameter is called m_Pcento within Ostrich
NGS        integer  Number of complexes used for optimization
                    search.  Minimum value is 1.
                    Recommended value is between 2 and 20 depending
                    on the number of parameters to be optimized and
                    on the degree of difficulty of the problem.
---> this parameter is called m_NumComplexes within Ostrich
ISEED      integer  Random seed used in optimization search.  Enter
                    any integer number.  Default value (=1969) is
                    assumed if this field is left blank.
                    Recommended value: any large integer.
---> this parameter is called m_Seed within Ostrich
IDEFLT     integer  Flag for setting the control variables of the
                    SCE-UA algorithm.  Enter false or leave the field
                    blank for default setting.  Enter true for user
                    specified setting.
                    If option true is chosen, user must specify alg. 
                    parameters.
---> this parameter is called m_bUserConfig within Ostrich
NPG        integer  Number of points in each complex.  NPG should
                    be greater than or equal to 2.  The default
                    value is equal to (2 * number of optimized
                    parameters + 1).
---> this parameter is called m_PtsPerComplex within Ostrich
NPS        integer  Number of points in each sub-complex.  NPS
                    should be greater than or equal to 2 and less
                    than NPG.  The default value is equal to 
                    (number of optimized parameters + 1).
---> this parameter is called m_PtsPerSubComplex within Ostrich
NSPL       integer  Number of evolution steps taken by each complex
                    before next shuffling.  Default value is equal
                    to NPG.
---> this parameter is called m_NumEvoSteps within Ostrich
MINGS      integer  Minimum number of complexes required for
                    optimization search, if the number of complexes
                    is allowed to reduce as the optimization search
                    proceeds.  The default value is equal to NGS.
---> this parameter is called m_MinComplexes within Ostrich
INIFLG     bool     Flag on whether to include an initial point in
                    the starting population.  Enter true if the initial 
                    point is to be included.  The default value is equal to false.
---> this parameter is called m_bUseInitPt within Ostrich
IPRINT    integer   Print-out control flag.  Enter '0' to print out
                    the best estimate of the global optimum at the
                    end of each shuffling loop.  Enter '1' to print
                    out every point in the entire sample population
                    at the end of each shuffling loop.  The default
                    value is equal to 0. Enter 2 to ignore this variable
                    and use conventional Ostrich output.
---> this parameter is called m_OutputMode within Ostrich
PARAMS     double * Initial estimates of the parameters to be optimized.
---> this parameter is called m_pParams within Ostrich
LOWER      double * Lower bounds of the parameters to be optimized.
---> this parameter is called m_pLower within Ostrich
UPPER      double * Upper bounds of the parameters to be optimized.
---> this parameter is called m_pUpper within Ostrich
Version History
10-31-09    lsm   Created
******************************************************************************/
#ifndef SCEUA_H
#define SCEUA_H

// parent class
#include "AlgorithmABC.h"

// forward declarations
class ModelABC;
class StatsClass;

/******************************************************************************
class SCEUA
******************************************************************************/
class SCEUA : public AlgorithmABC
{
   public:
      SCEUA(ModelABC * pModel);
      ~SCEUA(void) { DBG_PRINT("SCEUA::DTOR"); Destroy(); }
      void Destroy(void);

      void Optimize(void);
      void Calibrate(void);
      void WriteMetrics(FILE * pFile);
      void WarmStart(void);
      int  GetCurrentIteration(void) { return m_CurIter; }

   private :
	   void InitFromFile(IroncladString pFileName);
      void scemain(void);
      void scein(double * a, double * bl, double * bu, int nopt, int *maxn,
                 int *kstop, double *pcento, int *iseed, int *ngs, int *npg,
                 int *nps, int *nspl, int *mings, int *iniflg, int *iprint);
      void sceua(double * a, double * bl, double * bu, int nopt, int maxn,
                 int kstop, double pcento, int iseed, int ngs, int npg,
                 int nps, int nspl, int mings, int iniflg, int iprint);
      void cce(int nopt, int nps, double ** s, double * sf, double * bl,
               double * bu, double * xnstd, int * icall, double maxn,
               int * iseed);
      void getpnt(int nopt, int idist, int * iseed, double * x, double * bl,
                  double * bu, double * std, double * xi);
      void sort(int n, int m, double ** rb, double * ra);
      void parstt(int npt, int nopt, double ** x, double * xnstd,
                  double * bound, double * gnrng, int * ipcnvg);
      void sort(int n, int * ra);
      void comp(int n, int npt, int ngs1, int ngs2, int npg, 
                double ** a, double * af, double ** b, double * bf);
      void chkcst(int nopt, double * snew, double * bl, 
                  double * bu, int * ibound);

      StatusStruct m_pStatus;
      double m_Best;
      int m_Budget; //MAXN
      int m_Kstop; //KSTOP
      double m_Pcento; //PCENTO
      double m_Peps; //peps
      double m_fSaved;
      int m_NumComplexes; //NGS
      int m_Seed; //ISEED
      int m_UserConfig; //IDEFLT
      int m_PtsPerComplex; //NPG
      int m_PtsPerSubComplex; //NPS
      int m_NumEvoSteps; //NSPL
      int m_MinComplexes; //MINGS
      int m_UseInitPt; //INIFLG
      int m_OutputMode; //IPRINT
      int m_np; //number of parameters
      int m_CurIter;
      double * m_pParams; //PARAMS
      double * m_pLower; //LOWER
      double * m_pUpper; //UPPER
      bool m_bUseInitPt;
      ModelABC * m_pModel;
      StatsClass * m_pStats;
}; /* end class SCEUA */

extern "C" {
void SCEUA_Program(int argc, StringType argv[]);
}

#endif /* SCEUA_H */

SCEUA.cpp

/******************************************************************************
File      : SCEUA.cpp
Author    : L. Shawn Matott - Converted from Origincal S/******************************************************************************
File      : SCEUA.h
Author    : L. Shawn Matott - Converted from Origincal SCEUA Fortran code
Copyright : 2009, L. Shawn Matott
The SCE-UA method is a general purpose global optimization
program.  It was originally developed by Dr. Qingyun Duan as part
of his doctoral dissertation work at the Department of Hydrology
and Water Resources, University of Arizona, Tucson, AZ 85721, USA. 
The dissertation is entitled "A Global Optimization Strategy for
Efficient and Effective Calibration of Hydrologic Models".  The
program has since been modified to make it easier for use on
problems of users' interests.  The algorithm has been described
in detail in an article entitled "Effective and Efficient Global
Optimization for Conceptual Rainfall-Runoff Models", Water Resources
Research, Vol 28(4), pp.1015-1031, 1992; and in an article entitled
"A Shuffled Complex Evolution Approach for Effective and Efficient
Global Minimization" by Q. Duan, V.K. Gupta and S. Sorooshian,
Journal of Optimization Theory and its Applications, Vol 76(3), 
pp 501-521, 1993.  A paper entitled "Optimal Use of the SCE-UA Global
Optimization Method for Calibrating Watershed Models", by Q. Duan,
S. Sorooshian, & V.K. Gupta, Journal of Hydrology, Vol.158, 265-284,
1994, discussed how to use the SCE-UA Method in an efficient and 
effective manner.
Input Summary for the SCEUA algorithm (adapted from original Fortran-based
description):
==========================================================================
variable   type     description
MAXN       integer  Maximum number of trials allowed before
                    optimization is terminated.  The purpose of
                    MAXN is to stop an optimization search before
                    too much computer time is expended.  MAXN
                    should be set large enough so that optimization
                    is generally completed before MAXN trials are
                    performed. Recommended value is 10,000 (increase or
                    decrease as necessary).
---> this parameter is called m_Budget within Ostrich
KSTOP      integer  Number of shuffling loops in which the 
                    criterion must improve by the specified
                    percentage or else optimization will be
                    terminated. Recommended value: 5.
---> this parameter is called m_Kstop within Ostrich
PCENTO     double   Percentage by which the criterion value must
                    change in the specified number of shuffling 
                    loops or else optimization is terminated
                    (Use decimal equivalent: Percentage/100).
                    Recommended value: 0.01.
---> this parameter is called m_Pcento within Ostrich
NGS        integer  Number of complexes used for optimization
                    search.  Minimum value is 1.
                    Recommended value is between 2 and 20 depending
                    on the number of parameters to be optimized and
                    on the degree of difficulty of the problem.
---> this parameter is called m_NumComplexes within Ostrich
ISEED      integer  Random seed used in optimization search.  Enter
                    any integer number.  Default value (=1969) is
                    assumed if this field is left blank.
                    Recommended value: any large integer.
---> this parameter is called m_Seed within Ostrich
IDEFLT     integer  Flag for setting the control variables of the
                    SCE-UA algorithm.  Enter false or leave the field
                    blank for default setting.  Enter true for user
                    specified setting.
                    If option true is chosen, user must specify alg. 
                    parameters.
---> this parameter is called m_bUserConfig within Ostrich
NPG        integer  Number of points in each complex.  NPG should
                    be greater than or equal to 2.  The default
                    value is equal to (2 * number of optimized
                    parameters + 1).
---> this parameter is called m_PtsPerComplex within Ostrich
NPS        integer  Number of points in each sub-complex.  NPS
                    should be greater than or equal to 2 and less
                    than NPG.  The default value is equal to 
                    (number of optimized parameters + 1).
---> this parameter is called m_PtsPerSubComplex within Ostrich
NSPL       integer  Number of evolution steps taken by each complex
                    before next shuffling.  Default value is equal
                    to NPG.
---> this parameter is called m_NumEvoSteps within Ostrich
MINGS      integer  Minimum number of complexes required for
                    optimization search, if the number of complexes
                    is allowed to reduce as the optimization search
                    proceeds.  The default value is equal to NGS.
---> this parameter is called m_MinComplexes within Ostrich
INIFLG     bool     Flag on whether to include an initial point in
                    the starting population.  Enter true if the initial 
                    point is to be included.  The default value is equal to false.
---> this parameter is called m_bUseInitPt within Ostrich
IPRINT    integer   Print-out control flag.  Enter '0' to print out
                    the best estimate of the global optimum at the
                    end of each shuffling loop.  Enter '1' to print
                    out every point in the entire sample population
                    at the end of each shuffling loop.  The default
                    value is equal to 0. Enter 2 to ignore this variable
                    and use conventional Ostrich output.
---> this parameter is called m_OutputMode within Ostrich
PARAMS     double * Initial estimates of the parameters to be optimized.
---> this parameter is called m_pParams within Ostrich
LOWER      double * Lower bounds of the parameters to be optimized.
---> this parameter is called m_pLower within Ostrich
UPPER      double * Upper bounds of the parameters to be optimized.
---> this parameter is called m_pUpper within Ostrich
Version History
10-31-09    lsm   Created
******************************************************************************/
#ifndef SCEUA_H
#define SCEUA_H

// parent class
#include "AlgorithmABC.h"

// forward declarations
class ModelABC;
class StatsClass;

/******************************************************************************
class SCEUA
******************************************************************************/
class SCEUA : public AlgorithmABC
{
   public:
      SCEUA(ModelABC * pModel);
      ~SCEUA(void) { DBG_PRINT("SCEUA::DTOR"); Destroy(); }
      void Destroy(void);

      void Optimize(void);
      void Calibrate(void);
      void WriteMetrics(FILE * pFile);
      void WarmStart(void);
      int  GetCurrentIteration(void) { return m_CurIter; }

   private :
	   void InitFromFile(IroncladString pFileName);
      void scemain(void);
      void scein(double * a, double * bl, double * bu, int nopt, int *maxn,
                 int *kstop, double *pcento, int *iseed, int *ngs, int *npg,
                 int *nps, int *nspl, int *mings, int *iniflg, int *iprint);
      void sceua(double * a, double * bl, double * bu, int nopt, int maxn,
                 int kstop, double pcento, int iseed, int ngs, int npg,
                 int nps, int nspl, int mings, int iniflg, int iprint);
      void cce(int nopt, int nps, double ** s, double * sf, double * bl,
               double * bu, double * xnstd, int * icall, double maxn,
               int * iseed);
      void getpnt(int nopt, int idist, int * iseed, double * x, double * bl,
                  double * bu, double * std, double * xi);
      void sort(int n, int m, double ** rb, double * ra);
      void parstt(int npt, int nopt, double ** x, double * xnstd,
                  double * bound, double * gnrng, int * ipcnvg);
      void sort(int n, int * ra);
      void comp(int n, int npt, int ngs1, int ngs2, int npg, 
                double ** a, double * af, double ** b, double * bf);
      void chkcst(int nopt, double * snew, double * bl, 
                  double * bu, int * ibound);

      StatusStruct m_pStatus;
      double m_Best;
      int m_Budget; //MAXN
      int m_Kstop; //KSTOP
      double m_Pcento; //PCENTO
      double m_Peps; //peps
      double m_fSaved;
      int m_NumComplexes; //NGS
      int m_Seed; //ISEED
      int m_UserConfig; //IDEFLT
      int m_PtsPerComplex; //NPG
      int m_PtsPerSubComplex; //NPS
      int m_NumEvoSteps; //NSPL
      int m_MinComplexes; //MINGS
      int m_UseInitPt; //INIFLG
      int m_OutputMode; //IPRINT
      int m_np; //number of parameters
      int m_CurIter;
      double * m_pParams; //PARAMS
      double * m_pLower; //LOWER
      double * m_pUpper; //UPPER
      bool m_bUseInitPt;
      ModelABC * m_pModel;
      StatsClass * m_pStats;
}; /* end class SCEUA */

extern "C" {
void SCEUA_Program(int argc, StringType argv[]);
}

#endif /* SCEUA_H */CEUA Fortran code
Copyright : 2009, L. Shawn Matott
The SCE-UA method is a general purpose global optimization
program - Shuffled Complex Evolution.  It was originally developed 
by Dr. Qingyun Duan as part of his doctoral dissertation work at
University of Arizona, Tucson, AZ 85721, USA. 
The dissertation is entitled "A Global Optimization Strategy for
Efficient and Effective Calibration of Hydrologic Models".  The
program has since been modified to make it easier for use on
problems of users' interests.  
The algorithm has been described in detail in an article entitled :
"Effective and Efficient Global Optimization for Conceptual Rainfall-Runoff Models", 
Water Resources Research, Vol 28(4), pp.1015-1031, 1992
And in an article entitled:
"A Shuffled Complex Evolution Approach for Effective and Efficient Global Minimization",
 by Q. Duan, V.K. Gupta and S. Sorooshian, Journal of Optimization Theory and its 
Applications, Vol 76(3), pp 501-521, 1993.  
A paper entitled "Optimal Use of the SCE-UA Global Optimization Method for Calibrating Watershed Models", 
by Q. Duan, S. Sorooshian, & V.K. Gupta, Journal of Hydrology, Vol.158, 265-284, 1994, 
discussed how to use the SCE-UA Method in an efficient and  effective manner.
Input Summary for the SCEUA algorithm (adapted from original Fortran-based
description):
==========================================================================
variable   type     description
MAXN       integer  Maximum number of trials allowed before
                    optimization is terminated.  The purpose of
                    MAXN is to stop an optimization search before
                    too much computer time is expended.  MAXN
                    should be set large enough so that optimization
                    is generally completed before MAXN trials are
                    performed. Recommended value is 10,000 (increase or
                    decrease as necessary).
---> this parameter is called m_Budget within Ostrich
KSTOP      integer  Number of shuffling loops in which the 
                    criterion must improve by the specified
                    percentage or else optimization will be
                    terminated. Recommended value: 5.
---> this parameter is called m_Kstop within Ostrich
PCENTO     double   Percentage by which the criterion value must
                    change in the specified number of shuffling 
                    loops or else optimization is terminated
                    (Use decimal equivalent: Percentage/100).
                    Recommended value: 0.01.
---> this parameter is called m_Pcento within Ostrich
NGS        integer  Number of complexes used for optimization
                    search.  Minimum value is 1.
                    Recommended value is between 2 and 20 depending
                    on the number of parameters to be optimized and
                    on the degree of difficulty of the problem.
---> this parameter is called m_NumComplexes within Ostrich
ISEED      integer  Random seed used in optimization search.  Enter
                    any integer number.  Default value (=1969) is
                    assumed if this field is left blank.
                    Recommended value: any large integer.
---> this parameter is called m_Seed within Ostrich
IDEFLT     integer  Flag for setting the control variables of the
                    SCE-UA algorithm.  Enter false or leave the field
                    blank for default setting.  Enter true for user
                    specified setting.
                    If option true is chosen, user must specify alg. 
                    parameters.
---> this parameter is called m_bUserConfig within Ostrich
NPG        integer  Number of points in each complex.  NPG should
                    be greater than or equal to 2.  The default
                    value is equal to (2 * number of optimized
                    parameters + 1).
---> this parameter is called m_PtsPerComplex within Ostrich
NPS        integer  Number of points in each sub-complex.  NPS
                    should be greater than or equal to 2 and less
                    than NPG.  The default value is equal to 
                    (number of optimized parameters + 1).
---> this parameter is called m_PtsPerSubComplex within Ostrich
NSPL       integer  Number of evolution steps taken by each complex
                    before next shuffling.  Default value is equal
                    to NPG.
---> this parameter is called m_NumEvoSteps within Ostrich
MINGS      integer  Minimum number of complexes required for
                    optimization search, if the number of complexes
                    is allowed to reduce as the optimization search
                    proceeds.  The default value is equal to NGS.
---> this parameter is called m_MinComplexes within Ostrich
INIFLG     integer  Flag on whether to include an initial point in
                    the starting population.  Enter true if the initial 
                    point is to be included.  The default value is equal to false.
---> this parameter is called m_bUseInitPt within Ostrich
IPRINT    integer   Print-out control flag.  Enter '0' to print out
                    the best estimate of the global optimum at the
                    end of each shuffling loop.  Enter '1' to print
                    out every point in the entire sample population
                    at the end of each shuffling loop.  The default
                    value is equal to 0. Enter 2 to ignore this variable
                    and use conventional Ostrich output.
---> this parameter is called m_OutputMode within Ostrich
PARAMS     double * Initial estimates of the parameters to be optimized.
---> this parameter is called m_pParams within Ostrich
LOWER      double * Lower bounds of the parameters to be optimized.
---> this parameter is called m_pLower within Ostrich
UPPER      double * Upper bounds of the parameters to be optimized.
---> this parameter is called m_pUpper within Ostrich
Version History
10-31-09    lsm   Created
******************************************************************************/
#include <math.h>
#include <string.h>

#include "SCEUA.h"
#include "Model.h"
#include "ParameterGroup.h"
#include "ParameterABC.h"
#include "StatsClass.h"

#include "Utility.h"
#include "WriteUtility.h"
#include "Exception.h"

/******************************************************************************
WarmStart()
Read the best solution from a previous run.
******************************************************************************/
void SCEUA::WarmStart(void)
{
   int np = m_pModel->GetParamGroupPtr()->GetNumParams();
   double * pbest = new double[np+1];
   int newcount = SimpleWarmStart(np, pbest);
   m_pModel->GetParamGroupPtr()->WriteParams(pbest);
   ((Model *)m_pModel)->SetCounter(newcount);
   delete [] pbest;
}/* end WarmStart() */

/******************************************************************************
CTOR
Registers the algorithm pointer and creates instances of member variables.
******************************************************************************/
SCEUA::SCEUA(ModelABC * pModel)
{
   RegisterAlgPtr(this);
   m_pModel = pModel;
   m_pParams = NULL;
   m_pUpper = NULL;
   m_pLower = NULL;
   m_bUseInitPt = false;
   m_fSaved = NEARLY_HUGE;

   IncCtorCount();
}/* end CTOR() */

/******************************************************************************
Destroy()
******************************************************************************/
void SCEUA::Destroy(void)
{ 
   delete [] m_pParams;
   delete [] m_pLower;
   delete [] m_pUpper;
}/* end Destroy() */

/******************************************************************************
Calibrate()
Solve the Least-Squares minimization problem using SCEUA.
******************************************************************************/
void SCEUA::Calibrate(void)
{ 
   int id;
   char fileName[DEF_STR_SZ];
   FILE * pFile;

   NEW_PRINT("StatsClass", 1);
   m_pStats = new StatsClass(m_pModel);
   MEM_CHECK(m_pStats);
   RegisterStatsPtr(m_pStats);
   
   Optimize();

   //compute statistics (variance and covariance)
   m_pStats->CalcStats();

   id = 0;
   sprintf(fileName, "OstOutput%d.txt", id);

   //write statistics of best parameter set to output file
   pFile = fopen(fileName, "a");   
   m_pStats->WriteStats(pFile);
   fclose(pFile);

   //write statistics of best parameter set to output file
   m_pStats->WriteStats(stdout);
} /* end Calibrate() */

/******************************************************************************
Optimize()
Minimize the objective function using SCEUA.
******************************************************************************/
void SCEUA::Optimize(void)
{
   ParameterGroup * pGroup = m_pModel->GetParamGroupPtr();

   InitFromFile(GetInFileName());

   WriteSetup(m_pModel, "Shuffled Complex Evolution - University of Arizona");
   m_CurIter = 0;
   //write banner
   WriteBanner(m_pModel, "gen   best value     ", "Pct. Complete");
  
   scemain(); //main SCE implemenation, converted from FORTRAN

   //place model at optimal prameter set
   pGroup->WriteParams(m_pParams);
   m_pModel->Execute();

   WriteOptimal(m_pModel, m_Best);
   m_pStatus.pct = 100.00;
   m_pStatus.numRuns = m_pModel->GetCounter();
   WriteStatus(&m_pStatus);
   //write algorithm metrics
   WriteAlgMetrics(this);
} /* end Optimize() */

/******************************************************************************
scemain()
THIS IS THE MAIN PROGRAM CALLING SUBROUTINES SCEIN AND SCEUA
******************************************************************************/
void SCEUA::scemain(void)
{
   double * a, * bl, * bu;
   int jseed[10] = {2,3,5,7,11,13,17,19,23,29}; 

   a = m_pParams;
   bl = m_pLower;
   bu = m_pUpper;

   if(m_OutputMode != 2)
      printf(" ENTER THE MAIN PROGRAM --- \n"); 

   int nopt, kstop, iseed, ngs, npg, nps, nspl, mings, iprint, maxn;
   int iniflg;
   double pcento;
   nopt = m_np = m_pModel->GetParamGroupPtr()->GetNumParams();
   scein(a,bl,bu,nopt,&maxn,&kstop,&pcento,&iseed,
         &ngs,&npg,&nps,&nspl,&mings,&iniflg,&iprint);

   int nrun = 1;

   int i;
   for(i = 0; i < nrun; i++)
   {
      if (nrun != 1) iseed = jseed[i];
      if(m_OutputMode != 2)
         printf("@ SCE-UA Run Number %d Random Seed Value %d\n",i,iseed);
      sceua(a,bl,bu,nopt,maxn,kstop,pcento,iseed,
            ngs,npg,nps,nspl,mings,iniflg,iprint);
   }/* end for() */
}/* end scemain() */

/******************************************************************************
scein()
THIS SUBROUTINE READS AND PRINTS THE INPUT VARIABLES FOR
SHUFFLED COMPLEX EVOLUTION METHOD FOR GLOBAL OPTIMIZATION
 -- Version 2.1
ADAPTED FROM FORTRAN CODE WRITTEN BY 
    QINGYUN DUAN - UNIVERSITY OF ARIZONA, APRIL 1992
******************************************************************************/
void SCEUA::scein
(
   double * a,
   double * bl,
   double * bu,
   int nopt,
   int *maxn,
   int *kstop,
   double *pcento,
   int *iseed,
   int *ngs,
   int *npg,
   int *nps,
   int *nspl,
   int *mings,
   int *iniflg,
   int *iprint
)
{
   char pcntrl[100],deflt[100],usrsp[100];
   char reduc[40],initl[40],ysflg[40],noflg[40],**xname; 

   strcpy(deflt, "DEFAULT"); 
   strcpy(usrsp, "USER SPEC."); 
   strcpy(ysflg, "YES"); 
   strcpy(noflg, "NO");  
   xname = new char*[nopt];
   for(int i = 0; i < nopt; i++)
   {
     xname[i] = new char[50];   
     strncpy(xname[i], m_pModel->GetParamGroupPtr()->GetParamPtr(i)->GetName(), 9);
   }

   if(m_OutputMode != 2) printf("ENTER THE SCEIN SUBROUTINE --- \n");

   //INITIALIZE I/O VARIABLES
   FILE * pIn  = fopen("sce.in", "r");
   FILE * pOut = fopen("sce.out", "w");

   int ierror = 0;
   int iwarn = 0;
   if(m_OutputMode != 2)
   {
      fprintf(pOut, "\
          SHUFFLED COMPLEX EVOLUTION GLOBAL OPTIMIZATION\n\
          ==============================================\n\n\n");
   }

   // READ THE SCE CONTROL PARAMETERS
   int ideflt = 0;
   char line[160];
   fgets(line, 1600, pIn);
   sscanf(line, "%d %d %lf %d %d %d", maxn, kstop, pcento, ngs, iseed, &ideflt);
   if (*iseed == 0) *iseed = 1969;

  //IF ideflt IS EQUAL TO 1, READ THE SCE CONTROL PARAMETERS
   if (ideflt == 1)
   {
      fgets(line, 1600, pIn);
      sscanf(line, "%d %d %d %d %d %d", npg, nps, nspl, mings, iniflg, iprint);
      strcpy(pcntrl, usrsp);
   }
   else
   {
      strcpy(pcntrl, deflt);
   }

   //READ THE INITIAL PARAMETER VALUES AND THE PARAMETER BOUNDS
   int iopt;
   for(iopt = 0; iopt < nopt; iopt++)
   {
      fgets(line, 1600, pIn);
      sscanf(line,"%lf %lf %lf", &(a[iopt]), &(bl[iopt]), &(bu[iopt]));
   }

   //IF ideflt IS EQUAL TO 0, SET THE SCE CONTROL PARAMETERS TO THE DEFAULT VALUES
   if (ideflt == 0)
   {
      *npg = 2*nopt + 1;
      *nps = nopt + 1;
      *nspl = *npg;
      *mings = *ngs;
      *iniflg = 0;
      *iprint = 0;
   }/* end if() */

   //CHECK IF THE SCE CONTROL PARAMETERS ARE VALID
   if ((*ngs < 1) || (*ngs >= 1320))
   {
      fprintf(pOut, 
              "**ERROR** NUMBER OF COMPLEXES IN INITIAL POPULATION (%d) IS NOT A VALID CHOICE\n",
              *ngs);
      ierror = ierror + 1;
   }

   if ((*kstop < 0) || (*kstop >= 20))
   {
      fprintf(pOut, 
"**WARNING** THE NUMBER OF SHUFFLING LOOPS IN \
WHICH THE CRITERION VALUE MUST CHANGE SHOULD BE \
GREATER THAN 0 AND LESS THAN 10. kstop = %d WAS SPECIFIED. \
BUT kstop = 5 WILL BE USED INSTEAD.\n", 
      *kstop);
      iwarn = iwarn + 1;
      *kstop = 5;
   }/* end if() */

   if((*mings < 1) || (*mings > *ngs))
   {
      fprintf(pOut, 
"**WARNING** THE MINIMUM NUMBER OF COMPLEXES (%d) \
IS NOT A VALID CHOICE. SET IT TO DEFAULT \n", 
      *mings);
      iwarn = iwarn + 1;
      *mings = *ngs;
   }/* end if() */

   if ((*npg < 2) || (*npg > 1320/MyMax(*ngs,1))) 
   {
      fprintf(pOut, 
"**WARNING** THE NUMBER OF POINTS IN A COMPLEX (%d) \
IS NOT A VALID CHOICE, SET IT TO DEFAULT\n", 
      *npg);
      iwarn = iwarn + 1;
      *npg = 2*nopt+1;
   }/* end if() */

   if ((*nps < 2) || (*nps > *npg) || (*nps > 50))
   {
      fprintf(pOut, 
"**WARNING** THE NUMBER OF POINTS IN A SUB-COMPLEX (%d) \
IS NOT A VALID CHOICE, SET IT TO DEFAULT\n",
      *nps);
      iwarn = iwarn + 1;
      *nps = nopt + 1;
   }/* end if() */

   if (*nspl < 1)
   {
      fprintf(pOut, 
"**WARNING** THE NUMBER OF EVOLUTION STEPS \
TAKEN IN EACH COMPLEX BEFORE SHUFFLING (%d) \
IS NOT A VALID CHOICE, SET IT TO DEFAULT\n", 
      *nspl);
      iwarn = iwarn + 1;
      *nspl = *npg;
   }/* end if() */
   
   // COMPUTE THE TOTAL NUMBER OF POINTS IN INITIAL POPULATION
   int npt;
   npt = (*ngs) * (*npg); //npt = ngs * npg

   if (npt > 1320)
   {
      fprintf(pOut, 
"**WARNING** THE NUMBER OF POINTS IN INITIAL \
POPULATION (%d) EXCEED THE POPULATION LIMIT \
SET NGS TO 2, AND NPG, NPS AND NSPL TO DEFAULTS\n", 
      npt);
      iwarn = iwarn + 1;
      *ngs = 2;
      *npg = 2*nopt + 1;
      *nps = nopt + 1;
      *nspl = *npg;
   } /* end if() */

   // PRINT OUT THE TOTAL NUMBER OF ERROR AND WARNING MESSAGES
   if (ierror >= 1)
      fprintf(pOut, "*** TOTAL NUMBER OF ERROR MESSAGES IS %d\n",ierror);

   if (iwarn >= 1)
      fprintf(pOut, "*** TOTAL NUMBER OF WARNING MESSAGES IS %d\n",iwarn);

   if (*mings < *ngs)
      strcpy(reduc, ysflg);
   else
      strcpy(reduc, noflg);

   if (iniflg != 0)
      strcpy(initl, ysflg);
   else
      strcpy(initl, noflg);

   //PRINT SHUFFLED COMPLEX EVOLUTION OPTIMIZATION OPTIONS
   fprintf(pOut,"\
  SCE CONTROL     MAX TRIALS     REQUIRED IMPROVEMENT     RANDOM\n\
   PARAMETER        ALLOWED      PERCENT    NO. LOOPS      SEED\n\
  -----------     ----------     -------    ---------     ------\n");

   double pcenta;
   pcenta=(*pcento)*100.;
   fprintf(pOut,"  %-11s     %-10d     %7.2lf    %-9d     %-6d\n\n\n",
   pcntrl, *maxn, pcenta, *kstop, *iseed);

   fprintf(pOut,"\
                  SCE ALGORITHM CONTROL PARAMETERS\n\
                  ================================\n\n\
  NUMBER OF     POINTS PER     POINTS IN      POINTS PER    EVOL. STEPS\n\
  COMPLEXES      COMPLEX      INI. POPUL.     SUB-COMPLX    PER COMPLEX\n\
  ---------     ----------    -----------     ----------    -----------\n");
   fprintf(pOut,"  %-9d     %-10d    %-11d     %-10d    %-11d\n\n\n", 
           *ngs, *npg, npt, *nps, *nspl);

   fprintf(pOut,"\
               COMPLX NO.     MIN COMPLEX     INI. POINT\n\
               REDUCTION      NO. ALLOWED      INCLUDED\n\
               ----------     -----------     ----------\n");
   fprintf(pOut,"               %-10s     %-11d     %-10s\n\n\n", 
           reduc, *mings, initl);

   fprintf(pOut,"\
        INITIAL PARAMETER VALUES AND PARAMETER BOUNDS\n\
        =============================================\n\n\
  PARAMETER     INITIAL VALUE     LOWER BOUND     UPPER BOUND\n\
  ---------     -------------     -----------     -----------\n");
   for(int i = 0; i < nopt; i++)
   {
      fprintf(pOut, "  %-9s     %13.3lf     %11.3lf     %11.3lf\n",
              xname[i], a[i], bl[i], bu[i]);
   }/* end for() */
   fprintf(pOut,"\n\n");

   for(int i = 0; i < nopt; i++)
   {
     delete [] xname[i];   
   }
   delete [] xname;

   if (ierror >= 1)
   {
      fprintf(pOut, 
"*** THE OPTIMIZATION SEARCH IS NOT CONDUCTED BECAUSE OF INPUT DATA ERROR ***\n");
      fclose(pIn);
      fclose(pOut);
      ExitProgram(1);
   }/* end if() */

   fclose(pIn);
   fclose(pOut);
}/* end scein() */

/******************************************************************************
sceua()
  SHUFFLED COMPLEX EVOLUTION METHOD FOR GLOBAL OPTIMIZATION
     -- Version 2.1
  by QINGYUN DUAN (adpated to C++ by L. Shawn Matott)
  DEPARTMENT OF HYDROLOGY & WATER RESOURCES
  UNIVERSITY OF ARIZONA, TUCSON, AZ 85721
  (602) 621-9360, email: duan@hwr.arizona.edu
  WRITTEN IN OCTOBER 1990.
  REVISED IN AUGUST 1991
  REVISED IN APRIL 1992
  STATEMENT BY AUTHOR:
  --------------------
     This general purpose global optimization program is developed at
     the Department of Hydrology & Water Resources of the University
     of Arizona.  Further information regarding the SCE-UA method can
     be obtained from Dr. Q. Duan, Dr. S. Sorooshian or Dr. V.K. Gupta
     at the address and phone number listed above.  We request all
     users of this program make proper reference to the paper entitled
     'Effective and Efficient Global Optimization for Conceptual
     Rainfall-runoff Models' by Duan, Q., S. Sorooshian, and V.K. Gupta,
     Water Resources Research, Vol 28(4), pp.1015-1031, 1992.
  LIST OF INPUT ARGUEMENT VARIABLES
     a(.) = initial parameter set
     bl(.) = lower bound on parameters
     bu(.) = upper bound on parameters
     nopt = number of parameters to be optimized
  LIST OF SCE ALGORITHMIC CONTROL PARAMETERS:
     ngs = number of complexes in the initial population
     npg = number of points in each complex
     npt = total number of points in initial population (npt=ngs*npg)
     nps = number of points in a sub-complex
     nspl = number of evolution steps allowed for each complex before
         complex shuffling
     mings = minimum number of complexes required, if the number of
         complexes is allowed to reduce as the optimization proceeds
     iseed = initial random seed
     iniflg = flag on whether to include the initial point in population
         = 0, not included
         = 1, included
     iprint = flag for controlling print-out after each shuffling loop
         = 0, print information on the best point of the population
         = 1, print information on every point of the population
  CONVERGENCE CHECK PARAMETERS
     maxn = max no. of trials allowed before optimization is terminated
     kstop = number of shuffling loops in which the criterion value must
         chang by the given percentage before optimization is terminated
     pcento = percentage by which the criterion value must change in
         given number of shuffling loops
     ipcnvg = flag indicating whether parameter convergence is reached
         (i.e., check if gnrng is less than 0.001)
         = 0, parameter convergence not satisfied
         = 1, parameter convergence satisfied
  LIST OF LOCAL VARIABLES
     x(.,.) = coordinates of points in the population
     xf(.) = function values of x(.,.)
     xx(.) = coordinates of a single point in x
     cx(.,.) = coordinates of points in a complex
     cf(.) = function values of cx(.,.)
     s(.,.) = coordinates of points in the current simplex
     sf(.) = function values of s(.,.)
     bestx(.) = best point at current shuffling loop
     bestf = function value of bestx(.)
     worstx(.) = worst point at current shuffling loop
     worstf = function value of worstx(.)
     xnstd(.) = standard deviation of parameters in the population
     gnrng = normalized geometric mean of parameter ranges
     lcs(.) = indices locating position of s(.,.) in x(.,.)
     bound(.) = bound on ith variable being optimized
     ngs1 = number of complexes in current population
     ngs2 = number of complexes in last population
     iseed1 = current random seed
     criter(.) = vector containing the best criterion values of the last
         10 shuffling loops
******************************************************************************/
void SCEUA::sceua
(
   double * a,
   double * bl,
   double * bu,
   int nopt,
   int maxn,
   int kstop,
   double pcento,
   int iseed,
   int ngs,
   int npg,
   int nps,
   int nspl,
   int mings,
   int iniflg,
   int iprint
)
{
   FILE * pOut = fopen("sce.out", "a");

   //LOCAL ARRAYS
   double ** x, * xx, * bestx, * worstx, * xf;
   double ** s, * sf, ** cx, * cf;
   double * xnstd, * bound, criter[20], * unit;
   int * lcs;   

   //allocate memory
   lcs = new int[nps];
   sf = new double[nps];
   xf = new double[ngs*npg];
   cf = new double[npg];
   x = new double * [ngs*npg];
   cx = new double * [npg];
   int i;
   for(i = 0; i < ngs*npg; i++)
   {
      x[i] = new double[nopt];
   }
   for(i = 0; i < npg; i++)
   {
      cx[i] = new double[nopt];
   }
   xx = new double[nopt];
   bestx = new double[nopt];
   worstx = new double[nopt];
   xnstd = new double[nopt];
   bound = new double[nopt];
   unit = new double[nopt];
   s = new double *[nps];
   for(i = 0; i < nps; i++)
   {
      s[i] = new double[nopt];
   }


   char **xname; 
   xname = new char*[nopt];
   for(i = 0; i < nopt; i++)
   {
     xname[i] = new char[50];   
     strncpy(xname[i], m_pModel->GetParamGroupPtr()->GetParamPtr(i)->GetName(), 9);
   }

   if(m_OutputMode != 2) printf("ENTER THE SCEUA SUBROUTINE --- \n");

   // INITIALIZE VARIABLES
   int nloop, loop, igs, nopt1, nopt2, itmp;
   nloop = 0;
   loop = 0;
   igs = 0;
   nopt1 = 8;
   if (nopt < 8) nopt1 = nopt;
   nopt2 = 12;
   if (nopt < 12) nopt2 = nopt;

   //INITIALIZE RANDOM SEED TO A NEGATIVE INTEGER
   int iseed1;
   iseed1 = -abs(iseed);

   //COMPUTE THE TOTAL NUMBER OF POINTS IN INITIAL POPUALTION
   int npt, ngs1, npt1;
   npt = ngs * npg; 
   ngs1 = ngs; 
   npt1 = npt; 

   fprintf(pOut, "\
  ==================================================\n\
  ENTER THE SHUFFLED COMPLEX EVOLUTION GLOBAL SEARCH\n\
  ==================================================\n\n\n");

   if(m_OutputMode != 2) printf(" ***  Evolution Loop Number %d\n", nloop);

   //COMPUTE THE BOUND FOR PARAMETERS BEING OPTIMIZED
   int j;
   for(j = 1; j <= nopt; j++)
   {
      bound[j-1] = bu[j-1] - bl[j-1];
      unit[j-1] = 1.0;
   }

   //COMPUTE THE FUNCTION VALUE OF THE INITIAL POINT   
   double fa;
   //handle warm start
   if(m_pModel->CheckWarmStart() == true)
   {
      WarmStart();
      m_pModel->GetParamGroupPtr()->ReadParams(a);
   }
   // handle parameter extraction
   if(m_pModel->GetParamGroupPtr()->CheckExtraction() == true)
   {
      m_pModel->GetParamGroupPtr()->ReadParams(a);
   }
   m_pModel->GetParamGroupPtr()->WriteParams(a);
   fa = m_pModel->Execute();
   if (fa < m_fSaved)
   {
      m_fSaved = fa;
      m_pModel->SaveBest(0);
   }

   //write initial config.
   int nleft = m_Budget - m_pModel->GetCounter();

   double eb = (double)(m_pModel->GetCounter())/(double)m_Budget; //elapsed budget
   
   m_pStatus.curIter = 0;
   m_pStatus.maxIter = m_Budget;
   m_pStatus.pct = (float)100.00*((float)1.00-(float)nleft/(float)m_Budget);
   m_pStatus.numRuns = m_pModel->GetCounter();
   m_pModel->GetParamGroupPtr()->WriteParams(m_pParams);
   WriteRecord(m_pModel, 0, fa, m_pStatus.pct);
   m_CurIter++;
   WriteStatus(&m_pStatus);

   //PRINT THE INITIAL POINT AND ITS CRITERION VALUE
   fprintf(pOut, "\
*** PRINT THE INITIAL POINT AND ITS CRITERION VALUE ***\n\n\
 CRITERION    ");
   for(i = 0; i < nopt; i++)
   {
      fprintf(pOut, "%-9s    ", xname[i]);
   }
   fprintf(pOut, "\n  %8.0lf     ", fa);
   for(i = 0; i < nopt; i++)
   {
      fprintf(pOut, "%5.3lf     ", a[i]);
   }
   fprintf(pOut, "\n\n\n");
   
   // GENERATE AN INITIAL SET OF npt1 POINTS IN THE PARAMETER SPACE
   if (iniflg == 1)
   {
      for(j = 0; j < nopt; j++)
         x[0][j] = a[j];
      xf[0] = fa;
      WriteInnerEval(WRITE_SCE, npt, '.');
      WriteInnerEval(1, npt, '.');
   }/* end if() */
   // ELSE, GENERATE A POINT RANDOMLY AND SET IT EQUAL TO x(1,.)
   else
   {
      getpnt(nopt,1,&iseed1,xx,bl,bu,unit,bl);
      eb = (double)(m_pModel->GetCounter())/(double)m_Budget;
      for(j = 0; j < nopt; j++)
      {
         xx[j] = TelescopicCorrection(bl[j], bu[j], bestx[j], eb, xx[j]);
         x[0][j] = xx[j];
      }
      WriteInnerEval(WRITE_SCE, npt, '.');
      WriteInnerEval(1, npt, '.');
      m_pModel->GetParamGroupPtr()->WriteParams(xx);
      m_pModel->PerformParameterCorrections();
      for(j = 0; j < nopt; j++)
      {
         xx[j] = m_pModel->GetParamGroupPtr()->GetParamPtr(j)->GetEstVal();
         x[0][j] = xx[j];
      }
      xf[0] = m_pModel->Execute();
      if (xf[0] < m_fSaved)
      {
         m_fSaved = xf[0];
         m_pModel->SaveBest(0);
      }
   }

   //use initial point if it's better than the randomly generated one
   if(fa < xf[0])
   {
      fprintf(pOut, "THE INITIAL POINT IS BETTER THAN THE RANDOM STARTING POINT. USING IT INSTEAD.");

      for(j = 0; j < nopt; j++)
         x[0][j] = a[j];
      xf[0] = fa;
   }

   int icall;
   icall = 1;
   if (icall >= maxn) goto label_9000;

   //GENERATE npt1-1 RANDOM POINTS DISTRIBUTED UNIFORMLY IN THE PARAMETER
   //SPACE, AND COMPUTE THE CORRESPONDING FUNCTION VALUES
label_restart:
   for(i = 1; i < npt1; i++)
   {
      getpnt(nopt,1,&iseed1,xx,bl,bu,unit,bl);
      eb = (double)(m_pModel->GetCounter())/(double)m_Budget;
      for(j = 0; j < nopt; j++)
      {
         xx[j] = TelescopicCorrection(bl[j], bu[j], bestx[j], eb, xx[j]);
         x[i][j] = xx[j];
      }
      WriteInnerEval(i+1, npt, '.');
      m_pModel->GetParamGroupPtr()->WriteParams(xx);
      m_pModel->PerformParameterCorrections();
      for(j = 0; j < nopt; j++)
      {
         xx[j] = m_pModel->GetParamGroupPtr()->GetParamPtr(j)->GetEstVal();
         x[i][j] = xx[j];
      }
      xf[i] = m_pModel->Execute();
      if (xf[i] < m_fSaved)
      {
         m_fSaved = xf[i];
         m_pModel->SaveBest(0); 
      }

      icall = icall + 1;
      if (icall >= maxn)
      {
         break;
      }
   }/* end for() */
   WriteInnerEval(WRITE_ENDED, npt, '.');

   // ARRANGE THE POINTS IN ORDER OF INCREASING FUNCTION VALUE
   sort(npt1,nopt,x,xf);

   for(j = 0; j < nopt; j++)
   {
      bestx[j] = x[0][j];
      worstx[j] = x[npt1-1][j];
   }
   double bestf, worstf;
   bestf = xf[0];
   worstf = xf[npt1-1];

   // COMPUTE THE PARAMETER RANGE FOR THE INITIAL POPULATION
   double gnrng;
   int ipcnvg;
   parstt(npt1,nopt,x,xnstd,bound,&gnrng,&ipcnvg);

   // PRINT THE RESULTS FOR THE INITIAL POPULATION
   fprintf(pOut,"\
**** PRINT THE RESULTS OF THE SCE SEARCH ***\n\n\
 LOOP TRIALS COMPLXS  BEST F   WORST F   PAR RNG         ");
   for(i = 0; i < nopt; i++)
   {
      fprintf(pOut,"%-9s ", xname[i]);
   }
   fprintf(pOut,"\n");
   fprintf(pOut," %4d %6d %7d  %6.2lf  %9.3E  %8.3lf      ",
           nloop,icall,ngs1,bestf,worstf,gnrng);
   for(i = 0; i < nopt; i++)
   {
      fprintf(pOut,"%6.3lf    ", bestx[i]);
   }
   fprintf(pOut,"\n");

   if (iprint == 1)
   {
      fprintf(pOut, "POPULATION AT LOOP (%d)\n", nloop);
      for(i = 0; i < npt1; i++)
      {
         fprintf(pOut, "%8.3lf    ", xf[i]);
         for(j = 0; j < nopt; j++)
         {
            fprintf(pOut, "%8.3lf    ", x[i][j]);
         }
         fprintf(pOut, "\n");
      }/* end for() */
   }/* end if() */

   if (icall >= maxn) goto label_9000;
   if (ipcnvg == 1) goto label_9200;

   // BEGIN THE MAIN LOOP ----------------
 label_1000:

   nleft = m_Budget - m_pModel->GetCounter();
   m_pStatus.curIter = nloop+1;
   if(IsQuit() == true){ goto label_9999;}
   if(nleft <= 0){ m_pStatus.pct = 100.00;  goto label_9000;}

   nloop = nloop + 1;

   if(m_OutputMode != 2) printf(" ***  Evolution Loop Number %d\n",nloop); 
   
   //BEGIN LOOP ON COMPLEXES
   for(igs = 1; igs <= ngs1; igs++)
   {
      // ASSIGN POINTS INTO COMPLEXES
      int k1, k2;
      for(k1 = 1; k1 <= npg; k1++) 
      {
        k2 = (k1-1) * ngs1 + igs; 
        for(j = 1; j <= nopt; j++)
        {
            cx[k1-1][j-1] = x[k2-1][j-1]; 
        } //end for()
        cf[k1-1] = xf[k2-1];
      } //end for()
      // BEGIN INNER LOOP - RANDOM SELECTION OF SUB-COMPLEXES ---------------
      int tmp = 0;
      WriteInnerEval(WRITE_SCE, m_NumEvoSteps, '.');

      for(loop = 0; loop < nspl; loop++) 
      {
         // CHOOSE A SUB-COMPLEX (nps points) ACCORDING TO A LINEAR
         // PROBABILITY DISTRIBUTION
         if (nps == npg)
         {
            int k;
            for(k = 0; k < nps; k++)
            {
               lcs[k] = k;
            } // end do
            goto label_85; 
         } // end if

         double myrand;
         myrand = UniformRandom();
         itmp = (int)(npg + 0.5 - sqrt(pow((npg+0.5),2.00) - npg*(npg+1.00)*myrand));
         if(itmp >= npg) itmp = npg-1;
         lcs[0] = itmp;

         int k, lpos;
         for(k = 2; k <= nps; k++) 
         {
label_60:
            myrand = UniformRandom(); 
            lpos = (int)(npg + 0.5 - sqrt(pow((npg+0.5),2.00) - npg*(npg+1.00)*myrand));
            if(lpos >= npg) lpos = npg-1;

            for(k1 = 1; k1 <= k-1; k1++) 
            {
               if (lpos == lcs[k1-1]) goto label_60; 
            } // end do
            lcs[k-1] = lpos; 
         } // end do

         // ARRANGE THE SUB-COMPLEX IN ORDER OF INCEASING FUNCTION VALUE
         sort(nps,lcs);

         // CREATE THE SUB-COMPLEX ARRAYS
label_85: 
         for(k = 1; k <= nps; k++)
         {
            for(j = 1; j <= nopt; j++) 
            {
               s[k-1][j-1] = cx[lcs[k-1]][j-1]; 
            } // end do
            sf[k-1] = cf[lcs[k-1]];
         } // end do

         // USE THE SUB-COMPLEX TO GENERATE NEW POINT(S)
         cce(nopt,nps,s,sf,bl,bu,xnstd,&tmp,maxn,&iseed1);

         // IF THE SUB-COMPLEX IS ACCEPTED, REPLACE THE NEW SUB-COMPLEX
         // INTO THE COMPLEX
         for(k = 1; k <= nps; k++) 
         {
            for(j = 1; j <= nopt; j++) 
            {
               cx[lcs[k-1]][j-1] = s[k-1][j-1]; 
            } // end do
            cf[lcs[k-1]] = sf[k-1]; 
         } //end do

         // SORT THE POINTS
         sort(npg,nopt,cx,cf);

         //IF MAXIMUM NUMBER OF RUNS EXCEEDED, BREAK OUT OF THE LOOP
         if (icall >= maxn) break; 
         // END OF INNER LOOP ------------
      } /* end for() */

      WriteInnerEval(WRITE_ENDED, m_NumEvoSteps, '.');
      icall += tmp;

      // REPLACE THE NEW COMPLEX INTO ORIGINAL ARRAY x(.,.)
      for(k1 = 1; k1 <= npg; k1++)
      {
         k2 = (k1-1) * ngs1 + igs; 
         for(j = 1; j <= nopt; j++) 
         {
            x[k2-1][j-1] = cx[k1-1][j-1]; 
         } // end do
         xf[k2-1] = cf[k1-1]; 
      } // end do
      if (icall >= maxn) break; 
      //END LOOP ON COMPLEXES
   } /* end for() */ 

   // RE-SORT THE POINTS
   sort(npt1,nopt,x,xf);

   // RECORD THE BEST AND WORST POINTS
   for(j = 0; j < nopt; j++) 
   {
      m_pParams[j] = bestx[j] = x[0][j];
      worstx[j] = x[npt1-1][j]; 
   } //end do
   m_Best = bestf = xf[0];
   worstf = xf[npt1-1];

   // TEST THE POPULATION FOR PARAMETER CONVERGENCE
   parstt(npt1,nopt,x,xnstd,bound,&gnrng,&ipcnvg);

   // PRINT THE RESULTS FOR CURRENT POPULATION
   m_pModel->GetParamGroupPtr()->WriteParams(m_pParams);
   nleft = m_Budget - m_pModel->GetCounter();
   m_pStatus.pct = (float)100.00*((float)1.00-(float)nleft/(float)m_Budget);
   m_pStatus.numRuns = m_pModel->GetCounter();
   WriteStatus(&m_pStatus);
   WriteRecord(m_pModel, nloop, m_Best, m_pStatus.pct);
   m_CurIter++;

   if((nloop%5) == 0)
   {
      fprintf(pOut,"\
 LOOP TRIALS COMPLXS  BEST F   WORST F   PAR RNG         ");
      for(i = 0; i < nopt; i++)
      {
         fprintf(pOut,"%-9s ", xname[i]);
      }
      fprintf(pOut,"\n");
   }
   fprintf(pOut," %4d %6d %7d  %6.2lf  %9.3E  %8.3lf      ",
           nloop,icall,ngs1,bestf,worstf,gnrng);
   for(i = 0; i < nopt; i++)
   {
      fprintf(pOut,"%6.3lf    ", bestx[i]);
   }
   fprintf(pOut,"\n");

   if (iprint == 1)
   {
      fprintf(pOut, "POPULATION AT LOOP (%d)\n", nloop);
      for(i = 0; i < npt1; i++)
      {
         fprintf(pOut, "%8.3lf    ", xf[i]);
         for(j = 0; j < nopt; j++)
         {
            fprintf(pOut, "%8.3lf    ", x[i][j]);
         }
         fprintf(pOut, "\n");
      }/* end for() */
   }/* end if() */

   // TEST IF MAXIMUM NUMBER OF FUNCTION EVALUATIONS EXCEEDED
   if (icall >= maxn) goto label_9000; 

   // COMPUTE THE COUNT ON SUCCESSIVE LOOPS W/O FUNCTION IMPROVEMENT
   criter[19] = bestf; 
   if (nloop < (kstop+1)) goto label_132; 
   double denomi, timeou;
   denomi = fabs(criter[19-kstop] + criter[19]) / 2.0; 
   timeou = fabs(criter[19-kstop] - criter[19]) / denomi; 
   if (timeou < pcento) goto label_9100; 
label_132: 
   int l;
   for(l=0; l < 19; l++) 
   {
        criter[l] = criter[l+1];
   } //end do


   //IF POPULATION IS CONVERGED INTO A SUFFICIENTLY SMALL SPACE
   if (ipcnvg == 1) goto label_9200; 

   //NONE OF THE STOPPING CRITERIA IS SATISFIED, CONTINUE SEARCH

   //CHECK FOR COMPLEX NUMBER REDUCTION
   int ngs2;
   if (ngs1 > mings) 
   {
        ngs2 = ngs1; 
        ngs1 = ngs1 - 1; 
        npt1 = ngs1 * npg; 
        comp(nopt,npt1,ngs1,ngs2,npg,x,xf,cx,cf); 
   } //end if

   // END OF MAIN LOOP -----------
   goto label_1000;

   // SEARCH TERMINATED
label_9000: 

      fprintf(pOut, "\
*** OPTIMIZATION SEARCH TERMINATED BECAUSE THE\n\
    LIMIT ON THE MAXIMUM NUMBER OF TRIALS (%d)\n\
    WAS EXCEEDED.  SEARCH WAS STOPPED AT %d SUB-COMPLEX\n\
    OF COMPLEX %d IN SHUFFLING LOOP %d ***\n\n",
    maxn, loop, igs, nloop);

      goto label_9999; 

label_9100:

      fprintf(pOut, "\
*** OPTIMIZATION TERMINATED BECAUSE THE CRITERION\n\
    VALUE HAS NOT CHANGED %5.2lf PERCENT IN %d\n\
    SHUFFLING LOOPS ***\n\n", pcento*100.0,kstop);

      goto label_9999; 

 label_9200:
      fprintf(pOut, "\
 *** OPTIMIZATION RESTARTED BECAUSE THE POPULATION HAS\n\
     CONVERGED INTO %5.2lf PERCENT OF THE FEASIBLE SPACE ***\n\n",
      gnrng*100.0); 
      goto label_restart;

 label_9999:
      // PRINT THE FINAL PARAMETER ESTIMATE AND ITS FUNCTION VALUE
      fprintf(pOut, "\
*** PRINT THE FINAL PARAMETER ESTIMATE AND ITS CRITERION VALUE ***\n\n\
 CRITERION        ");

      for(i = 0; i < nopt; i++)
      {
         fprintf(pOut,"%-9s ", xname[i]);
      }
      fprintf(pOut,"\n%6.3lf    ", bestf);
      for(i = 0; i < nopt; i++)
      {
         fprintf(pOut,"%6.3lf    ", bestx[i]);
      }
      fprintf(pOut,"\n");

   fclose(pOut);
   /* clean up memory */
   for(i = 0; i < nopt; i++)
   {
     delete [] xname[i];   
   }
   delete [] xname;
   for(i = 0; i < ngs*npg; i++)
   {
      delete [] x[i];
   }
   for(i = 0; i < npg; i++)
   {
      delete [] cx[i];
   }
   delete [] x;
   delete [] cx;
   delete [] xx;
   delete [] bestx;
   delete [] worstx;
   delete [] xnstd;
   delete [] bound;
   delete [] unit;
   for(i = 0; i < nps; i++)
   {
      delete [] s[i];
   }
   delete [] s;
   delete [] sf;
   delete [] lcs;
   delete [] cf;
   delete [] xf;
} /* end sceua() */

/******************************************************************************
cce()
ALGORITHM TO GENERATE A NEW POINT(S) FROM A SUB-COMPLEX
******************************************************************************/
void SCEUA::cce
(
   int nopt,
   int nps,
   double ** s,
   double * sf,
   double * bl,
   double * bu,
   double * xnstd,
   int * icall,
   double maxn,
   int * iseed
)
{
   //SUB-COMPLEX VARIABLES
   const double c1=0.8;
   const double c2=0.4;

   /* ----------------------------------------------------
   LIST OF LOCAL VARIABLES
      sb(.) = the best point of the simplex
      sw(.) = the worst point of the simplex
      w2(.) = the second worst point of the simplex
      fw = function value of the worst point
      ce(.) = the centroid of the simplex excluding wo
      snew(.) = new point generated from the simplex
      iviol = flag indicating if constraints are violated
            = 1 , yes
            = 0 , no
   ----------------------------------------------------- */
   double * sw, * sb, *ce, *snew;
   sw = new double[nopt];
   sb = new double[nopt];
   ce = new double[nopt];
   snew = new double[nopt];

   //EQUIVALENCE OF VARIABLES FOR READABILTY OF CODE
   int n = nps;
   int m = nopt;
   double alpha = 1.0;
   double beta = 0.5;

   /* ---------------------------------------------------
   IDENTIFY THE WORST POINT wo OF THE SUB-COMPLEX s
   COMPUTE THE CENTROID ce OF THE REMAINING POINTS
   COMPUTE step, THE VECTOR BETWEEN wo AND ce
   IDENTIFY THE WORST FUNCTION VALUE fw
   --------------------------------------------------- */
   int i, j;
   for(j = 0; j < m; j++)
   {
      sb[j] = s[0][j]; 
      sw[j] = s[n-1][j]; 
      ce[j] = 0.0; 
      for(i = 0; i < n-1; i++) 
      {
         ce[j] = ce[j] + s[i][j]; 
      } //end do
     ce[j] = ce[j]/(double)(n-1);
   } //end do
   double fw;
   fw = sf[n-1]; 

   //COMPUTE THE NEW POINT snew
   //FIRST TRY A REFLECTION STEP
   for(j = 0; j < m; j++) 
   {
      snew[j] = ce[j] + alpha * (ce[j] - sw[j]);
   } //end do

   //CHECK IF snew SATISFIES ALL CONSTRAINTS
   int ibound;
   chkcst(nopt,snew,bl,bu,&ibound); 

   /* ------------------------------------------------------------------
   snew IS OUTSIDE THE BOUND,
   CHOOSE A POINT AT RANDOM WITHIN FEASIBLE REGION ACCORDING TO
   A NORMAL DISTRIBUTION WITH BEST POINT OF THE SUB-COMPLEX
   AS MEAN AND STANDARD DEVIATION OF THE POPULATION AS STD
   ------------------------------------------------------------------ */
   if (ibound >= 1) getpnt(nopt,2,iseed,snew,bl,bu,xnstd,sb);

   //COMPUTE THE FUNCTION VALUE AT snew
   double fnew;
   WriteInnerEval(*icall+1, m_NumEvoSteps, '.');
   double eb = (double)(m_pModel->GetCounter())/(double)m_Budget;
   for(j = 0; j < m; j++) snew[j] = TelescopicCorrection(bl[j], bu[j], sb[j], eb, snew[j]);
   m_pModel->GetParamGroupPtr()->WriteParams(snew);
   m_pModel->PerformParameterCorrections();
   for(j = 0; j < m; j++) snew[j] = m_pModel->GetParamGroupPtr()->GetParamPtr(j)->GetEstVal();
   fnew = m_pModel->Execute(); 
   if (fnew < m_fSaved)
   {
      m_fSaved = fnew;
      m_pModel->SaveBest(0);
   }

   *icall = *icall + 1;

   //COMPARE fnew WITH THE WORST FUNCTION VALUE fw
   //fnew IS LESS THAN fw, ACCEPT THE NEW POINT snew AND RETURN
   if (fnew <= fw) goto label_2000;
   if (*icall >= maxn) goto label_3000;

   //fnew IS GREATER THAN fw, SO TRY A CONTRACTION STEP
   for(j = 0; j < m; j++)
   {
      snew[j] = ce[j] - beta * (ce[j] - sw[j]);
   } //end do

   //COMPUTE THE FUNCTION VALUE OF THE CONTRACTED POINT
   eb = (double)(m_pModel->GetCounter())/(double)m_Budget;
   for(j = 0; j < m; j++) snew[j] = TelescopicCorrection(bl[j], bu[j], sb[j], eb, snew[j]);
   WriteInnerEval(*icall+1, m_NumEvoSteps, '.');
   m_pModel->GetParamGroupPtr()->WriteParams(snew);
   m_pModel->PerformParameterCorrections();
   for(j = 0; j < m; j++) snew[j] = m_pModel->GetParamGroupPtr()->GetParamPtr(j)->GetEstVal();
   fnew = m_pModel->Execute();
   if (fnew < m_fSaved)
   {
      m_fSaved = fnew;
      m_pModel->SaveBest(0);
   }

   *icall = *icall + 1;

   //COMPARE fnew TO THE WORST VALUE fw
   //IF fnew IS LESS THAN OR EQUAL TO fw, THEN ACCEPT THE POINT AND RETURN
   if (fnew <= fw) goto label_2000; 
   if (*icall >= maxn) goto label_3000; 

   /* ---------------------------------------------------------------------
   IF BOTH REFLECTION AND CONTRACTION FAIL, CHOOSE ANOTHER POINT
   ACCORDING TO A NORMAL DISTRIBUTION WITH BEST POINT OF THE SUB-COMPLEX
   AS MEAN AND STANDARD DEVIATION OF THE POPULATION AS STD
   --------------------------------------------------------------------- */
   getpnt(nopt,2,iseed,snew,bl,bu,xnstd,sb);

   //COMPUTE THE FUNCTION VALUE AT THE RANDOM POINT
   eb = (double)(m_pModel->GetCounter())/(double)m_Budget;
   for(j = 0; j < m; j++) snew[j] = TelescopicCorrection(bl[j], bu[j], sb[j], eb, snew[j]);
   WriteInnerEval(*icall+1, m_NumEvoSteps, '.');
   m_pModel->GetParamGroupPtr()->WriteParams(snew);
   m_pModel->PerformParameterCorrections();
   for(j = 0; j < m; j++) snew[j] = m_pModel->GetParamGroupPtr()->GetParamPtr(j)->GetEstVal();
   fnew = m_pModel->Execute();
   if (fnew < m_fSaved)
   {
      m_fSaved = fnew;
      m_pModel->SaveBest(0);
   }

   *icall = *icall + 1;

   //REPLACE THE WORST POINT BY THE NEW POINT
label_2000:
   for(j = 0; j < m; j++)
   {
      s[n-1][j] = snew[j];
   } //end do
   sf[n-1] = fnew;

label_3000:
   //free up memory  
   delete [] sw;
   delete [] sb;
   delete [] ce;
   delete [] snew;
} /* end cce() */

/******************************************************************************
getpnt()
This subroutine generates a new point within feasible region
x(.) = new point
xi(.) = focal point
bl(.) = lower bound
bu(.) = upper bound
std(.) = standard deviation of probability distribution
idist = probability flag
      = 1 - uniform distribution
      = 2 - Gaussian distribution
******************************************************************************/
void SCEUA::getpnt
(
   int nopt,
   int idist,
   int * iseed,
   double * x,
   double * bl,
   double * bu,
   double * std,
   double * xi
)
{
   int ibound;
   int j;
   double myrand;

   int icount = m_pModel->GetCounter();
label_1:
   for(j = 0; j < nopt; j++) //1   do j=1, nopt
   {
label_2:
      if (idist == 1)
      {
         myrand = UniformRandom();
      }
      else if (idist == 2)
      {
         myrand = GaussRandom();
      }
      else
      {
         printf("unknown distribution!\n");
      }

      x[j] = xi[j] + std[j] * myrand * (bu[j] - bl[j]);

      FILE * pFile = fopen("getpnt.txt", "a+");
      fprintf(pFile, "%d\tx[%d]:%E\txi[%d]:%e\tstd[%d]:%E\tmyrand : %E\tbu[%d]:%E\tbl[%d]:%E\n",
                     icount, j+1, x[j], j+1, xi[j], j+1, std[j], myrand, j+1, bu[j], j+1, bl[j]);
      fclose(pFile);

      //Check explicit constraints
      chkcst(1,&x[j],&bl[j],&bu[j],&ibound);
      if (ibound >= 1)
      {
         goto label_2;
      }
   } //end do

   //Check implicit constraints    
   chkcst(nopt,x,bl,bu,&ibound); 
   if (ibound >= 1)
   {
      goto label_1; 
   }
}/* end getpnt() */

/******************************************************************************
parstt()
SUBROUTINE CHECKING FOR PARAMETER CONVERGENCE
******************************************************************************/
void SCEUA::parstt
(
   int npt,
   int nopt,
   double ** x,
   double * xnstd,
   double * bound,
   double * gnrng,
   int * ipcnvg
)
{
   double * xmax, * xmin, * xmean;
   xmax = new double[nopt];
   xmin = new double[nopt];
   xmean = new double[nopt];

   const double delta = 1.0e-20;
   const double peps = m_Peps;

   //COMPUTE MAXIMUM, MINIMUM AND STANDARD DEVIATION OF PARAMETER VALUES
   double gsum, xsum1, xsum2;
   int i,k;
   gsum = 0.0; 
   for(k = 0; k < nopt; k++) 
   {
      xmax[k] = -1.0E+20; 
      xmin[k] = 1.0E+20;
      xsum1 = 0.0; 
      xsum2 = 0.0; 

      for(i = 0; i < npt; i++) 
      {
         xmax[k] = MyMax(x[i][k], xmax[k]); 
         xmin[k] = MyMin(x[i][k], xmin[k]); 
         xsum1 = xsum1 + x[i][k]; 
         xsum2 = xsum2 + x[i][k]*x[i][k];
      } //end do

      xmean[k] = xsum1/(double)npt; 
      xnstd[k] = (xsum2 / (double)npt - xmean[k]*xmean[k]);

      if (xnstd[k] <= delta) xnstd[k] = delta; 
      xnstd[k] = sqrt(xnstd[k]);
      xnstd[k] = xnstd[k] / bound[k];

      gsum = gsum + log(delta + (xmax[k]-xmin[k])/bound[k]);
   } //end do
   *gnrng = exp(gsum/(double)nopt);

   //CHECK IF NORMALIZED STANDARD DEVIATION OF PARAMETER IS <= eps
   *ipcnvg = 0;
   if (*gnrng <= peps) 
   {
      *ipcnvg = 1;
   } //end if

   delete [] xmax;
   delete [] xmin;
   delete [] xmean;

}/* end parstt() */

/******************************************************************************
comp()
THIS SUBROUTINE REDUCE INPUT MATRIX a(n,ngs2*npg) TO MATRIX
b(n,ngs1*npg) AND VECTOR af(ngs2*npg) TO VECTOR bf(ngs1*npg)
******************************************************************************/
void SCEUA::comp
(
   int n,
   int npt,
   int ngs1,
   int ngs2,
   int npg,
   double ** a,
   double * af,
   double ** b,
   double * bf
)
{
   int i, igs, ipg, k1,  k2;
   for(igs = 1; igs <= ngs1; igs++)
   {
      for(ipg = 1; ipg <= npg; ipg++)
      {
         k1=(ipg-1)*ngs2 + igs; 
         k2=(ipg-1)*ngs1 + igs;
         while(k2 > npg) k2 -= npg;
         for(i = 1; i <= n; i++)
         {
            b[k2-1][i-1] = a[k1-1][i-1];
         } //end do
         bf[k2-1] = af[k1-1];
      } //end do
   } //end do

   int j, jj;
   for(j = 0; j < npt; j++) 
   {
      jj = j % npg;
      for(i = 0; i < n; i++)
      {
         a[j][i] = b[jj][i]; 
      } //end do
      af[j] = bf[jj];
   } //end do

} /* end comp() */

/******************************************************************************
sort()
Sort a complex of parameter sets in ascending order of cost function.
******************************************************************************/
void SCEUA::sort
(
   int n,
   int m,
   double ** rb,
   double * ra
)
{
   //n = number of paramter sets
   //m = number of parameters
   //rb = list of parameter sets
   //ra = list of costs

   for(int p = 0; p < n; p++)
   {
      double fp = ra[p];
      for(int i = p + 1; i < n; i++)
      {
         double fi = ra[i];
         //swap if ith entry is better than pth
         if(fi < fp)
         {
            ra[p] = fi;
            ra[i] = fp;
            for(int j = 0; j < m; j++)
            {
               double t = rb[i][j];
               rb[i][j] = rb[p][j];
               rb[p][j] = t;
            }/* end for() */
         }/* end if() */
      }/* end for() */
   }/* end for() */
} /* end sort() */

/******************************************************************************
sort()
Sort a list of integers in ascending order.
******************************************************************************/
void SCEUA::sort
(
   int n,
   int * ra
)
{
   for(int p = 0; p < n; p++)
   {
      int fp = ra[p];
      for(int i = p + 1; i < n; i++)
      {
         int fi = ra[i];
         //swap if ith entry is better than pth
         if(fi < fp)
         {
            ra[p] = fi;
            ra[i] = fp;
         }/* end if() */
      }/* end for() */
   }/* end for() */
} /* end sort() */

/******************************************************************************
chkcst()
     This subroutine check if the trial point satisfies all
     constraints.
     ibound - violation indicator
            = -1 initial value
            = 0  no violation
            = 1  violation
     nopt = number of optimizing variables
     ii = the ii'th variable of the arrays x, bl, and bu
******************************************************************************/
void SCEUA::chkcst
(
   int nopt,
   double * x,
   double * bl,
   double * bu,
   int * ibound
)
{
   *ibound = -1;

   //Check if explicit constraints are violated
   for(int ii=1; ii<=nopt; ii++)
   {
      if ((x[ii-1] < bl[ii-1]) || (x[ii-1] > bu[ii-1])) goto label10;
   }
   if (nopt == 1) goto label9;


//     Check if implicit constraints are violated
//     (no implicit constraints for this function)
//
//     No constraints are violated
//      
label9:    *ibound = 0;
      return;

//    At least one of the constraints are violated
label10:   *ibound = 1;
      return;
}/* end chkcst() */

/******************************************************************************
InitFromFile()
Read configuration information from the given filename, then write the 
configuration info. to the file "sce.in" (maintains compatibility with SCE
fortran implementation).
******************************************************************************/
void SCEUA::InitFromFile(IroncladString pFileName)
{
   FILE * pFile;
   int i;
   char * line;
   char tmp[DEF_STR_SZ], tmp2[DEF_STR_SZ];

   //assign defaults
   m_np = m_pModel->GetParamGroupPtr()->GetNumParams();
   m_Budget = 10000; //MAXN
   m_Kstop = 5; //KSTOP
   m_Pcento = 0.01; //PCENTO
   m_Peps = 1.0E-3; //peps
   m_NumComplexes = (int)(sqrt((double)m_np)); //NGS
   m_Seed = 1969; //ISEED
   m_UserConfig = 1; //IDEFLT
   m_PtsPerComplex = 2*m_np + 1; //NPG
   m_PtsPerSubComplex = m_np+1; //NPS
   m_NumEvoSteps = m_PtsPerComplex; //NSPL
   m_MinComplexes = m_NumComplexes; //MINGS
   m_UseInitPt = 1; //INIFLG
   m_OutputMode = 2; //IPRINT
   m_bUseInitPt = false; //INIFLG

   //allocate initial parameter configuration
   ParameterGroup * pGroup = m_pModel->GetParamGroupPtr();
   m_np = pGroup->GetNumParams();
   NEW_PRINT("double", m_np);
   m_pParams = new double[m_np];
   MEM_CHECK(m_pParams);

   NEW_PRINT("double", m_np);
   m_pLower = new double[m_np];
   MEM_CHECK(m_pParams);

   NEW_PRINT("double", m_np);
   m_pUpper = new double[m_np];
   MEM_CHECK(m_pParams);

   for(i = 0; i < m_np; i++)
   {
      m_pParams[i] = pGroup->GetParamPtr(i)->GetEstVal();
      m_pLower[i] = pGroup->GetParamPtr(i)->GetLwrBnd();
      m_pUpper[i] = pGroup->GetParamPtr(i)->GetUprBnd();
   }/* end for() */

   //read in SCEUA configuration
   pFile = fopen(pFileName, "r");
   if(pFile == NULL) 
   {
      //couldn't open file, use defaults and log the error.
      LogError(ERR_FILE_IO, "Couldn't open SCEUA config. file. Using Defaults");      
      return;
   }/* end if() */   

   if(CheckToken(pFile, "RandomSeed", GetInFileName()) == true)
   {
      fclose(pFile);
      m_Seed = GetRandomSeed();
      pFile = fopen(pFileName, "r");
   }
   rewind(pFile);

   //make sure correct tokens are present
   if(CheckToken(pFile, "BeginSCEUA", pFileName) == true)
   {
      FindToken(pFile, "EndSCEUA", pFileName);
      rewind(pFile);

      FindToken(pFile, "BeginSCEUA", pFileName);
      line = GetNxtDataLine(pFile, pFileName);
      while(strstr(line, "EndSCEUA") == NULL)
      {         
         if(strstr(line, "Budget") != NULL)
         {
            sscanf(line, "%s %d", tmp, &m_Budget); 
            if(m_Budget < 100)
            {
               LogError(ERR_FILE_IO, "Invalid SCEUA budget. Defaulting to 100.");
               m_Budget = 100;
            }
         }/*end if() */
         else if(strstr(line, "LoopStagnationCriteria") != NULL)
         {
            sscanf(line, "%s %d", tmp, &m_Kstop); 
         }
         else if(strstr(line, "PctChangeCriteria") != NULL)
         {
            sscanf(line, "%s %lf", tmp, &m_Pcento); 
         }
         else if(strstr(line, "PopConvCriteria") != NULL)
         {
            sscanf(line, "%s %lf", tmp, &m_Peps); 
         }          
         else if(strstr(line, "NumComplexes") != NULL)
         {
            sscanf(line, "%s %d", tmp, &m_NumComplexes); 
         }
         else if(strstr(line, "NumPointsPerComplex") != NULL)
         {
            sscanf(line, "%s %d", tmp, &m_PtsPerComplex); 
         }
         else if(strstr(line, "NumPointsPerSubComplex") != NULL)
         {
            sscanf(line, "%s %d", tmp, &m_PtsPerSubComplex); 
         }
         else if(strstr(line, "NumEvolutionSteps") != NULL)
         {
            sscanf(line, "%s %d", tmp, &m_NumEvoSteps); 
         }
         else if(strstr(line, "MinNumOfComplexes") != NULL)
         {
            sscanf(line, "%s %d", tmp, &m_MinComplexes); 
         }
         else if(strstr(line, "UseInitialPoint") != NULL)
         {
            sscanf(line, "%s %s", tmp, tmp2); 
            MyStrLwr(tmp2);
            if(strcmp(tmp2, "yes") == 0) m_bUseInitPt = true;
         }

         else
         {
            sprintf(tmp, "Unknown token: %s", line);
            LogError(ERR_FILE_IO, tmp);
         }/* end else() */
         line = GetNxtDataLine(pFile, pFileName);
      } /* end while() */
   }/* end if() */   
   fclose(pFile);

   //create sce.in file
   int iniflg = 0;
   if(m_bUseInitPt) iniflg = 1;
   FILE * pOut = fopen("sce.in", "w");
   fprintf(pOut, "%d  %d  %lf  %d  %d  1\n", 
           m_Budget, m_Kstop, m_Pcento, m_NumComplexes, m_Seed);
   fprintf(pOut, "%d  %d  %d  %d  %d  2\n", 
           m_PtsPerComplex, m_PtsPerSubComplex, m_NumEvoSteps, m_MinComplexes, iniflg);
   for(i = 0; i < m_np; i++)
   {
      fprintf(pOut, "%E %E %E\n", m_pParams[i], m_pLower[i], m_pUpper[i]);
   }
   fclose(pOut);
} /* end InitFromFile() */

/******************************************************************************
WriteMetrics()
Write out algorithm metrics and setup.
******************************************************************************/
void SCEUA::WriteMetrics(FILE * pFile) 
{
   fprintf(pFile, "\nAlgorithm Metrics\n");
   fprintf(pFile, "Algorithm                : Shuffled Complex Evolution (SCE)\n");
   fprintf(pFile, "Budget                   : %d\n", m_Budget);
   fprintf(pFile, "Loop Stagnation Criteria : %d\n", m_Kstop); 
   fprintf(pFile, "Pct Change Criteria      : %lf\n", m_Pcento); 
   fprintf(pFile, "Number of Complexes      : %d\n", m_NumComplexes); 
   fprintf(pFile, "Points Per Complex       : %d\n", m_PtsPerComplex); 
   fprintf(pFile, "Points Per Sub-Complex   : %d\n", m_PtsPerSubComplex); 
   fprintf(pFile, "Num. of Evolution Steps  : %d\n", m_NumEvoSteps); 
   fprintf(pFile, "Min. Num. of Complexes   : %d\n", m_MinComplexes); 
  
   m_pModel->WriteMetrics(pFile);
}/* end WriteMetrics() */

/******************************************************************************
SCEUA_Program()
Calibrate or optimize the model using SCE.
******************************************************************************/
void SCEUA_Program(int argC, StringType argV[])
{
   NEW_PRINT("Model", 1);
   ModelABC * model = new Model();

   NEW_PRINT("SCEUA", 1);
   SCEUA * SCE = new SCEUA(model);
   MEM_CHECK(SCE);

   if(model->GetObjFuncId() == OBJ_FUNC_WSSE) { SCE->Calibrate(); }
   else { SCE->Optimize(); }

   delete SCE;
   delete model;
} /* end SCEUA_Program() */
  • 17
    点赞
  • 47
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
SCE-UA算法是Qingyun Duan(青云)、Soroosh Sorooshian 和Vijai Gupta等开发的一个具有复合优化策略的优化算法(Duan等,1992)。具体原理可以参考文献。笔者用C++实现了SCE-UA算法,并用常见的测试函数进行了测试! 可以访问本人的两篇博客,内有详细介绍: 【算法02 SCE-UA简介源代码 https://blog.csdn.net/weixin_43012724/article/details/121401083 【算法】03 SCE-UA算法C++实现 https://blog.csdn.net/weixin_43012724/article/details/121862991 作者: 卢家波 邮箱:lujiabo@hhu.edu.cn 版本:2021.11 创建 V1.0 版权: MIT 引用格式:卢家波,SCEUA算法C++实现. 南京:河海大学,2021. LU Jiabo, Shuffled Complex Evolution in C++. Nanjing:Hohai University, 2021. 参考文献:[1]青云,SCEUA的原始Fortran代码,1992, https://shxy.hhu.edu.cn/2019/0904/c12296a195177/page.htm [2]L. Shawn Matott改编的C++代码,2009, https://github.com/MESH-Model/MESH_Project_Baker_Creek/blob/7e0a7e588213916deb2b6c11589df0d132d9b310/Model/Ostrich/SCEUA.h [3]Van Hoey S改编的Python代码,2011 [4]Mostapha Kalami Heris, Shuffled Complex Evolution in MATLAB (URL: https://yarpiz.com/80/ypea110-shuffled-complex-evolution), Yarpiz, 2015. [5]Duan, Q.Y., Gupta, V.K. & Sorooshian, S. Shuffled complex evolution approach for effective and efficient global minimization. J Optim Theory Appl 76, 501–521 (1993). https://doi.org/10.1007/BF00939380. [6]Duan, Q., Sorooshian, S., and Gupta, V. (1992), Effective and efficient global optimization for conceptual rainfall-runoff models, Water Resour. Res., 28( 4), 1015– 1031, https://doi.org/10.1029/91WR02985. [7]Duan, Q., Sorooshian, S., & Gupta, V. K. (1994). Optimal use of the SCE-UA global optimization method for calibrating watershed models. Journal of Hydrology, 158(3-4), 265-284. https://doi.org/10.1016/0022-1694(94)90057-4. [8]王书功. 水文模型参数估计方法及参数估计不确定性研究[M]. 河南:黄河水利出版社,2010.(https://book.douban.com/subject/5377630/) [9]王书功. 水文模型参数估计方法及参数估计不确定性研究[D]. 北京:中国科学院研究生院,2006.(https://jz.docin.com/p-87849994.html)
SCE-UA(Shuffled Complex Evolution-University of Arizona)算法是一种用于参数估计和优化问题的进化算法,适于连续参数空间。源自于传统的演化算法,如遗传算法和进化策略,并结合了复杂系统中的随机性和有序性。 该算法主要针对复杂的非线性、非凸优化问题,特别适用于模型参数估计、水文学、气象学和环境科学等领域。SCE-UA算法的基本思想是通过随机生成一组不同的参数向量,并使用交叉和变异操作产生新的参数向量组成的群体。然后,根据设定的适应度函数对每个参数向量进行评估,并选择适应度较高的一部分进行下一代的繁衍。 在每一代中,SCE-UA算法通过对参数向量进行随机扰动和重排来增加群体的多样性和全局搜索能力。这种通过交换参数向量来增加多样性的操作被称为“complex shuffling”或“complexation”。 SCE-UA算法通过迭代搜索过程来不断优化参数向量,并最终找到一个逼近最优解的解集。该算法通过自适应调整步长和交叉率等参数,以平衡全局搜索和局部搜索之间的权衡。 在Matlab中,你可以使用SCE-UA算法来解决参数估计和优化问题。有一些第三方工具箱或代码库提供了SCE-UA算法的实现,如“SCE-UA Global Optimization Algorithm Toolbox”和“SCE-UA Optimization Algorithm”。 希望我对SCE-UA算法能够给你提供一些帮助!如果你有更多关于该算法的问题,可以继续问我。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

卢家波

如果对你有帮助,请我喝杯茶吧

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值