diff --git a/DESCRIPTION b/DESCRIPTION index df13e4ca97a848af32d716970f4a2dd6b658ef3e..825808e6c0bdd6299a38312d322e4557f4d8e7b8 100755 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,8 +1,8 @@ Package: hydroPSO Type: Package Title: Model-Independent Particle Swarm Optimisation for Environmental Models -Version: 0.1-56 -Date: 2012-06-14 +Version: 0.1-56-1 +Date: 2012-06-15 Author: Mauricio Zambrano-Bigiarini [aut, cre] and Rodrigo Rojas [ctb] Author@R: c(person("Mauricio", "Zambrano-Bigiarini", email = "mzb.devel@gmail.com", role=c("aut", "cre") ), person("Rodrigo", "Rojas", email = "Rodrigo.RojasMujica@gmail.com", role=c("ctb") ) ) Maintainer: Mauricio Zambrano-Bigiarini <mzb.devel@gmail.com> diff --git a/NEWS b/NEWS index a3b31b822d9688a3b21b38788270e18e9106871e..8ffc02a26f4d42379dcf446cda5915c3d3686bbe 100755 --- a/NEWS +++ b/NEWS @@ -1,6 +1,12 @@ NEWS/ChangeLog for hydroPSO -------------------------- +0.1-57 XX-Jun-2012 + o 'hydroPSO' : -) added '...' parameter. It is only used when 'fn' is different from "hydromod". This is only done for 'optim' compatibility. + -) fixed small bug related to improper PSO evolution when 'best.update'=="async" (NOT the default option !) + AND (topology!="gbest" | method!="pso") + -) source code was tidy up + 0.1-56 14-Jun-2012 o 'hydroPSO' : -) much less memory consumption for large values of 'maxit' and/or 'npart' (thanks to Paul Smith for reporting it !) The files 'BestParamPerIter.txt', 'PbestPerIter.txt', 'LocalBestPerIter.txt', 'Velocities.txt' are now written at the end of diff --git a/R/PSO_v2012.R b/R/PSO_v2012.R index 4be491e23e0ed205de394ce994555b6040ced10c..5de6ac4111cbb93e0cbf5f1c216e63b39ea3e9fb 100755 --- a/R/PSO_v2012.R +++ b/R/PSO_v2012.R @@ -1104,7 +1104,7 @@ Random.Topology.Generation <- function(npart, K, # Updates: Dec-2010 # # May-2011 ; 28-Oct-2011 ; 14-Nov-2011 ; 23-Nov-2011 ; # # 15-Jan-2012 ; 23-Jan-2012 ; 30-Jan-2012 ; 23-Feb-2012 ; 23-Mar-2012 # -# 14-Jun-2012 # +# 14-Jun-2012 ; 15-Jun-2012 # ################################################################################ # 'lower' : minimum possible value for each parameter # 'upper' : maximum possible value for each parameter @@ -1326,6 +1326,7 @@ Random.Topology.Generation <- function(npart, K, hydroPSO <- function( par, fn="hydromod", + ..., method=c("pso", "ipso", "fips", "wfips"), lower=-Inf, upper=Inf, @@ -2045,13 +2046,48 @@ hydroPSO <- function( X.neighbours <- Random.Topology.Generation(npart, K, drty.out, iter) ModelOut <- vector("list", npart) + + # IW: linear, non-linear, runif + if (!use.IW) { + w <- 1 + } else { + if ( (IW.type == "linear") | (IW.type == "non-linear") ) { + w <- compute.value.with.iter(iter=iter.tv, niter=niter.tv, + nexp=IW.exp, val.ini=w.ini, + val.fin=w.fin) + } else if (IW.type == "runif") { + w <- runif(1, min=w.ini, max=w.fin) + } # ELSE end + } # ELSE end + + # TVc1: linear, non-linear + if ( (use.TVc1) & (TVc1.type != "GLratio") ) { + if ( (TVc1.type == "linear") | (TVc1.type == "non-linear") ) + c1 <- compute.value.with.iter(iter=iter.tv, niter=niter.tv, + nexp=TVc1.exp, val.ini=c1.ini, + val.fin=c1.fin) + } # If end + + # TVc2 + if (use.TVc2) + c2 <- compute.value.with.iter(iter=iter.tv, niter=niter.tv, + nexp=TVc2.exp, val.ini=c2.ini, + val.fin=c2.fin) + + # lambda + if (use.TVlambda) { + lambda <- compute.value.with.iter(iter=iter.tv, niter=niter.tv, + nexp=TVlambda.exp, val.ini=vmax.ini, + val.fin=vmax.fin) + Vmax <- lambda*Lmax + } # IF end ########################################################################## # 3.a) Evaluate the particles fitness if ( fn.name != "hydromod" ) { # Evaluating a Test Function - Xt.fitness[iter, 1:npart] <- apply(X, fn, MARGIN=1) + Xt.fitness[iter, 1:npart] <- apply(X, fn, MARGIN=1, ...) GoF <- Xt.fitness[iter, 1:npart] ModelOut[1:npart] <- GoF ### @@ -2077,9 +2113,9 @@ hydroPSO <- function( model.FUN.args <- modifyList(model.FUN.args, list(param.values=X[part,]) ) hydromod.out <- do.call(model.FUN, as.list(model.FUN.args)) - Xt.fitness[iter, part] <- as.numeric(hydromod.out[["GoF"]]) - GoF <- Xt.fitness[iter, part] - ModelOut[[part]] <- hydromod.out[["sim"]] + Xt.fitness[iter, part] <- as.numeric(hydromod.out[["GoF"]]) + GoF <- Xt.fitness[iter, part] + ModelOut[[part]] <- hydromod.out[["sim"]] if(is.finite(GoF)) nfn <- nfn + 1 @@ -2130,51 +2166,28 @@ hydroPSO <- function( X.best.part <- tmp[["x.best"]] gbest.fit <- tmp[["gbest.fit"]] gbest.pos <- tmp[["gbest.pos"]] - - } # IF end - - - suppressWarnings(ifelse(MinMax=="max", pbest.fit.iter <- max( Xt.fitness[iter, ], na.rm=TRUE ), - pbest.fit.iter <- min( Xt.fitness[iter, ], na.rm=TRUE) ) ) - - tmp <- UpdateLocalBest(pbest.fit=pbest.fit, + + tmp <- UpdateLocalBest(pbest.fit=pbest.fit, localBest.pos=LocalBest.pos, localBest.fit=LocalBest.fit, x.neighbours=X.neighbours, MinMax=MinMax) - LocalBest.fit <- tmp[["localBest.fit"]] - LocalBest.pos <- tmp[["localBest.pos"]] - - if ( method == "ipso" ) { - tmp <- UpdateNgbest(pbest.fit=pbest.fit, - ngbest=ngbest, - MinMax=MinMax) - ngbest.fit <- tmp[["ngbest.fit"]] - ngbest.pos <- tmp[["ngbest.pos"]] - } # IF end - - GPbest.fit.rate <- mean(pbest.fit, na.rm=TRUE) - ifelse( (is.finite(GPbest.fit.rate) ) & ( GPbest.fit.rate !=0 ), - GPbest.fit.rate <- abs( ( gbest.fit - GPbest.fit.rate ) / GPbest.fit.rate ), - GPbest.fit.rate <- +Inf) + LocalBest.fit <- tmp[["localBest.fit"]] + LocalBest.pos <- tmp[["localBest.pos"]] - ifelse( (gbest.fit.prior != 0) & (is.finite(gbest.fit.prior) ) , - gbest.fit.rate <- abs( ( gbest.fit - gbest.fit.prior ) / gbest.fit.prior ), - gbest.fit.rate <- +Inf) - - out <- ComputeSwarmRadiusAndDiameter(x=X, gbest= X.best.part[gbest.pos, ], Lmax=Lmax, - MinMax=MinMax, pbest.fit=pbest.fit) - swarm.radius <- out[["swarm.radius"]] - swarm.diameter <- out[["swarm.diameter"]] - NormSwarmRadius <- swarm.radius/swarm.diameter + if ( method == "ipso" ) { + tmp <- UpdateNgbest(pbest.fit=pbest.fit, + ngbest=ngbest, + MinMax=MinMax) + ngbest.fit <- tmp[["ngbest.fit"]] + ngbest.pos <- tmp[["ngbest.pos"]] + } # IF end - if ( (verbose) & ( iter/REPORT == floor(iter/REPORT) ) ) - message( "iter:", format(iter, width=6, justify="right"), - " Gbest:", formatC( gbest.fit, format="E", digits=digits, flag=" "), - " Gbest_rate:", format( round(gbest.fit.rate*100, 2), width=6, nsmall=2, justify="left"), "%", - " Iter_best_fit:", formatC(pbest.fit.iter, format="E", digits=digits, flag=" "), - " nSwarm_Radius:", formatC(NormSwarmRadius, format="E", digits=digits, flag=" "), - " |g-mean(p)|/mean(p):", format( round(GPbest.fit.rate*100, 2), width=6, nsmall=2, justify="left"), "%" ) + } # IF end + + # 'X.bak' is only needed to correctly compute the Normalised Swarm Radious + # for the current iteration + X.bak <- X ########################################################################## ################### Particles Loop (j) - Start ######################## @@ -2183,8 +2196,9 @@ hydroPSO <- function( if (write2disk) { - # File 'Model_Out.txt' GoF <- Xt.fitness[iter, j] + + # File 'Model_Out.txt' if(is.finite(GoF)) { writeLines(as.character(c(iter, j, formatC(GoF, format="E", digits=digits, flag=" "), @@ -2194,9 +2208,9 @@ hydroPSO <- function( writeLines("", OFout.Text.file) # File 'Particles.txt' # - if(is.finite(Xt.fitness[iter, j])) { + if(is.finite(GoF)) { writeLines(as.character( c(iter, j, - formatC(Xt.fitness[iter, j], format="E", digits=digits, flag=" "), #GoF + formatC(GoF, format="E", digits=digits, flag=" "), #GoF formatC(X[j, ], format="E", digits=digits, flag=" ") ) ), Particles.TextFile, sep=" ") } else writeLines(as.character( c(iter, j, "NA", @@ -2205,9 +2219,9 @@ hydroPSO <- function( writeLines("", Particles.TextFile) # File 'Velocities.txt' # - if(is.finite(Xt.fitness[iter, j])) { + if(is.finite(GoF)) { writeLines( as.character( c(iter, j, - formatC(Xt.fitness[iter, j], format="E", digits=digits, flag=" "), # GoF + formatC(GoF, format="E", digits=digits, flag=" "), # GoF formatC(V[j, ], format="E", digits=digits, flag=" ") ) ), Velocities.TextFile, sep=" ") } else writeLines( as.character( c(iter, j, "NA", @@ -2233,16 +2247,30 @@ hydroPSO <- function( X.best.part[j,] <- tmp[["x.best"]] gbest.pos <- tmp[["gbest.pos"]] gbest.fit <- tmp[["gbest.fit"]] + + tmp <- UpdateLocalBest(pbest.fit=pbest.fit, + localBest.pos=LocalBest.pos, + localBest.fit=LocalBest.fit, + x.neighbours=X.neighbours, + MinMax=MinMax) + LocalBest.fit <- tmp[["localBest.fit"]] + LocalBest.pos <- tmp[["localBest.pos"]] - } # IF end - + if ( method == "ipso" ) { + tmp <- UpdateNgbest(pbest.fit=pbest.fit, + ngbest=ngbest, + MinMax=MinMax) + ngbest.fit <- tmp[["ngbest.fit"]] + ngbest.pos <- tmp[["ngbest.pos"]] + } # IF end - if (use.IW) { - if ( (IW.type == "linear") | (IW.type == "non-linear") ) { - w <- compute.value.with.iter(iter=iter.tv, niter=niter.tv, - nexp=IW.exp, val.ini=w.ini, - val.fin=w.fin) - } else if (IW.type == "aiwf") { + } # IF end + + ### IW, TVc1, Tv2, lambda + + # IW: aiwf, GLratio + if (use.IW) { + if (IW.type == "aiwf") { w <- compute.w.aiwf(iter.fit= Xt.fitness[iter, ], particle.pos =j, gbest.fit=gbest.fit, @@ -2251,34 +2279,15 @@ hydroPSO <- function( MinMax=MinMax ) - } else if (IW.type == "GLratio") { + } else if (IW.type == "GLratio") { w <- compute.w.with.GLratio(MinMax, gbest.fit, pbest.fit) - } else if (IW.type == "runif") { - w <- runif(1, min=w.ini, max=w.fin) - } # ELSE end - } else w <- 1 - - if (use.TVc1) { - if ( (TVc1.type == "linear") | (TVc1.type == "non-linear") ) { - c1 <- compute.value.with.iter(iter=iter.tv, niter=niter.tv, - nexp=TVc1.exp, val.ini=c1.ini, - val.fin=c1.fin) - } else if (TVc1.type == "GLratio") { - c1 <- compute.c1.with.GLratio(MinMax, gbest.fit, pbest.fit[j]) - } # ELSE IF end - } # If end - - if (use.TVc2) - c2 <- compute.value.with.iter(iter=iter.tv, niter=niter.tv, - nexp=TVc2.exp, val.ini=c2.ini, - val.fin=c2.fin) - - if (use.TVlambda) { - lambda <- compute.value.with.iter(iter=iter.tv, niter=niter.tv, - nexp=TVlambda.exp, val.ini=vmax.ini, - val.fin=vmax.fin) - Vmax <- lambda*Lmax - } # IF end + } # ELSE end + } # IF end + + + # TVc1: GLratio + if ( (use.TVc1) & (TVc1.type == "GLratio") ) + c1 <- compute.c1.with.GLratio(MinMax, gbest.fit, pbest.fit[j]) ######################################################################## # 3.b) Updating the velocity of all the particles @@ -2318,8 +2327,34 @@ hydroPSO <- function( ########################################################################## ################### Particles Loop (j) - End ########################## ########################################################################## - + gbest.fit.iter[iter] <- gbest.fit + + suppressWarnings(ifelse(MinMax=="max", pbest.fit.iter <- max( Xt.fitness[iter, ], na.rm=TRUE ), + pbest.fit.iter <- min( Xt.fitness[iter, ], na.rm=TRUE) ) ) + + GPbest.fit.rate <- mean(pbest.fit, na.rm=TRUE) + ifelse( (is.finite(GPbest.fit.rate) ) & ( GPbest.fit.rate !=0 ), + GPbest.fit.rate <- abs( ( gbest.fit - GPbest.fit.rate ) / GPbest.fit.rate ), + GPbest.fit.rate <- +Inf) + + ifelse( (gbest.fit.prior != 0) & (is.finite(gbest.fit.prior) ) , + gbest.fit.rate <- abs( ( gbest.fit - gbest.fit.prior ) / gbest.fit.prior ), + gbest.fit.rate <- +Inf) + + out <- ComputeSwarmRadiusAndDiameter(x=X.bak, gbest= X.best.part[gbest.pos, ], Lmax=Lmax, + MinMax=MinMax, pbest.fit=pbest.fit) + swarm.radius <- out[["swarm.radius"]] + swarm.diameter <- out[["swarm.diameter"]] + NormSwarmRadius <- swarm.radius/swarm.diameter + + if ( (verbose) & ( iter/REPORT == floor(iter/REPORT) ) ) + message( "iter:", format(iter, width=6, justify="right"), + " Gbest:", formatC( gbest.fit, format="E", digits=digits, flag=" "), + " Gbest_rate:", format( round(gbest.fit.rate*100, 2), width=6, nsmall=2, justify="left"), "%", + " Iter_best_fit:", formatC(pbest.fit.iter, format="E", digits=digits, flag=" "), + " nSwarm_Radius:", formatC(NormSwarmRadius, format="E", digits=digits, flag=" "), + " |g-mean(p)|/mean(p):", format( round(GPbest.fit.rate*100, 2), width=6, nsmall=2, justify="left"), "%" ) ########################################################################## # Random Generation around gbest, if requested # diff --git a/man/hydroPSO.Rd b/man/hydroPSO.Rd index 56f2d1f834dd2cd752493f93f5f06445743abd8f..5ccd7ccc689002d84424aef482e3d067992aa474 100755 --- a/man/hydroPSO.Rd +++ b/man/hydroPSO.Rd @@ -14,7 +14,7 @@ Enhanced Particle Swarm Optimisation algorithm Particle Swarm Optimisation algorithm to calibrate environmental models. It includes a series of controlling options and PSO variants to improve the performance of the algorithm and customize it to different calibration problems } \usage{ -hydroPSO(par, fn= "hydromod", method=c("pso", "ipso", "fips", "wfips"), +hydroPSO(par, fn= "hydromod", ..., method=c("pso", "ipso", "fips", "wfips"), lower=-Inf, upper=Inf, control=list(), model.FUN=NULL, model.FUN.args=list() ) } @@ -25,8 +25,13 @@ OPTIONAL. numeric with a first guess for the parameters to be optimised (\env{n} All the particles are randomly initialised according to the value of \code{Xini.type}. If the user provides \env{m} parameter sets for \code{par}, they are used to overwrite the first \env{m} parameter sets randomly defined according to the value of \code{Xini.type}. If some elements in \code{par} are non finite (lower than \code{lower} or larger than \code{upper}) they are ignored \cr } \item{fn}{ -character, name of a valid R function \code{c('sphere','ackley','griewank','rastrigin','rosenbrock','schafferF6')} to be optimised or character value \sQuote{'hydromod'}. When \code{fn='hydromod'} the algorithm uses \code{model.FUN} and \code{model.FUN.args} to extract the values simulated by the model and to compute its corresponding goodness-of-fit function. When \code{fn!='hydromod'} the algorithm uses the value(s) returned by \code{fn} as both model output and its corresponding goodness-of-fit \cr -When \code{fn='hydromod'} the algorithm will optimise the model defined by \code{model.FUN} and \code{model.args} +character, name of a valid R function to be optimised (minimized or maximized) or the character value \sQuote{'hydromod'}. \cr +-) When \code{fn!='hydromod'}, the first argument of \code{fn} has to be a vector of parameters over which optimisation is to take place. It should return a scalar result. When \code{fn!='hydromod'} the algorithm uses the value(s) returned by \code{fn} as both model output and its corresponding goodness-of-fit measure. \cr +-) When \code{fn=='hydromod'} the algorithm will optimise the model defined by \code{model.FUN} and \code{model.args}, which are used to extract the values simulated by the model and to compute its corresponding goodness-of-fit measure. +} +\item{\dots}{ +OPTIONAL. Only used when \code{fn!='hydromod'}. \cr +further arguments to be passed to \code{fn}. } \item{method}{ character, variant of the PSO algorithm to be used. Valid values are in \code{c('pso', 'ipso', 'fips', 'wfips')}: \cr @@ -37,9 +42,6 @@ character, variant of the PSO algorithm to be used. Valid values are in \code{c( \kbd{wfips}: same implementation as \kbd{fips} method, but the contribution of each particle is weighted according to their goodness-of-fit value (see Mendes et al., 2004) \cr By default \code{method=pso} } -%%\item{\dots}{ -%%further arguments to be passed to \code{fn} -%%} \item{lower}{ numeric, lower boundary for each parameter \cr Note for \code{\link[stats]{optim}} users: in \kbd{hydroPSO} the length of \code{lower} and \code{upper} are used to defined the dimension of the solution space