-
Mauricio Zambrano-Bigiarini authored
'hydroPSO': immproved checking of some arguments; 'random.update' only used when 'best.update'=async, and more and better examples. 'text\_functions': corrected name of the 'rastringin' function, and corrected definition of the 'shafferF6' function
Mauricio Zambrano-Bigiarini authored'hydroPSO': immproved checking of some arguments; 'random.update' only used when 'best.update'=async, and more and better examples. 'text\_functions': corrected name of the 'rastringin' function, and corrected definition of the 'shafferF6' function
PSO_v2012.R 123.91 KiB
# File PSO_v2012.R
# Part of the hydroPSO package, http://www.rforge.net/hydroPSO/
# Copyright 2008-2012 Mauricio Zambrano-Bigiarini
# Distributed under GPL 2 or later
################################################################################
## Random.Bounded.Matrix ##
################################################################################
# Author : Mauricio Zambrano-Bigiarini ##
################################################################################
# Created: 2008 ##
# Updates: 23-Nov-2010 ##
################################################################################
# Purpose : To create a matrix randomly generated, with a bounded uniform distribution
# 'npart' : number of particles in the swarm
# 'X.MinMax': Matrix of 'n' rows and 2 columns,
# the first column has the minimum values for each dimension, and
# the second column has the maximum values for each dimension
Random.Bounded.Matrix <- function(npart, x.MinMax) {
# dimension of the solution space (number of parameters )
n <- nrow(x.MinMax)
lower <- x.MinMax[,1]
upper <- x.MinMax[,2]
##x <- lower + (upper-lower)*matrix(runif(n*npart,0,1), nrow=npart, ncol=n)
# random initialization for all the particles, with a value in [0,1]
X <- matrix(runif(n*npart,0,1), nrow=npart, ncol=n)
# Transforming X into the real range defined by the user
X <- t( lower + (upper - lower )*t(X) )
return(X)
} # 'Random.Bounded.Matrix2' end
#Random.Bounded.Matrix(10, X.MinMax)
################################################################################
## random Latin-Hypercube Sampling ##
################################################################################
# Author: Mauricio Zambrano-Bigiarini
# Created: 17-Dec-2010
# Updates:
################################################################################
# Purpose : Draws a Latin Hypercube Sample from a set of uniform distributions
# for use in creating a Latin Hypercube Design
################################################################################
# Output : An n by ndim Latin Hypercube Sample matrix with values uniformly
# distributed on [0,1]
################################################################################
# 'n' : number of strata used to divide each parameter range
# 'ranges' : Matrix of 'N' rows and 2 columns, (N is the number of parameters)
# the first column has the minimum values for each dimension, and
# the second column has the maximum values for each dimension
rLHS <- function(n, ranges) {
# dimension of the solution space (number of parameters )
ndim <- nrow(ranges)
lower <- ranges[,1]
upper <- ranges[,2]
### LHS initialization for all the particles
##require(lhs)
##X <- lower + (upper-lower)*randomLHS(n, ndim)
# LHS initialization for all the particles, with a value in [0,1]
require(lhs)
X <- randomLHS(n, ndim)
# Transforming X into the real range defined by the user
X <- t( lower + (upper - lower )*t(X) )
return(X)
} # 'rLHS' end
################################################################################
# compute.CF Function #
################################################################################
# Author : Mauricio Zambrano-Bigiarini #
################################################################################
# Created: 2008 #
# Updates: #
################################################################################
# Computes the Clerc's Constriction Factor
# Clerc, M.; Kennedy, J.; , "The particle swarm - explosion, stability, and
# convergence in a multidimensional complex space," Evolutionary Computation,
# IEEE Transactions on , vol.6, no.1, pp.58-73, Feb 2002
# doi: 10.1109/4235.985692
compute.CF <- function(c1, c2) {
psi <- c1 + c2 # psi >= 4
CF <- 2 / abs( 2 - psi - sqrt(psi^2 - 4*psi) )
} # 'compute.CF' end
# 'x' : vector of 'n' parameters, corresponding to one particle
# 'v' : vector of 'n' velocities of each parameter, corresponding to the current particle
# 'vmax.perc' : percentage of the range of each dimension that is allowed as
# maximum velocity in that dimension
# 'Pbest' : matrix with the current best parameter values for all the particles
# 'gbest' : vector with the best parameter values in the swarm
# 'w' : Inertial factor.
# 'c1' : constant that encourages the exploration of the solution space
# 'c2' : constant that encourages the exploitation of the current global best
# 'CF' : constant representing the Clerk's Constriction Factor,to insure convergence of the PSO algorithm
# 'x.MinMax' : Matrix with the valid range for each parameter of 'X'.
# Rows = 'n' (number of parameter
# Columns = 2,
# First column has the minimum possible value for each parameter
# Second column has the maximum possible value for each parameter
# 'topology' : character, with the topology to be used in PSO. Valid values
# are in c('gbest', 'lbest')
# 'method' : character, with the method to be used as PSO algorithm. Valid values
# are in c('pso', 'ipso', 'fips', 'wfips')
# Result : vector of 'n' velocities, one for each parameter, corresponding to the current particle
################################################################################
## compute.veloc Function ##
################################################################################
# Author : Mauricio Zambrano-Bigiarini #
################################################################################
# Created: 2008 #
# Updates: Oct-2011 ; Nov-2011 #
################################################################################
compute.veloc <- function(x, v, w, c1, c2, CF, Pbest, part.index, gbest,
topology, method, MinMax, neighs.index,
localBest, localBest.pos,
ngbest.fit, ngbest, lpbest.fit) {
pbest <- Pbest[part.index, ]
# dimension of 'x' (number of parameters)
n <- length(gbest)
r1 <- runif(n, min=0, max=1)
r2 <- runif(n, min=0, max=1)
if ( method=="pso" ) {
ifelse(part.index != localBest.pos,
vn <- CF * ( w*v + r1*c1*(pbest-x) + r2*c2*(localBest-x) ),
vn <- CF * ( w*v + r1*c1*(pbest-x) ) )
} else if ( method=="ipso" ) {
# number of best particles that have to be considered
nngbest <- length(ngbest.fit)
R2 <- matrix(rep(r2,nngbest), nrow=nngbest, byrow=TRUE)
# computing the c2 values for each one of the best particles,
# weighted according to their fitness value
ifelse(MinMax == "min", c2i <- c2 * ( (1/ngbest.fit)/sum(1/ngbest.fit) ),
c2i <- c2 * ( ngbest.fit/sum(ngbest.fit) )
)
# transforming 'x' into a matrix, with the same values in each row, in
# order to be able to substract 'x' from 'ngest'
X <- matrix(rep(x, nngbest), ncol=n, byrow=TRUE)
# computing the velocity
vn <- CF * ( w*v + r1*c1*(pbest-x) + colSums(R2*c2i*(ngbest-X) ) )
} else if ( method=="fips" ) {
neighs.index <- neighs.index[!is.na(neighs.index)] # only for topology=='random'
N <- length(neighs.index)
X <- matrix(rep(x,N), nrow=N, byrow=TRUE)
P <- Pbest[neighs.index, ]
phi <- c1 + c2
r <- runif(N, min=0, max=phi)
vn <- CF * ( w*v + (1/N)*colSums( r*(P-X) ) )
} else if ( method=="wfips" ) {
neighs.index <- neighs.index[!is.na(neighs.index)] # only for topology=='random'
N <- length(neighs.index)
X <- matrix(rep(x,N), nrow=N, byrow=TRUE)
P <- Pbest[neighs.index, ]
pfit <- lpbest.fit[neighs.index]
phi <- c1 + c2
r <- runif(N, min=0, max=phi)
ifelse(MinMax == "min", wght <- (1/lpbest.fit)/sum(1/lpbest.fit),
wght <- lpbest.fit/sum(lpbest.fit)
)
vn <- CF * ( w*v + (1/N) * colSums( wght*r*(P-X) ) )
} # ELSE end
return(vn)
} # 'compute.veloc' end
################################################################################
## roll.vector Function ##
################################################################################
# Author : Mauricio Zambrano-Bigiarini #
################################################################################
# Created: 2009 #
# Updates: #
################################################################################
# 'old.vector': vector of length 'L' that will be rolled
# 'new.value' : real that will be put at the end of 'old.vector'
# Result: a vector with elements x.new[i] = x.old[i+1], i=1,L-1, x.new[L]= 'new.value'
roll.vector <- function(old.vector, new.value) {
tmp <- old.vector
L <- length(old.vector)
tmp[1:(L-1)] <- old.vector[2:L]
tmp[L] <- new.value
return(tmp)
} # 'roll.vector' end
################################################################################
## compute.value.with.iter Function ##
################################################################################
# Author : Mauricio Zambrano-Bigiarini #
################################################################################
# Created: 2008 #
# Updates: #
################################################################################
# 'iter' : the current iteration number
# 'niter' : maximum number of iteration that can be done within a single run
# 'nexp' : nonlinear modulation index
# 'val.ini' : initial inertial weight at the start of a given run
# 'val.fin' : fiinal inertial weight at the end of a given run
# Result : Nonlinear modulated inertial weight
compute.value.with.iter <- function(iter, niter, nexp, val.ini, val.fin) {
w <- ( ( (niter - iter) / niter )^nexp ) * ( val.ini - val.fin) + val.fin
return(w)
} # 'compute.value.with.iter' end
################################################################################
## compute.w.aiwf Function ##
## Adaptive inertial weight factor (AIWF) ##
################################################################################
# Author : Mauricio Zambrano-Bigiarini
################################################################################
# Started: 2008
# Updates: 24-Nov-2011
################################################################################
# Reference:
# According to Liu et al., 2005 ("Improved Particle Swarm Combined with Caos")
# B. Liu, et al., "An improved particle swarm optimization combined with chaos,"
# Chaos, Solitons and Fractals, vol. 25, pp. 1261-1271, 2005.
# 'iter.fit' : vector with 'n.particles' values corresponding to the fitness
# obtained in the current iteration for each one of the particles
# 'particle.pos': position of the particle, for identifying it
# 'gbest.fit' : number with the best fitness found so far, considering all the particles
# 'w.max' : initial inertial weight at the start of a given run (maximum value)
# 'w.min' : final inertial weight at the end of a given run (minimum value)
# 'MinMax' : string indicating if PSO have to find a minimum or a maximum for the fitness function.
# valid values are: "min", "max"
# Result : Adaptive inertial weight factor (AIWF)
compute.w.aiwf <- function(iter.fit, particle.pos, gbest.fit, w.max, w.min, MinMax) {
# 'f' : fitness value of the particle in the current iteration
f <- iter.fit[particle.pos]
# 'f.avg': mean fitness value of all the particles in the current iteration
f.avg <- mean(iter.fit, na.rm=TRUE)
# 'f.min': best fitness value of all the particles in the current iteration
ifelse(MinMax == "min", f.min <- min(iter.fit, na.rm=TRUE), f.min <- max(iter.fit, na.rm=TRUE) )
ifelse(MinMax == "min", to.apply <- (f <= f.avg), to.apply <- (f >= f.avg) )
if (to.apply) {
w <- w.min + ( ( (w.max - w.min) * abs(f - f.min) ) / abs(f.avg - f.min) )
} else w <- w.max
return(w)
} # 'compute.w.aiwf' end
################################################################################
## compute.w.with.GLratio Function ##
################################################################################
# Author : Mauricio Zambrano-Bigiarini #
################################################################################
# Started: 23-Dec-2010 #
# Updates: #
################################################################################
compute.w.with.GLratio <- function(MinMax, gbest.fit, pbest.fit) {
# If we are Minimizing, the ratio 'gbest/pbest' have to be less than 1,
# and the closer to 1, the closer the particle to 'gbest'
ifelse(MinMax == "min",
w <- 1.1 - ( gbest.fit / mean(pbest.fit) ),
w <- 1.1 - ( mean(pbest.fit) / gbest.fit )
)
return(w)
} # 'compute.w.with.GLratio' END
################################################################################
## compute.c1.with.GLratio Function ##
################################################################################
# Author : Mauricio Zambrano-Bigiarini #
################################################################################
# Started: 27-Dec-2010 #
# Updates: #
################################################################################
# Based on M. Senthil Arumugam and M.V.C. Rao; 2008. Applied Soft Computing
# "On the improved Performances of the particle swarm optimization algorithms
# with adaptive parameters, cross-over operators and root mean square (RMS)
# variants for computing optimal control of a class of hybrid systems"
# 'gbest.fit': global best objective function
# 'pbest.fit': best objective function of the current particle
compute.c1.with.GLratio <- function(MinMax, gbest.fit, pbest.fit) {
# If we are Minimizing, the ratio 'gbest/pbest' have to be less than 1,
# and the closer to 1, the closer the particle to 'gbest'
ifelse(MinMax == "min",
c1 <- 1.0 + ( gbest.fit / pbest.fit ),
c1 <- 1.0 + ( pbest.fit / gbest.fit )
)
return(c1)
} # 'compute.c1.with.GLratio' END
################################################################################
## velocity.boundary.treatment Function ##
################################################################################
# Author : Mauricio Zambrano-Bigiarini #
################################################################################
# Started: 2008 #
# Updates: #
################################################################################
# 'x' : vector of 'n' parameters, corresponding to one particle
# 'n' : dimension of the solution space (number of parameters)
# 'X.MinMax' : string indicating if PSO have to find a minimum or a maximum
# for the fitness function.
# valid values are: "min", "max"
# 'v' : vector of 'n' velocities of each parameter, corresponding to
# the current particle
# 'boundary.wall' : boundary treatment that is used to limit the sea
# the limits given by 'X.MinMax'.
# Valid values are: 'absorbing', 'reflecting' and 'invisible'
# Result : vector of 'n' velocities, one for each parameter,
# corresponding to the current particle
velocity.boundary.treatment <- function(v, vmax ) {
byd.vmax.pos <- which( abs(v) > vmax )
if ( length(byd.vmax.pos) > 0 )
v[byd.vmax.pos] <- sign(v[byd.vmax.pos])*abs(vmax[byd.vmax.pos])
return(v)
} # 'velocity.boundary.treatment' end
################################################################################
## position.update.and.boundary.treatment Function ##
################################################################################
# Author : Mauricio Zambrano-Bigiarini #
################################################################################
# Started: 2008 #
# Updates: #
################################################################################
# 'x' : vector of 'n' parameters, corresponding to one particle
# 'X.MinMax' : string indicating if PSO have to find a minimum or a maximum
# for the fitness function.
# valid values are: "min", "max"
# 'v' : vector of 'n' velocities of each parameter, corresponding to
# the current particle
# 'boundary.wall' : boundary treatment that is used to limit the sea
# the limits given by 'X.MinMax'.
# Valid values are: 'absorbing', 'reflecting', 'invisible', 'damping'
# Result : vector of 'n' velocities, one for each parameter,
# corresponding to the current particle
# References:
# Robinson, J.; Rahmat-Samii, Y.; Particle swarm optimization in electromagnetics.
# Antennas and Propagation, IEEE Transactions on , vol.52, no.2, pp. 397-407,
# Feb. 2004. doi: 10.1109/TAP.2004.823969
# Huang, T.; Mohan, A.S.; , A hybrid boundary condition for robust particle
# swarm optimization. Antennas and Wireless Propagation Letters, IEEE , vol.4,
# no., pp. 112-117, 2005. doi: 10.1109/LAWP.2005.846166
position.update.and.boundary.treatment <- function(x, v, x.MinMax, boundary.wall) {
# dimension of 'x' (number of parameters)
n <- nrow(x.MinMax)
# Vector with the new positions of the current particle
x.new <- x + v
# By default the new velocity is assumed not to be limited
v.new <- v
# Minimum and maximum values for each dimension
x.min <- x.MinMax[,1]
x.max <- x.MinMax[,2]
byd.min.pos <- which(x.new < x.min)
if ( length(byd.min.pos) > 0) {
if ( boundary.wall == "absorbing") {
x.new[byd.min.pos] <- x.min[byd.min.pos]
v.new[byd.min.pos] <- 0*v[byd.min.pos]
} else if ( boundary.wall == "reflecting") {
x.new[byd.min.pos] <- 2*x.min[byd.min.pos] - x.new[byd.min.pos]
v.new[byd.min.pos] <- v[byd.min.pos]
} else if ( boundary.wall == "invisible") {
x.new[byd.min.pos] <- x[byd.min.pos]
v.new[byd.min.pos] <- v[byd.min.pos]
} else if ( boundary.wall == "damping") {
L <- abs( x.min[byd.min.pos] - x.new[byd.min.pos] )
x.new[byd.min.pos] <- x.min[byd.min.pos] + runif(1)*L
v.new[byd.min.pos] <- v[byd.min.pos]
}# ELSE end
} # IF end
byd.max.pos <- which( x.new > x.max )
if ( length(byd.max.pos) > 0 ) {
if ( boundary.wall == "absorbing") {
x.new[byd.max.pos] <- x.max[byd.max.pos]
v.new[byd.max.pos] <- 0*v[byd.max.pos]
} else if ( boundary.wall == "reflecting") {
x.new[byd.max.pos] <- 2*x.max[byd.max.pos] - x.new[byd.max.pos]
v.new[byd.max.pos] <- v[byd.max.pos]
} else if ( boundary.wall == "invisible") {
x.new[byd.max.pos] <- x[byd.max.pos]
v.new[byd.max.pos] <- v[byd.max.pos]
} else if ( boundary.wall == "damping") {
L <- abs( x.new[byd.max.pos] - x.max[byd.max.pos])
x.new[byd.max.pos] <- x.max[byd.max.pos] - runif(1)*L
v.new[byd.max.pos] <- v[byd.max.pos]
}# ELSE end
} # IF end
out <- list(x.new=x.new, v.new=v.new)
return(out)
} # 'position.update.and.boundary.treatment' end
################################################################################
## async.update.pgbests Function ##
################################################################################
## Author : Mauricio Zambrano-Bigiarini ##
################################################################################
## Started: 2008 ##
## Updated: 26-Jan-2012 ##
################################################################################
# Function for updating the values of 'pbest', 'x.best', 'gbest.fit' and 'gbest.pos'
# for ONLY 1 particle !!
# 'x' : vector with the 'n' parameters of a single particle
# 'x.pos' : position of the current particle
# 'xt.fitness' : particle's fitness
# 'MinMax' : string indicating if PSO have to find a minimum or a maximum
# for the fitness function.
# valid values are: "min", "max"
# 'of.name' : function that will be used for computing the fitness.
# 'l.pbest.fit' : best fitness value found by the particle so far.
# 'gbest.fit' : best fitness value found by the swarm so far.
# 'gbest.pos' : position of the particle corresponding to 'gbest.fit'.
# 'x.best' : 'n' values corresponding to the parameters of the particle
# that achieve the best fitness value for the particle
# Result : a list of 4 components (this values are different of the input ones,
# only if the new values provide a better fitness value )
# : 1: pbest : real with the new best fitness value of the particle
# : 2: x.best : vector with the new 'n' best parameters for the particle
# : 3: gbest.fit : real with the new best fitness value for the swarm
# : 4: gbest.pos : integer with the location of the particle that has
# the best fitness value in the swarm
async.update.pgbests <- function(x,
x.pos,
xt.fitness,
MinMax,
l.pbest.fit,
gbest.fit,
gbest.pos,
x.best
) {
ifelse(MinMax == "max", l.update <- which(xt.fitness > l.pbest.fit ),
l.update <- which(xt.fitness < l.pbest.fit ) )
# Updating 'pbest.fit', 'gbest.fit', 'gbest.pos' and 'x.best.part'
if ( length(l.update>0) ) {
# 'pbest.fit': updating the value of the best fit of the particles
l.pbest.fit <- xt.fitness
# 'X.best' updating
x.best <- x
# 'gbest.fit': updating the value of the best global fit
# 'gbest.pos': updating the position of the particle with the best global fit
if ( MinMax=="max" ) {
if ( l.pbest.fit > gbest.fit ) {
gbest.fit <- l.pbest.fit
gbest.pos <- x.pos
} # IF end
} else if ( MinMax=="min" ) {
if ( l.pbest.fit < gbest.fit ) {
gbest.fit <- l.pbest.fit
gbest.pos <- x.pos
} # IF end
} # ELSE end
} # IF end
tmp <- list(4)
tmp[[1]] <- l.pbest.fit
tmp[[2]] <- x.best
tmp[[3]] <- gbest.fit
tmp[[4]] <- gbest.pos
names(tmp) <- c("pbest", "x.best", "gbest.fit", "gbest.pos")
return(tmp)
} # 'async.update.pgbests' end
################################################################################
## sync.update.pgbests Function ##
################################################################################
## Author : Mauricio Zambrano-Bigiarini ##
################################################################################
## Started: 2008 ##
## Updated: 27-Jan-2012 ##
################################################################################
# Function for updating the values of 'pbest', 'x.best', 'gbest.fit' and 'gbest.pos'
# for the ALL the SWARM !!
# 'x' : Matrix with the 'n' parameters of all the particles
# 'xt.fitness' : numeric vector of 'n.particles', with the current fitness
# obtained by all the particles in the swarm
# 'MinMax' : Character indicating if PSO have to find a minimum or a
# maximum for the fitness function.
# Valid values are in: c('min', 'max')
# 'pbest.fit' : numeric vector with length equal to 'n.particles', with the best
# fitness value found by each particle in the swarm so far.
# 'gbest.fit' : numeric, with the best fitness value found by the swarm so far.
# 'gbest.pos' : numeric, with the position of the particle corresponding
# to 'gbest.fit'.
# 'x.best' : Matrix of 'n*n.particles' values, corresponding to the
# 'n' parameters of each one of the particles in the swarm
# that achieve the best fitness value for the particle
# Result: a list of 4 components (this values are different of the input ones,
# only if the new values provide a better fitness value )
# : 1: pbest.fit : numeric vector with the new best fitness value of each
# particle
# : 2: x.best : matrix with the new 'n' best parameters for each particle
# : 3: gbest.fit : numeric (single value) with the new best fitness value
# for the swarm
# : 4: gbest.pos : integer with the location of the particle that has the
# best fitness value in the swarm
sync.update.pgbests <- function(x,
xt.fitness,
MinMax,
pbest.fit,
gbest.fit,
gbest.pos,
x.best
) {
# index of all the particles which current fit is better than their last 'pbest'
ifelse(MinMax == "max", better.index <- which( xt.fitness > pbest.fit ),
better.index <- which( xt.fitness < pbest.fit ) )
# if it exists some particles that have a better fitness value
if (length(better.index) > 0) {
# 'pbest.fit': updating the value of the best fit for each particle
pbest.fit[ better.index ] <- xt.fitness[better.index ]
# 'X.best.part': updating the value of the best parameters for the particles
# with better fitness
x.best[better.index, ] <- x[better.index, ]
# 'gbest.fit': updating the value of the best global fit
# 'gbest.pos': updating the position of the particle with the best global fit
if ( MinMax == "max" ) {
if ( max(pbest.fit, na.rm=TRUE) > gbest.fit ) {
gbest.pos <- which.max(pbest.fit)
#gbest.fit <- max(xt.fitness[better.index ])
gbest.fit <- pbest.fit[gbest.pos]
} # IF end
} else if ( MinMax == "min" ) {
if ( min(pbest.fit, na.rm=TRUE) < gbest.fit ) {
gbest.pos <- which.min(pbest.fit)
#gbest.fit <- min(xt.fitness[better.index ])
gbest.fit <- pbest.fit[gbest.pos]
} # IF end
} # ELSE end
} # IF end
# Creating the output
tmp <- list(4)
tmp[[1]] <- pbest.fit
tmp[[2]] <- x.best
tmp[[3]] <- gbest.fit
tmp[[4]] <- gbest.pos
names(tmp) <- c("pbest", "x.best", "gbest.fit", "gbest.pos")
return(tmp)
} # 'sync.update.pgbests' end
################################################################################
# computeCurrentXmaxMin #
################################################################################
# Author: Mauricio Zambrano-Bigiarini
# Started: 22-Dec-2010
################################################################################
# Purpose: To compute the minimum parameter range currently embraced for the best
# positions found so far in the swarm
################################################################################
# 'x.best.part': matrix with the best parameter values for each particle.
# nrows = number of particles
# ncols = number of parameters = n
computeCurrentXmaxMin <- function(x.best.part) {
# number of parameters
n <- ncol(x.best.part)
x.min <- sapply(1:n, function(i,y) { min(y[,i], na.rm=TRUE) }, y = x.best.part)
x.max <- sapply(1:n, function(i,y) { max(y[,i], na.rm=TRUE) }, y = x.best.part)
out <- cbind(x.min, x.max)
return(out)
} # 'computeCurrentXmaxMin' END
################################################################################
# decrease.search.space Function #
################################################################################
## Author : Mauricio Zambrano-Bigiarini ##
################################################################################
## Started: 2010 ##
## Updated: ##
################################################################################
# Decrease the search space according to the methodology proposed in the CPSO #
# 'Lmin.min' : vector of 'n' elements, with the minimum value that each dimension
# take within the minimum searching space defined by the user
# 'Lmin.max' : vector of 'n' elements, with the maximum value that each dimension
# take within the minimum searching space defined by the user
# 'Lmin' : vector of 'n' elements, with the minimum length that each dimension
# can take in the searching space defined by the user
# 'x.MinMaxCurrent' : Matrix with the minimum and maximum values for each dimension
# during the current iteration
# Rows = 'n' (number of parameters)
# Columns = 2,
# First column has the minimum possible value for each parameter
# Second column has the maximum possible value for each parameter
# 'x.MinMaxRange' : Matrix with the valid range for each parameter of 'X', as
# defined by the user
# Rows = 'n' (number of parameters)
# Columns = 2,
# First column has the minimum possible value for each parameter
# Second column has the maximum possible value for each parameter
# 'x.best' : vector of 'n' elements with the parameters of the particle
# with the best fitness value
# 'r' : real between 0 and 1. Only required when 'use.CLS' =TRUE
# represents the rate that is used for decreasing the
# searching space in the chaotic implementation
# Result : vector with the 'n' parameters of only 1 particle
decrease.search.space <- function(Lmin, x.MinMaxCurrent, x.MinMaxRange, x.best, r) {
# name of each parameter
param.IDs <- row.names(x.MinMaxRange)
# number of dimensions
n <- length(param.IDs)
# Removing possible attributes
x.best <- as.numeric( x.best )
x.min.curr <- as.numeric( x.MinMaxCurrent[ ,1] )
x.max.curr <- as.numeric( x.MinMaxCurrent[ ,2] )
x.min.rng <- as.numeric( x.MinMaxRange[ ,1] )
x.max.rng <- as.numeric( x.MinMaxRange[ ,2] )
# Current lenght of the parameter space in each dimension
Lcurr <- x.max.curr - x.min.curr
# New desired lenght of the parameter space in each dimension
Lnew <- r*Lcurr
# Creating the new minimum and maximum boundaries
x.min.new <- x.min.curr
x.max.new <- x.max.curr
# Updating the boundaries when the new length is larger than Lmin
for (i in 1:n) {
if (Lnew[i] >= Lmin[i]) {
x.min.new[i] <- max( x.min.curr[i], x.best[i] - 0.5*Lnew[i] )
x.max.new[i] <- min( x.max.curr[i], x.best[i] + 0.5*Lnew[i] )
#x.min.new[i] <- max( x.min.rng[i], x.best[i] - 0.5*Lnew[i] )
#x.max.new[i] <- min( x.max.rng[i], x.best[i] + 0.5*Lnew[i] )
} # IF end
} # FOR end
# New lenght of the parameter space in each dimension
Lnew <- x.max.new - x.min.new
#x.min.new <- pmax(x.min.rng, x.best - 0.5*Lnew )
#x.max.new <- pmin(x.max.rng, x.best + 0.5*Lnew )
x.MinMaxCurrent[ ,1] <- x.min.new
x.MinMaxCurrent[ ,2] <- x.max.new
# Relative change achieved in each dimension
rel.change <- (Lnew-Lcurr)/Lcurr
names(rel.change) <- param.IDs
return(x.MinMaxCurrent)
} # 'decrease.search.space' end
#decrease.search.space(Lmin, x.MinMaxCurrent, x.MinMaxRange, x.best, r)
################################################################################
# InitializateX #
################################################################################
# Author : Mauricio Zambrano-Bigiarini
# Started: 23-Dec-2010
# Updates: 24-Dec-2010
################################################################################
# Purpose: Function for the initialization of the position and the velocities
# of all the particles in the swarm
################################################################################
# -) npart : number of particles
# -) param.IDs : character, with the ID of each parameter/dimension.
# It has 'n' elements, where 'n' is the number of dimensions
# -) X.MinMax : Matrix with the minimum and maximum values for each dimension
# during the current iteration
# -) Rows = 'n' (number of parameters)
# -) Columns = 2,
# First column has the minimum possible value for each parameter
# Second column has the maximum possible value for each parameter
# 'init.type' : character, indicating how to carry out the initialization
# of the position of all the particles in the swarm
# valid values are in c('random', 'lhs')
InitializateX <- function(npart, param.IDs, x.MinMax, x.ini.type) {
# Number of parameters
n <- length(param.IDs)
# 'X' #
# Matrix of unknown parameters.
# Rows = 'npart';
# Columns = 'n' (Dimension of the Solution Space)
# Random bounded values are assigned to each dimension
if ( x.ini.type=="random" ) {
X <- Random.Bounded.Matrix(npart, x.MinMax)
} else X <- rLHS(npart, x.MinMax)
colnames(X) <- param.IDs
rownames(X) <- paste("Part", 1:npart, sep="")
return(X)
} # InitializateX
################################################################################
# InitializateV #
################################################################################
# Author : Mauricio Zambrano-Bigiarini
# Started: 24-Dec-2010
# Updates: 24-Nov-2011
################################################################################
# Purpose: Function for the initialization of the position and the velocities
# of all the particles in the swarm
################################################################################
# -) npart : number of particles
# -) param.IDs : character, with the ID of each parameter/dimension.
# It has 'n' elements, where 'n' is the number of dimensions
# -) X.MinMax : Matrix with the minimum and maximum values for each dimension
# during the current iteration
# -) Rows = 'n' (number of parameters)
# -) Columns = 2,
# First column has the minimum possible value for each parameter
# Second column has the maximum possible value for each parameter
# 'v.ini' : character, indicating how to carry out the initialization
# of the velocitites of all the particles in the swarm
# valid values are in c(0, 'random', 'lhs')
InitializateV <- function(npart, param.IDs, x.MinMax, v.ini.type, Xini) {
# Number of parameters
n <- length(param.IDs)
# 'V' #
# Matrix of velocities for each particles and iteration.
# Rows = 'npart';
# Columns = 'n' (Dimension of the Solution Space)
# Random bounded values are assigned to each dimension
if ( v.ini.type=="random" ) {
V <- ( Random.Bounded.Matrix(npart, x.MinMax) - Xini)/2
} else if ( v.ini.type=="lhs" ) {
V <- ( rLHS(npart, x.MinMax) - Xini)/2
} else if ( v.ini.type=="zero" ) {
V <- matrix(0, ncol=n, nrow=npart, byrow=TRUE)
}
colnames(V) <- param.IDs
rownames(V) <- paste("Part", 1:npart, sep="")
return(V)
} # InitializateV
################################################################################
## UpdateLocalBest ##
################################################################################
# Author : Mauricio Zambrano-Bigiarini
# Started: 24-Dec-2010
# Updates: 29-Dec-2010 ;
# 14-Nov-2011 ; 27-Jan-2011
################################################################################
# Purpose: Function for computing the best value in the neighbourhood of each
# particle
################################################################################
# pbest.fit : numeric, with best fitness in the history of each particle
# LocalBest.fit: numeric, best fitness in the history of the neighbourhood of
# each particle
# x.neighbours : numeric matrix, with the index/position of the particles that
# are considered "informants" of each particle.
# rows = number of particles
# columns= K+1 ; K: nmbr of informants provided by the user
# MinMax : character, indicating if PSO have to find a minimum or a
# maximum for the fitness function.
# Valid values are in: c('min', 'max')
UpdateLocalBest <- function(pbest.fit, localBest.pos, localBest.fit, x.neighbours, MinMax) {
# Number of particles
npart <- nrow(x.neighbours)
for ( i in 1:npart ) {
# index of all the particles that are "neighbours" to the particle 'i'
neighs.index <- x.neighbours[i,]
# if one or more of the "neighbours" have a better fitness than the current Local Best
ifelse(MinMax == "max", better.index <- which( pbest.fit[neighs.index] > localBest.fit[i] ),
better.index <- which( pbest.fit[neighs.index] < localBest.fit[i] ) )
# if there are some particles that have a better fitness value
if (length(better.index) > 0)
ifelse(MinMax == "max", localBest.fit[i] <- max( pbest.fit[neighs.index], na.rm=TRUE ) ,
localBest.fit[i] <- min( pbest.fit[neighs.index], na.rm=TRUE ) )
ifelse(MinMax == "max", localBest.pos[i] <- neighs.index[which.max( pbest.fit[neighs.index] )] ,
localBest.pos[i] <- neighs.index[which.min( pbest.fit[neighs.index] )] )
} # FOR end
out <- list(localBest.pos=localBest.pos, localBest.fit=localBest.fit)
return(out)
} # UpdateLocalBest
################################################################################
# UpdateNgbest #
################################################################################
# Author : Mauricio Zambrano-Bigiarini
# Started: 24-Dec-2010
# Updates: 29-Dec-2010
################################################################################
# Purpose: Function for computing the 'n.neighbours' best values in the swarm,
# and its positions
################################################################################
# pbest.fit : numeric, with best fitness in the history of each particle
# ngbest : Number of local best that have to be considered
# MinMax : character, indicating if PSO have to find a minimum or a
# maximum for the fitness function.
# Valid values are in: c('min', 'max')
UpdateNgbest <- function(pbest.fit, ngbest, MinMax) {
ifelse(MinMax=="max", sorted.fit <- sort(pbest.fit, decreasing= TRUE),
sorted.fit <- sort(pbest.fit, decreasing= FALSE) )
# Ordered index of all the particles,
# MinMax=="max" => Decreasing order
# MinMax=="min" => Increasing order
sorted.index <- pmatch(sorted.fit, pbest.fit)
ngbest.fit <- pbest.fit[sorted.index][1:ngbest]
ngbest.pos <- sorted.index[1:ngbest]
# Creating the output
out <- list(2)
out[[1]] <- ngbest.fit
out[[2]] <- ngbest.pos
names(out) <- c("ngbest.fit", "ngbest.pos")
return(out)
} # UpdateNgbest
################################################################################
# ComputeSwarmRadiusAndDiameter #
################################################################################
# Author : Mauricio Zambrano-Bigiarini
# Started: 12-Jan-2011
# Updates: 12-Jan-2011 ; 28-Oct-2011
################################################################################
# Purpose: Function for computing the sarm radius, for detecting premature
# convergence, in order to avoid stagnation
################################################################################
# X : matrix, with the current parameter values for all the particles
# gbest : numeric, with the parameter values for the best particle in the swarm
# MinMax : character, indicating if PSO have to find a minimum or a
# maximum for the fitness function.
# Valid values are in: c('min', 'max')
# Lmax :
ComputeSwarmRadiusAndDiameter <- function(x, gbest, Lmax, MinMax, pbest.fit) {
# number of parameters
n <- ncol(x)
# number of particles
npart <- nrow(x)
# Euclidean distance, in the n-dimensional space for all the particles
radius <- numeric(npart)
gbest <- matrix(rep(gbest, npart), nrow=npart, byrow=TRUE)
radius <- sqrt( rowSums( (x-gbest)^2 ) )
swarm.radius <- max(radius, na.rm=TRUE)
swarm.diameter <- sqrt(sum(Lmax^2))
# creating the output
out <- list(2)
out[[1]] <- swarm.radius
out[[2]] <- swarm.diameter
names(out) <- c("swarm.radius", "swarm.diameter")
return( out )
} # ComputeSwarmRadiusAndDiameter
################################################################################
# RegroupingSwarm #
################################################################################
# Author : Mauricio Zambrano-Bigiarini
# Started: 13-Jan-2011
# Updates: 18-Nov-2011
################################################################################
# Purpose: Function for regrouping the swarm in a search space centred around
# the global best, which is hoped to be both, small enough for efficient
# search and large enough to allow the swarm to escape from the current
# local best
################################################################################
RegroupingSwarm <- function(x,
gbest,
x.Range,
Lmax,
RG.thr,
RG.r) {
# number of parameters
n <- ncol(x)
# number of particles
npart <- nrow(x)
# Regrouping factor
rf <- RG.r # user-defined
#rf <- 6/(5*RG.thr) # Evers & Ghalia
#rf <- (1/RG.thr)/2 # MZB
# name of each parameter
param.IDs <- row.names(x.Range)
# Removing possible attributes
gbest <- as.numeric( gbest )
x.min.rng <- as.numeric( x.Range[ ,1] )
x.max.rng <- as.numeric( x.Range[ ,2] )
# Maximum length of the parameter space in each dimension
Lmax <- x.max.rng - x.min.rng
# Transforming the 'gbest' into a matrix, in order to make easier some
# further computations
Gbest <- matrix(rep(gbest, npart), nrow=npart, byrow=TRUE)
# New desired length of the parameter space in each dimension
# Is equal to the product of the regrouping factor with the maximum distance of
# each particle to the global best, for each dimension
Lnew <- rf * apply( abs(x-Gbest), MARGIN=2, FUN=max)
#Lnew <- rf * apply( abs(x-Gbest), MARGIN=2, FUN=mean)
# Making sure that the new range for each dimension is no larger than the original one
Lnew <- pmin(Lmax, Lnew)
# Re-initializing particle's positions around gbest
for (part in 1:npart) {
r3 <- runif(n, 0, 1)
x[part, ] <- gbest + r3*Lnew - 0.5*Lnew
# If needed, Clamping the particle positions to the maximum value
x[part, ] <- pmin(x[part,], x.max.rng)
# If needed, Clamping the particle positions to the minimum value
x[part, ] <- pmax(x[part,], x.min.rng)
} # FOR end
# Relative change achieved in each dimension
rel.change <- (Lnew-Lmax)/Lmax
names(rel.change) <- param.IDs
out <- list(2)
out[[1]] <- x
out[[2]] <- Lnew
names(out) <- c("X", "Lnew")
return(out)
} # 'RegroupingSwarm' end
################################################################################
# Random.Topology.Generation #
################################################################################
# Author : Mauricio Zambrano-Bigiarini
# Started: 23-Nov-2011
# Updates:
################################################################################
# Purpose: Function for creating a random topology, as implemented on the
# Standard PSO 2007
################################################################################
Random.Topology.Generation <- function(npart, K,
psoout.drty, iter # only needed during testing phase
) {
p.avg <- 1 - (1 - 1/npart)^K
tmp <- matrix(runif(npart*npart, 0, 1) <= p.avg, nrow=npart, ncol=npart)
diag(tmp) <- TRUE
X.neighbours <- matrix(rep(NA, npart*npart), ncol=npart, nrow=npart, byrow=TRUE)
for (i in 1:npart) {
l <- length(which(tmp[,i]))
X.neighbours[i, 1:l] <- which(tmp[,i])
} # FOR end
rownames(X.neighbours) <- paste("Part", 1:npart, sep="")
colnames(X.neighbours) <- paste("Neigh", 1:npart, sep="")
return(X.neighbours)
} # ELSE end
################################################################################
### Function for evaluating the hydrological model for a single particle #####
################################################################################
### Started: 21-Jun-2011 ###
### Updates: 28-Jun-2011 ###
### 19-Jun-2012 ; 03-Jul-2012 ###
################################################################################
hydromod.eval <- function(part, Particles, iter, npart, maxit,
REPORT, verbose, digits,
model.FUN, model.FUN.args
) {
if ( iter/REPORT == floor(iter/REPORT) ) {
if (verbose) message("================================================================================")
if (verbose) message( "[Iter: ", format( iter, width=4, justify="left" ), "/", maxit,
". Particle: ", format( part, width=4, justify="left" ), "/", npart,
": Starting...]" )
if (verbose) message("================================================================================")
} # IF end
# Creating the R output
nelements <- 2
out <- vector("list", nelements)
# Evaluating the hydrological model
model.FUN.args <- modifyList(model.FUN.args, list(param.values=Particles[part,]) )
hydromod.out <- do.call(model.FUN, as.list(model.FUN.args))
out[[1]] <- as.numeric(hydromod.out[["GoF"]])
out[[2]] <- hydromod.out[["sim"]]
# meaningful names
names(out)[1:nelements] <- c("GoF", "model.out")
if ( iter/REPORT == floor(iter/REPORT) ) {
if (verbose) message("================================================================================")
if (verbose) message( "[Iter: ", format( iter, width=4, justify="left" ), "/", maxit,
". Particle: ", format( part, width=4, justify="left" ), "/", npart,
". Finished !. GoF: ", format(hydromod.out[["GoF"]], scientific=TRUE, digits=digits),
"]" )
if (verbose) message("================================================================================")
if (verbose) message(" | ")
if (verbose) message(" | ")
} # IF end
return(out)
} # 'hydromod.eval' END
################################################################################
# P.S.O. #
################################################################################
# Author : Mauricio Zambrano-Bigiarini #
################################################################################
# Started: 2008 #
# 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 ; 15-Jun-2012 ; 03-Jul-2012 ; 06-Jul-2012 #
# 11-Jul-2012 ; 17-Jul-2012 ; 18-Jul-2012 ; 13-Sep-2012; 14-Sep-2012 #
################################################################################
# 'lower' : minimum possible value for each parameter
# 'upper' : maximum possible value for each parameter
# 'of.name' : String with the test function that will be used for computing the fitness.
# Valid values are in: c('sinc', 'rosenbrock', 'sphere',
# 'rastrigin', 'griewank', 'schafferF6', 'hydromod')
# 'MinMax' : character, indicating if PSO have to find a minimum or a
# maximum for the fitness function.
# Valid values are in: c('min', 'max')
# 'npart' : number of particles that makes the swarm.
# Must be divisible by 5 (requirement for the chaotic part)
# 'maxit' : numeric, with the maximum number of iterations
# 'c1' : numeric, representing the cognition constant.
# Encourages the exploration of the solution space.
# How much the particle is influenced by the memory of his best location
# 'c2' : numeric, representing the social constant.
# Encourages the exploitation of the current global best
# How much the particle is influenced by the rest of the swarm
# 'use.CF' : logical, indicating if the Clerc's Constriction Factor have to be used
# to ensure the convergence of the PSO algorithm
# 'lambda' : numeric in [0,1] representing a percentage to limit
# the maximum velocity for each dimension, which is computed
# as 'vmax = Vmax.perc*(Xmax-Xmin)'
# 'par' : OPTIONAL. numeric of length 'n' (number of parameters),
# providing a first guess for the parameters to be optimised.
# If it is not present, all the particles are randomly initialized,
# according to the value of \code{Xini.type}
# 'Xini.type' : character, indicating how to initialise the position of all
# the particles in the swarm, within the ranges defined by
# \code{X.Boundaries}. Valid values are: \cr
# -) "random": random initialisation
# -) "lhs" : Latin Hypercube initialisation. \bold{it
# requires the \pkg{lhs} package}
# 'Vini.type : character, indicating how to initialise the velocity of all
# the particles in the swarm, within the ranges defined by
# \code{X.Boundaries}. Valid values are: \cr
# -) 0 : all the particles are initialised with zero velocity
# -) "random": random initialisation
# -) "lhs" : Latin Hypercube initialisation. \bold{it
# requires the \pkg{lhs} package}
# 'best.update' : character, indicating when to update the global and local best
# Valid values are: \cr
# -) "sync" : the update is made in a synchronous way, i.e.,
# after computing the position and fitness of
# ALL the particles in the swarm
# -) "async": the update is made in an asynchronous way, i.e.,
# after computing the position and fitness of
# EACH particle in the swarm
# 'boundary.wall' : Boundary treatment that is used to limit the sea
# the limits given by 'X.Boundaries'.
# Valid values are: 'absorbing', 'reflecting' and 'invisible'
# See \citet{RobinsonRahmatSamii2004}
# 'topology' : character, with the neighbourhood topology to be used in PSO.
# Valid values are in \code{c('gbest', 'lbest', 'ipso')}:
# \kbd{gbest}: every particle is connected to every other individual,
# and in particular to the best one. This is
# also termed \textit{star} topology, and it is
# generally assumed to have a fast convergence.
# However, if the global optimum is not close
# to the attraction zone of the best particle,
# the swarm can get trapped into local optima.
# see Kennedy 1999; Kennedy and Mendes 2002
# \kbd{lbest}: each particle is connected to its \textit{K}
# immediate neighbours only. This is also termed
# \textit{circles} or \textit{ring} topology,
# and generally the swarm will converge slower
# than with the \kbd{gbest} topology,
# but it has a greater chance to locate the
# global optimum. see Kennedy 1999; Kennedy and Mendes 2002
# \kbd{ipso}: At each iteration, al the particles in the swarm
# are rearranged in descending order according
# to their fitness value and the best \kbd{ngbest}
# particles to modify particle's position and velocity.
# See Zhao 2006.
# 'K' : OPTIONAL. Only used when \code{topology=='lbest'}
# numeric, with the total amount of neighbours of each particle
# to be considered in the computation of their personal best.
# It MUST BE an even number, in order to consider the same
# amount of neighbours to the left and the right of each particle.
# By default \code{K=3}.
# 'iter.ini' : OPTIONAL. Only used when \code{topology=='lbest'}
# numeric, with the amount of iterations in which the topology
# \kbd{gbest} will be used before starting to use the \kbd{lbest}
# topology for the computation of the personal best of each particle.
# This argument has not been found in literature, and it aims at
# making faster the localization of the global zone of attraction.
# By default \code{iter.ini=0}.
# 'ngbest' : OPTIONAL. Only used when \code{topology=='ipso'}
# numeric, with the amount of particles that will be considered
# in the computation of the global best. \cr
# By default \code{ngbest=4}. See Zhao 2006.
# 'use.IW' : logical, indicating if an inertia weight (\env{w}) will be used
# to avoid particles fly around their best position without
# converging into it. See Shi and Eberhart 1998 and Zheng et al. 2003.
# 'IW.type' : OPTIONAL, only required when \code{use.IW= TRUE}.
# character, that defined how to vary the inertia weight
# \env{w} along the iterations. Valid values are: \cr
# Valid values are: \cr
# -) "linear" : \env{w} varies linearly between the initial
# and final values specified by the user
# in \code{IW.w}.
# See Shi and Eberhart, 1998. and Zheng et al., 2003
# -) "non-linear": \env{w} varies non-linearly between the initial
# and final values specified by the user
# in \code{IW.w}.
# See Chatterjee and Siarry, 2006. \cr
# -) "runif" : \env{w} is a uniform random variable in
# the range [w.min, w.max] specified by the user
# in \code{IW.w}. It is a generalization of
# the variation proposed in Eberhart and Shi, 2001b
# -) "aiwf" : Adaptive inertia weight factor, where the
# inertia weight is varied adaptively
# depending of the objective values of the particles \cr
# See Liu et al., 2005 \cr
# -) "GLratio" : \env{w} varies according to the ration between
# the global best and the average of the particle's
# local best. See Arumugam and Rao, 2008 \cr
# 'IW.w' : OPTIONAL, only required when \code{use.IW= TRUE & IW.type!='GLratio'}
# numeric with the inertia weight(s) (\env{w} or \env{[w.ini, w.fin]}).
# It can be one single number which is then used during all the algorithm,
# or it can be a vector of length 2, with the initial and final values
# (in that order) that \env{w} will take along the iterations
# 'IW.exp' : OPTIONAL, only required when \code{use.IW= TRUE} AND \code{IW.type= 'non-linear'}
# non-linear modulation index. See Chatterjee and Siarry, 2006. \cr
# When \code{IW.type='linear'}, \code{IW.exp} is set to 1.
# 'use.TVc1' : logical, indicating if the cognitive constant (c1) will have
# a time-varying value instead of a constant one provided by the user.
# See Ratnaweera et al., 2004
# 'TVc1.type' : character, required only when \code{use.TVc1 = TRUE}.
# Valid values are in: \code{c('linear', 'non-linear', 'GLratio')}
# 'TVc1.rng' : OPTIONAL, only required when \code{use.TVc1= TRUE & TVc1.type!='GLratio'}
# numeric with the initial and final values for the cognitive
# constant \env{[c1.ini, c1.fin]} (in that order) along the iterations
# 'TVc1.exp' : OPTIONAL, only required when \code{use.TVc1= TRUE} AND ('TVc1.type'= "non-linear"). \cr
# non-linear modulation index. When \code{TVc1.type= 'linear}
# \code{TVc1.exp} is set to 1.
# When \code{TVc1.exp} is equal to 1, \code{TVc1} corresponds
# to the improvement proposed by Ratnaweera et al., 2004,
# whereas when \code{TVc1.exp} is different from one, no reference
# has been found in literature by the authors, but it was included
# as an option taking into account the work of Chatterjee and
# Siarry 2006 for the inertia weight.\cr
# 'use.TVc2' : logical, indicating if the social constant (c2) will have
# a time-varying value instead of a constant one provided by the user.
# See Ratnaweera et al., 2004
# 'TVc2.type' : character, required only when \code{use.TVc2 = TRUE}.
# Valid values are in: \code{c('linear', 'non-linear')}
# 'TVc2.rng' : OPTIONAL, only required when \code{use.TVc2= TRUE}
# numeric with the initial and final values for the social
# constant \env{[c2.ini, c2.fin]} (in that order)
# for \env{c1} along the iterations
# 'TVc2.exp' : OPTIONAL, only required when \code{use.TVc1= TRUE} AND ('TVc1.type'= "non-linear"). \cr
# non-linear modulation index. When \code{TVc1.type= 'linear}
# \code{TVc1.exp} is set to 1.
# When \code{TVc2.exp} is equal to 1, \code{TVc2} corresponds
# to the improvement proposed by Ratnaweera et al., 2004,
# whereas when \code{TVc2.exp} is different from one, no reference
# has been found in literature by the authors, but it was included
# as an option taking into account the work of Chatterjee and
# Siarry 2006 for the inertia weight.\cr
# 'use.RG' : logical, indicating if the swarm should be regrouped when
# premature convergence is detected. When \code{use.RG=TRUE}
# the swarm is regrouped in a search space centred about gbest,
# which is hoped to be both small enough for efficient search
# and large enough to allow the swarm to escape from stagnation.
# See Evers and Ghalia 2009
# 'RG.thr' : ONLY required when \code{use.RG=TRUE}. \cr
# numeric with a positive value representing the
# \kbd{stagnation threshold}, which is used to decide if the
# swarm has to be regrouped or not. See Evers and Galia 2009
# for further details \cr
# Regrouping occurs when the \kbd{normalised swarm radius}
# is less than \code{RG.thr}.
# 'RG.r' : ONLY required when \code{use.RG=TRUE}. \cr
# numeric with a positive value representing the
# \kbd{regrouping factor}, which is used to regroup the swarm
# in a search space centred about the global best, which is
# hoped to be both small enough for efficient search and
# large enough to allow the swarm escape from the current well.
# See Evers and Galia 2009 for further details
# 'RG.miniter' : ONLY required when \code{use.RG=TRUE}. \cr
# numeric with the minimum number of iterations needed before
# regrouping
# 'psoout.drty' : character, with the name of the directory where the output
# files will be written
# 'use.DS' : Boolean. It indicates if the solution space will be decreased
# when the particles are stagned around gbest
# 'DS.dmin' : Real between 0 and 1, indicating the minimum length of
# each dimension accepted by the user.
# Only required when 'use.DS' = TRUE
# 'DS.tol' : Real. Tolerance that will be used for deciding when
# to decrease the solution space
# It starts when 'gbest.fit.rate' < DS.tol,
# gbest.fit.rate = abs( [gbest.fit(n)-gbest.fit(n-1)/gbest.fit(n) )
# Only required when 'use.DS' = TRUE
# 'DS.r' : Real between 0 and 1.
# represents the rate that is used for decreasing the
# searching space
# Only required when 'use.DS' = TRUE
# 'out.with.pbest' : Logical, indicating if the best parameter values for each
# particle and their fitness has to be included in the output
# of the algorithm
# 'out.with.fit.iter: Logical,indicating if the fitness of each particle and in
# each iteration has to be included in the output of the algorithm
# 'write2disk' : Logical, indicating if output files have to be written to
# the disk or not
# 'param.ranges' : character, with the name of the file that stores the desired
# range of variation for each
# 'verbose' : logical, should progress messages be printed ?
# 'REPORT' : OPTIONAL, only used when \code{verbose=TRUE}.
# The frequency of report messages printed to the screen. Default
# to every 10 iterations
# optim:
# par, fn, gr = NULL, ..., method = c("Nelder-Mead",
# "BFGS", "CG", "L-BFGS-B", "SANN"), lower = -Inf, upper = Inf,
# control = list(), hessian = FALSE
hydroPSO <- function(
par,
fn="hydromod",
...,
method=c("pso", "ipso", "fips", "wfips"),
lower=-Inf,
upper=Inf,
control=list(),
model.FUN=NULL,
model.FUN.args=list()
) {
########################################################################
# 0) Checkings and Basic computations - Start #
########################################################################
if (!missing(par)) {
if (class(par)=="numeric") {
n <- length(par)
} else if ( (class(par)=="matrix") | (class(par)=="data.frame") ) {
n <- ncol(par)
} # ELSE IF end
} else n <- NULL
if (missing(fn)) {
stop("Missing argument: 'fn' must be provided")
} else {
fn.name <- fn
fn <- match.fun(fn)
} # ELSE end
method <- match.arg(method)
if (length(lower) != length(upper) )
stop( paste( "Invalid argument: 'length(lower) != length(upper) (", length(lower), "!=", length(upper), ")'", sep="" ) )
if (!is.null(n)) {
if (length(lower) != n)
stop( paste( "Invalid argument: 'length(lower) != nparam (", length(lower), "!=", n, ")'", sep="" ) )
if (length(upper) != n)
stop( paste( "Invalid argument: 'length(upper) != nparam (", length(lower), "!=", n, ")'", sep="" ) )
} else n <- length(lower)
############################################################################
con <- list(
drty.in="PSO.in",
drty.out="PSO.out",
param.ranges="ParamRanges.txt",
digits=7,
MinMax=c("min", "max"),
npart=NA,
maxit=1000,
maxfn=Inf,
c1= 0.5+log(2),
c2= 0.5+log(2),
use.CF= FALSE,
lambda= 1,
abstol= NULL,
reltol=sqrt(.Machine$double.eps),
Xini.type=c("lhs", "random"),
Vini.type=c("lhs", "random", "zero"),
best.update=c("sync", "async"),
random.update=TRUE,
boundary.wall=c("reflecting", "damping", "absorbing", "invisible"),
topology=c("random", "gbest", "lbest", "vonNeumann"), K=3, iter.ini=0, ngbest=4, # only used when 'method=ipso'
use.IW = TRUE, IW.type=c("linear", "non-linear", "runif", "aiwf", "GLratio"), IW.w=1/(2*log(2)), IW.exp= 1,
use.TVc1= FALSE, TVc1.type=c("non-linear", "linear", "GLratio"), TVc1.rng= c(1.28, 1.05), TVc1.exp= 1.5,
use.TVc2= FALSE, TVc2.type=c("non-linear", "linear"), TVc2.rng= c(1.05, 1.28), TVc2.exp= 1.5,
use.TVlambda=FALSE, TVlambda.type=c("non-linear", "linear"), TVlambda.rng= c(1, 0.25), TVlambda.exp= 1,
use.RG = FALSE, RG.thr= 1.1e-4, RG.r= 0.8, RG.miniter= 5, # RG.r not used in reagrouping
plot=FALSE,
out.with.pbest=FALSE,
out.with.fit.iter=FALSE,
write2disk=TRUE,
verbose=TRUE,
REPORT=100
)
MinMax <- match.arg(control[["MinMax"]], con[["MinMax"]])
Xini.type <- match.arg(control[["Xini.type"]], con[["Xini.type"]])
Vini.type <- match.arg(control[["Vini.type"]], con[["Vini.type"]])
best.update <- match.arg(control[["best.update"]], con[["best.update"]])
boundary.wall <- match.arg(control[["boundary.wall"]], con[["boundary.wall"]])
topology <- match.arg(control[["topology"]], con[["topology"]])
IW.type <- match.arg(control[["IW.type"]], con[["IW.type"]])
TVc1.type <- match.arg(control[["TVc1.type"]], con[["TVc1.type"]])
TVc2.type <- match.arg(control[["TVc2.type"]], con[["TVc2.type"]])
TVlambda.type <- match.arg(control[["TVlambda.type"]], con[["TVlambda.type"]])
nmsC <- names(con)
con[(namc <- names(control))] <- control
if (length(noNms <- namc[!namc %in% nmsC]))
warning("[Unknown names in control: ", paste(noNms, collapse = ", "), " (not used) !]")
drty.in <- con[["drty.in"]]
drty.out <- con[["drty.out"]]
param.ranges <- con[["param.ranges"]]
digits <- con[["digits"]]
npart <- ifelse(is.na(con[["npart"]]),ceiling(10+2*sqrt(n)),con[["npart"]])
maxit <- con[["maxit"]]
maxfn <- con[["maxfn"]]
c1 <- con[["c1"]]
c2 <- con[["c2"]]
use.CF <- con[["use.CF"]]
lambda <- con[["lambda"]]
abstol <- con[["abstol"]]
reltol <- con[["reltol"]]
random.update <- as.logical(con[["random.update"]])
K <- con[["K"]]
iter.ini <- con[["iter.ini"]]
ngbest <- con[["ngbest"]]
use.IW <- as.logical(con[["use.IW"]])
IW.w <- con[["IW.w"]]
IW.exp <- con[["IW.exp"]]
use.TVc1 <- as.logical(con[["use.TVc1"]])
TVc1.rng <- con[["TVc1.rng"]]
TVc1.exp <- con[["TVc1.exp"]]
use.TVc2 <- as.logical(con[["use.TVc2"]])
TVc2.rng <- con[["TVc2.rng"]]
TVc2.exp <- con[["TVc2.exp"]]
use.TVlambda <- as.logical(con[["use.TVlambda"]])
TVlambda.rng <- con[["TVlambda.rng"]]
TVlambda.exp <- con[["TVlambda.exp"]]
use.RG <- as.logical(con[["use.RG"]])
RG.thr <- con[["RG.thr"]]
RG.r <- con[["RG.r"]]
RG.miniter <- con[["RG.miniter"]]
plot <- as.logical(con[["plot"]])
out.with.pbest <- as.logical(con[["out.with.pbest"]])
out.with.fit.iter <- as.logical(con[["out.with.fit.iter"]])
write2disk <- as.logical(con[["write2disk"]])
verbose <- as.logical(con[["verbose"]])
REPORT <- con[["REPORT"]]
############################################################################
######################### Dummy checkings ##################################
if (maxit < REPORT) {
REPORT <- maxit
warning("[ 'REPORT' is greater than 'maxit' => 'REPORT=maxit' ]")
} # IF end
if ( (lambda < 0) | (lambda >1) )
stop("Invalid argument: 'lambda' has to be in [0, 1] !!")
if ( K > npart ) {
K <- npart
warning("[ 'K' is greater than 'npart' => 'K=npart' ]")
} # IF end
if ( (K < 1) | (floor(K) != K) ) {
K <- npart
stop("'K' must be a positive integer (> 0) !!'")
} # IF end
ifelse( ("gof.Ini" %in% names(model.FUN.args)), gof.Ini.exists <- TRUE, gof.Ini.exists <- FALSE )
ifelse( ("gof.Fin" %in% names(model.FUN.args)), gof.Fin.exists <- TRUE, gof.Fin.exists <- FALSE )
############################################################################
# 1) Initialisation #
###################################################$$$$#####################
if (verbose) message(" ")
if (verbose) message("================================================================================")
if (verbose) message("[ Initialising ... ]")
if (verbose) message("================================================================================")
if (verbose) message(" ")
tmp.stg <- c("npart", "maxit", "method", "topology", "boundary.wall")
tmp.val <- c(npart, maxit, method, topology, boundary.wall)
message("[", paste(tmp.stg, tmp.val, collapse = " ; ", sep="="), "]")
if (length(yesNms <- namc[namc %in% nmsC])) {
yesVals <- con[pmatch(namc[namc %in% nmsC], nmsC)][c(yesNms)]
message(" ")
message("[ user-definitions in control: ", paste(yesNms, yesVals, collapse = " ; ", sep="="), " ]")
message(" ")
} # IF end
if (fn.name=="hydromod") {
if (drty.in == basename(drty.in) )
drty.in <- paste( getwd(), "/", drty.in, sep="")
if ( !file.exists( file.path(drty.in) ) )
stop( paste("Invalid argument: The directory '", drty.in, "' doesn't exist !", sep="") )
if (param.ranges == basename(param.ranges) )
param.ranges <- paste( file.path(drty.in), "/", param.ranges, sep="")
if ( !file.exists( param.ranges ) )
stop( paste("Invalid argument: The file '", param.ranges, "' doesn't exist !", sep="") )
if ( is.null(model.FUN) ) {
stop( "'model.FUN' has to be defined !" )
} else {
model.FUN.name <- model.FUN
model.FUN <- match.fun(model.FUN)
} # ELSE end
if ( length(model.FUN.args)==0 ) {
warning( "[ 'model.FUN.args' is an empty list. Are you sure your model does not have any argument(s) ? ]" )
} else {
model.FUN.argsDefaults <- formals(model.FUN)
model.FUN.args <- modifyList(model.FUN.argsDefaults, model.FUN.args)
} # ELSe end
} # IF end
# checking 'X.Boundaries'
if (fn.name=="hydromod") {
if (verbose) message("================================================================================")
if (verbose) message("[ Reading 'param.ranges' ... ]")
if (verbose) message("================================================================================")
X.Boundaries <- read.ParameterRanges(ParamRanges.fname=param.ranges)
} else {
if ( (lower[1L] == -Inf) || (upper[1L] == Inf) ) {
stop( "Invalid argument: 'lower' and 'upper' boundaries must be finite !!'" )
} else X.Boundaries <- cbind(lower, upper)
} # ELSE end
n <- nrow(X.Boundaries)
if (is.null(rownames(X.Boundaries))) {
param.IDs <- paste("Param", 1:n, sep="")
} else param.IDs <- rownames(X.Boundaries)
if (drty.out == basename(drty.out) )
drty.out <- paste( getwd(), "/", drty.out, sep="")
if (!file.exists(file.path(drty.out))) {
if (write2disk) {
dir.create(file.path(drty.out))
if (verbose) message(" ")
if (verbose) message("[ Output directory '", basename(drty.out), "' was created on: '", dirname(drty.out), "' ]")
if (verbose) message(" ")
} # IF end
} # IF end
if (is.null(abstol)) ifelse(MinMax == "max", abstol <- +Inf, abstol <- -Inf)
if (Xini.type=="lhs") {
if ( is.na( match("lhs", installed.packages()[,"Package"] ) ) ) {
warning("[ Package 'lhs' is not installed => Xini.type='random' ]")
Xini.type <- "random"
} # IF end
} # IF end
if (Vini.type=="lhs") {
if ( is.na( match("lhs", installed.packages()[,"Package"] ) ) ) {
warning("[ Package 'lhs' is not installed => Vini.type='random' ]")
Vini.type <- "random"
} # IF end
} # IF end
if (use.IW) {
w <- IW.w
if (length(w) == 2) {
w.ini <- w[1] #initial inertial weight at the start of a given run
w.fin <- w[2] #final inertial weight at the end of a given run
} else if (length(w) == 1) {
w.ini <- w
w.fin <- w
} else stop("Invalid argument: 'length(w)' must be 1 or 2 !!")
if (IW.type == "linear") {
if (IW.exp != 1) {
warning("[ IW.type == 'linear' => 'IW.exp=1' ]")
IW.exp= 1
} # IF end
} # IF end
} # IF end
if (use.CF) {
if (c1+c2 < 4) stop("Invalid argument: 'c1+c2' must be >= 4 when 'use.CF=TRUE'")
CF <- compute.CF(c1, c2)
if ( use.TVc1 ) stop("Invalid argument: You can not use 'TVc1' when 'use.CF=TRUE'")
if ( use.TVc2 ) stop("Invalid argument: You can not use 'TVc2' when 'use.CF=TRUE'")
} else CF <- 1
if ( use.IW & use.CF )
stop("Invalid argument: Inertia Weight and Constriction Factor can not be used simultaneously !!")
if (use.TVc1) {
c1.ini <- TVc1.rng[1]
c1.fin <- TVc1.rng[2]
if (TVc1.type == "linear") {
if (TVc1.exp != 1) {
warning("[ TVc1.type == 'linear' => 'TVc1.exp=1' ]")
TVc1.exp= 1
} # IF end
} # IF end
} # IF end
if (use.TVc2) {
c2.ini <- TVc2.rng[1]
c2.fin <- TVc2.rng[2]
if (TVc2.type == "linear") {
if (TVc2.exp != 1) {
warning("[ TVc2.type == 'linear' => 'TVc2.exp=1' ]")
TVc2.exp= 1
} # IF end
} # IF end
} # IF end
if (use.TVlambda) {
# Computing ('vmax.ini', 'vmax.fin')
vmax.ini <- TVlambda.rng[1]
vmax.fin <- TVlambda.rng[2]
if (TVlambda.type == "linear") {
if (TVlambda.exp != 1) {
warning("[ TVlambda.type == 'linear' => 'TVlambda.exp=1' ]")
TVlambda.exp= 1
} # IF end
} # IF end
} # IF end
if ( (topology == "lbest") | (topology == "random") ) {
if (topology == "lbest") {
if (K != npart) {
if ( (trunc((K-1)/2) -(K-1)/2) != 0 )
stop("Invalid argument: 'K' must be odd" )
} # IF end
} # IF end
} else if (topology=="vonNeumann") {
topology <- "lbest"
if (npart < 5) stop("Invalid argument: for 'vonNeumann' topology 'npart' should be >= 5 !!")
if (K != 5) K <- 5
} else if (topology == "gbest") {
K <- npart
} # ELSE end
if ( method == "ipso" ) {
if ( (ngbest < 1) | (ngbest > npart) )
stop("Invalid argument: 'ngbest' must be in [1, 'npart]'" )
if ( topology!="gbest") {
if (verbose) warning("[ Note: 'method=ipso' => 'topology' was changed to 'gbest' !]" )
topology <- "gbest"
} # IF end
} # IF end
Lmax <- (X.Boundaries[ ,2] - X.Boundaries[ ,1])
########################################################################
# 2) Initialization of Swarm location and velocities #
########################################################################
X.Boundaries.current <- X.Boundaries
Vmax <- lambda*Lmax
X <- InitializateX(npart=npart, param.IDs=param.IDs,
x.MinMax=X.Boundaries, x.ini.type=Xini.type)
V <- InitializateV(npart=npart, param.IDs=param.IDs,
x.MinMax=X.Boundaries, v.ini.type=Vini.type, Xini=X)
V <- t(apply(V, MARGIN=1, FUN=velocity.boundary.treatment, vmax=Vmax))
if (!missing(par)) {
if (!any(is.na(par)) && all(par>=lower) && all(par<=upper)) {
if (class(par)=="numeric") {
X[1,] <- par
} else if ( (class(par)=="matrix") | (class(par)=="data.frame") ) {
tmp <- ncol(par)
if ( tmp != n )
stop( paste("Invalid argument: 'ncol(par) != n' (",tmp, "!=", n, ")", sep="") )
tmp <- nrow(par)
X[1:tmp,] <- par
} # ELSE end
} # IF end
} # IF end
X.best.part <- X
# Worst possible value defined for the objective function
ifelse(MinMax == "max", fn.worst.value <- -.Machine$double.xmax/2,
fn.worst.value <- +.Machine$double.xmax/2)
pbest.fit <- rep(fn.worst.value, npart)
pbest.fit.iter <- fn.worst.value
pbest.fit.iter.prior <- fn.worst.value*2
gbest.fit <- fn.worst.value
gbest.fit.iter <- rep(gbest.fit, maxit)
gbest.fit.prior <- gbest.fit
gbest.pos <- 1
Xt.fitness <- matrix(rep(fn.worst.value, maxit*npart), ncol=npart, nrow=maxit, byrow=TRUE)
colnames(Xt.fitness) <- paste("Part", 1:npart, sep="")
rownames(Xt.fitness) <- paste("iter.", 1:maxit, sep="")
if (topology != "random") {
nc <- K
ifelse(trunc(K/2) != ceiling(K/2), N <- (K-1)/2, N <- K/2)
ifelse(trunc(K/2) != ceiling(K/2), NN <- 1, NN <- 0)
X.neighbours <- matrix(rep(-NA, nc*npart), ncol=nc, nrow=npart, byrow=TRUE)
for ( i in 1:npart) {
for ( j in -N:N ) {
neigh.index <- i + j
if ( neigh.index < 1 ) neigh.index <- npart + neigh.index
if ( neigh.index > npart ) neigh.index <- neigh.index - npart
X.neighbours[i,j+N+NN] <- neigh.index
} # FOR end
} # FOR end
rownames(X.neighbours) <- paste("Part", 1:npart, sep="")
colnames(X.neighbours) <- paste("Neigh", 1:nc, sep="")
} # IF end
LocalBest.fit <- rep(fn.worst.value, npart)
LocalBest.pos <- 1:npart
if ( topology == "ipso") {
ngbest.fit <- rep(fn.worst.value, ngbest)
ngbest.pos <- rep(1, ngbest)
} else {
ngbest.fit <- NA
ngbest.pos <- NA
} # ELSE end
############################################################################
# Text Files initialization #
############################################################################
if (write2disk) {
if (verbose) message(" ")
if (verbose) message("================================================================================")
if (verbose) message("[ Writing the 'PSO_logfile.txt' file ... ]")
if (verbose) message("================================================================================")
PSOparam.fname <- paste(file.path(drty.out), "/", "PSO_logfile.txt", sep="")
PSOparam.TextFile <- file(PSOparam.fname , "w+")
writeLines("================================================================================", PSOparam.TextFile)
writeLines(c("Platform :", sessionInfo()[[1]]$platform), PSOparam.TextFile, sep=" ")
writeLines("", PSOparam.TextFile)
writeLines(c("R version :", sessionInfo()[[1]]$version.string), PSOparam.TextFile, sep=" ")
writeLines("", PSOparam.TextFile)
writeLines(c("hydroPSO version :", sessionInfo()$otherPkgs$hydroPSO$Version), PSOparam.TextFile, sep=" ")
writeLines("", PSOparam.TextFile)
writeLines(c("hydroPSO Built :", sessionInfo()$otherPkgs$hydroPSO$Built), PSOparam.TextFile, sep=" ")
writeLines("", PSOparam.TextFile)
writeLines("================================================================================", PSOparam.TextFile)
Time.Ini <- Sys.time()
writeLines(c("Starting Time :", date()), PSOparam.TextFile, sep=" ")
writeLines("", PSOparam.TextFile)
writeLines("================================================================================", PSOparam.TextFile)
writeLines(c("Objective Function:", fn.name), PSOparam.TextFile, sep=" ")
writeLines("", PSOparam.TextFile)
writeLines(c("Dimension :", n), PSOparam.TextFile, sep=" ")
writeLines("", PSOparam.TextFile)
writeLines(c("Nmbr of Particles :", npart), PSOparam.TextFile, sep=" ")
writeLines("", PSOparam.TextFile)
writeLines(c("Max Iterations :", maxit), PSOparam.TextFile, sep=" ")
writeLines("", PSOparam.TextFile)
writeLines(c("Method :", method), PSOparam.TextFile, sep=" ")
writeLines("", PSOparam.TextFile)
if ( method == "ipso" ) {
writeLines(c("ngbest :", ngbest), PSOparam.TextFile, sep=" ")
writeLines("", PSOparam.TextFile)
} # IF end
writeLines(c("Topology :", topology), PSOparam.TextFile, sep=" ")
writeLines("", PSOparam.TextFile)
if ( (topology == "lbest") | (topology == "random") ) {
writeLines(c("K :", K), PSOparam.TextFile, sep=" ")
writeLines("", PSOparam.TextFile)
writeLines(c("iter.ini :", iter.ini), PSOparam.TextFile, sep=" ")
writeLines("", PSOparam.TextFile)
} # IF end
writeLines(c("Boundary wall :", boundary.wall), PSOparam.TextFile, sep=" ")
writeLines("", PSOparam.TextFile)
writeLines(c("Best update method:", best.update), PSOparam.TextFile, sep=" ")
writeLines("", PSOparam.TextFile)
writeLines(c("Random update :", random.update), PSOparam.TextFile, sep=" ")
writeLines("", PSOparam.TextFile)
if (use.TVc1) {
writeLines(c("use.TVc1 :", use.TVc1), PSOparam.TextFile, sep=" ")
writeLines("", PSOparam.TextFile)
writeLines(c("TVc1.type :", TVc1.type), PSOparam.TextFile, sep=" ")
writeLines("", PSOparam.TextFile)
writeLines(c("TVc1.rng :", TVc1.rng), PSOparam.TextFile, sep=" ")
writeLines("", PSOparam.TextFile)
writeLines(c("TVc1.exp :", TVc1.exp), PSOparam.TextFile, sep=" ")
writeLines("", PSOparam.TextFile)
} else {
writeLines(c("c1 :", c1), PSOparam.TextFile, sep=" ")
writeLines("", PSOparam.TextFile)
} # ELSE end
if (use.TVc2) {
writeLines(c("use.TVc2 :", use.TVc2), PSOparam.TextFile, sep=" ")
writeLines("", PSOparam.TextFile)
writeLines(c("TVc2.type :", TVc2.type), PSOparam.TextFile, sep=" ")
writeLines("", PSOparam.TextFile)
writeLines(c("TVc2.rng :", TVc2.rng), PSOparam.TextFile, sep=" ")
writeLines("", PSOparam.TextFile)
writeLines(c("TVc2.exp :", TVc2.exp), PSOparam.TextFile, sep=" ")
writeLines("", PSOparam.TextFile)
} else {
writeLines(c("c2 :", c2), PSOparam.TextFile, sep=" ")
writeLines("", PSOparam.TextFile)
} # ELSE end
if (use.TVlambda) {
writeLines(c("use.TVlambda :", use.TVlambda), PSOparam.TextFile, sep=" ")
writeLines("", PSOparam.TextFile)
writeLines(c("TVlambda.type :", TVlambda.type), PSOparam.TextFile, sep=" ")
writeLines("", PSOparam.TextFile)
writeLines(c("TVlambda.rng :", TVlambda.rng), PSOparam.TextFile, sep=" ")
writeLines("", PSOparam.TextFile)
writeLines(c("TVlambda.exp :", TVlambda.exp), PSOparam.TextFile, sep=" ")
writeLines("", PSOparam.TextFile)
} else {
writeLines(c("lambda :", lambda), PSOparam.TextFile, sep=" ")
writeLines("", PSOparam.TextFile)
} # ELSE end
if (use.IW) {
writeLines(c("use.IW :", use.IW), PSOparam.TextFile, sep=" ")
writeLines("", PSOparam.TextFile)
writeLines(c("IW.type :", IW.type), PSOparam.TextFile, sep=" ")
writeLines("", PSOparam.TextFile)
writeLines(c("IW.w :", IW.w), PSOparam.TextFile, sep=" ")
writeLines("", PSOparam.TextFile)
writeLines(c("IW.exp :", IW.exp), PSOparam.TextFile, sep=" ")
writeLines("", PSOparam.TextFile)
} # IF end
writeLines(c("maxfn :", maxfn), PSOparam.TextFile, sep=" ")
writeLines("", PSOparam.TextFile)
writeLines(c("abstol :", abstol), PSOparam.TextFile, sep=" ")
writeLines("", PSOparam.TextFile)
writeLines(c("reltol :", reltol), PSOparam.TextFile, sep=" ")
writeLines("", PSOparam.TextFile)
close(PSOparam.TextFile)
# File 'Model_out.txt' #
OFout.Text.fname <- paste(file.path(drty.out), "/", "Model_out.txt", sep="")
OFout.Text.file <- file(OFout.Text.fname, "w+")
writeLines(c("Iter", "Part", "GoF", "Model_Output"), OFout.Text.file, sep=" ")
writeLines("", OFout.Text.file)
close(OFout.Text.file)
# File 'Particles.txt' #
Particles.Textfname <- paste(file.path(drty.out), "/", "Particles.txt", sep="")
Particles.TextFile <- file(Particles.Textfname, "w+")
writeLines(c("Iter", "Part", "GoF", param.IDs), Particles.TextFile, sep=" ")
writeLines("", Particles.TextFile)
close(Particles.TextFile)
# File 'Velocities.txt' #
Velocities.Textfname <- paste(file.path(drty.out), "/", "Velocities.txt", sep="")
Velocities.TextFile <- file(Velocities.Textfname, "w+")
writeLines(c("Iter", "Part", "GoF", param.IDs), Velocities.TextFile, sep=" ")
writeLines("", Velocities.TextFile)
close(Velocities.TextFile)
# File 'ConvergenceMeasures.txt' #
ConvergenceMeasures.Textfname <- paste(file.path(drty.out), "/", "ConvergenceMeasures.txt", sep="")
ConvergenceMeasures.TextFile <- file(ConvergenceMeasures.Textfname, "w+")
writeLines(c("Iter", "Gbest", "GbestRate[%]", "IterBestFit", "normSwarmRadius", "|gbest-mean(pbest)|/mean(pbest)[%]"), ConvergenceMeasures.TextFile, sep=" ")
writeLines("", ConvergenceMeasures.TextFile)
close(ConvergenceMeasures.TextFile)
# File 'BestParamPerIter.txt' #
BestParamPerIter.Textfname <- paste(file.path(drty.out), "/", "BestParamPerIter.txt", sep="")
BestParamPerIter.TextFile <- file(BestParamPerIter.Textfname, "w+")
writeLines(c("Iter", "GoF", param.IDs), BestParamPerIter.TextFile, sep=" ")
writeLines("", BestParamPerIter.TextFile)
close(BestParamPerIter.TextFile)
# File 'PbestPerIter.txt' #
PbestPerIter.Textfname <- paste(file.path(drty.out), "/", "PbestPerIter.txt", sep="")
PbestPerIter.TextFile <- file(PbestPerIter.Textfname, "w+")
writeLines(c("Iter", paste("Part", 1:npart, sep="") ), PbestPerIter.TextFile, sep=" ")
writeLines("", PbestPerIter.TextFile)
close(PbestPerIter.TextFile)
# File 'LocalBestPerIter.txt' #
LocalBestPerIter.Textfname <- paste(file.path(drty.out), "/", "LocalBestPerIter.txt", sep="")
LocalBestPerIter.TextFile <- file(LocalBestPerIter.Textfname, "w+")
writeLines(c("Iter", paste("Part", 1:npart, sep="") ), LocalBestPerIter.TextFile, sep=" ")
writeLines("", LocalBestPerIter.TextFile)
close(LocalBestPerIter.TextFile)
if (use.RG) {
# File 'Xmin.txt' #
Xmin.Text.fname <- paste(file.path(drty.out), "/", "Xmin.txt", sep="")
Xmin.Text.file <- file(Xmin.Text.fname, "w+")
writeLines(c("Iter", param.IDs), Xmin.Text.file, sep=" ")
writeLines("", Xmin.Text.file)
writeLines(as.character(c(1, X.Boundaries[,1])), Xmin.Text.file, sep=" ")
writeLines("", Xmin.Text.file)
close(Xmin.Text.file)
# File 'Xmax.txt' #
Xmax.Text.fname <- paste(file.path(drty.out), "/", "Xmax.txt", sep="")
Xmax.Text.file <- file(Xmax.Text.fname, "w+")
writeLines(c("Iter", param.IDs ), Xmax.Text.file, sep=" ")
writeLines("", Xmax.Text.file)
writeLines(as.character(c(1, X.Boundaries[,2])), Xmax.Text.file, sep=" ")
writeLines("", Xmax.Text.file)
close(Xmax.Text.file)
} # IF end
if (fn.name=="hydromod") {
##############################################################################
# 2) Writing Info File
##############################################################################
if (verbose) message("================================================================================")
if (verbose) message("[ Writing the 'hydroPSO_logfile.txt' file ... ]")
if (verbose) message("================================================================================")
# File 'hydroPSO_logfile.txt' #
hydroPSOparam.fname <- paste(file.path(drty.out), "/", "hydroPSO_logfile.txt", sep="")
hydroPSOparam.TextFile <- file(hydroPSOparam.fname , "w+")
writeLines("================================================================================", hydroPSOparam.TextFile)
writeLines(c("Platform :", sessionInfo()[[1]]$platform), hydroPSOparam.TextFile, sep=" ")
writeLines("", hydroPSOparam.TextFile)
writeLines(c("R version :", sessionInfo()[[1]]$version.string), hydroPSOparam.TextFile, sep=" ")
writeLines("", hydroPSOparam.TextFile)
writeLines(c("hydroPSO version :", sessionInfo()$otherPkgs$hydroPSO$Version), hydroPSOparam.TextFile, sep=" ")
writeLines("", hydroPSOparam.TextFile)
writeLines(c("hydroPSO Built :", sessionInfo()$otherPkgs$hydroPSO$Built), hydroPSOparam.TextFile, sep=" ")
writeLines("", hydroPSOparam.TextFile)
writeLines("================================================================================", hydroPSOparam.TextFile)
Time.Ini <- Sys.time()
writeLines(c("Starting Time :", date()), hydroPSOparam.TextFile, sep=" ")
writeLines("", hydroPSOparam.TextFile)
writeLines("================================================================================", hydroPSOparam.TextFile)
writeLines(c("PSO Input Directory :", drty.in), hydroPSOparam.TextFile, sep=" ")
writeLines("", hydroPSOparam.TextFile)
writeLines(c("PSO Output Directory :", drty.out), hydroPSOparam.TextFile, sep=" ")
writeLines("", hydroPSOparam.TextFile)
writeLines(c("Parameter Ranges :", basename(param.ranges)), hydroPSOparam.TextFile, sep=" ")
writeLines("", hydroPSOparam.TextFile)
try(writeLines(c("hydromod function :", model.FUN.name), hydroPSOparam.TextFile, sep=" ") , TRUE)
writeLines("", hydroPSOparam.TextFile)
writeLines(c("hydromod args :"), hydroPSOparam.TextFile, sep=" ")
writeLines("", hydroPSOparam.TextFile)
for ( i in 1:length(model.FUN.args) ) {
arg.name <- names(model.FUN.args)[i]
arg.name <- format(paste(" ", arg.name, sep=""), width=22, justify="left" )
arg.value <- ""
arg.value <- try(as.character( as.character(model.FUN.args[i])), TRUE)
writeLines(c(arg.name, ":", arg.value), hydroPSOparam.TextFile, sep=" ")
writeLines("", hydroPSOparam.TextFile)
} # FOR end
# Closing the text file
close(hydroPSOparam.TextFile)
} # IF 'fn.name' END
} # IF 'write2disk' end
########################################################################
GPbest.fit.rate <- Inf
iter <- 1
nfn <- 1
iter.rg <- 1
nregroup <- 0
iter.tv <- iter
niter.tv <- maxit
if (write2disk) {
OFout.Text.file <- file(OFout.Text.fname, "a")
Particles.TextFile <- file(Particles.Textfname, "a")
Velocities.TextFile <- file(Velocities.Textfname, "a")
ConvergenceMeasures.TextFile <- file(ConvergenceMeasures.Textfname, "a")
BestParamPerIter.TextFile <- file(BestParamPerIter.Textfname, "a")
PbestPerIter.TextFile <- file(PbestPerIter.Textfname, "a")
LocalBestPerIter.TextFile <- file(LocalBestPerIter.Textfname, "a")
if (use.RG) {
Xmin.Text.file <- file(Xmin.Text.fname, "a")
Xmax.Text.file <- file(Xmax.Text.fname, "a")
} # IF end
} # IF end
######################### START Main Iteration Loop ########################
abstol.conv <- FALSE
reltol.conv <- FALSE
improvement <- FALSE
end.type.stg <- "Unknown"
end.type.code <- "-999"
############################################################################
# 3) Main Algorithm #
############################################################################
if (verbose) message(" ")
if (verbose) message("================================================================================")
if (verbose) message("[ Running PSO ... ]")
if (verbose) message("================================================================================")
if (verbose) message(" ")
while ( (iter <= maxit) && (!abstol.conv) && (!reltol.conv) && (nfn <= maxfn) ) {
if ( (topology=="random") & (!improvement) )
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 an R Function
GoF <- apply(X, fn, MARGIN=1, ...)
Xt.fitness[iter, 1:npart] <- GoF
ModelOut[1:npart] <- GoF ###
nfn <- nfn + npart
} else { # fn.name = "hydromod"
if ("verbose" %in% names(model.FUN.args)) {
verbose.FUN <- model.FUN.args[["verbose"]]
} else verbose.FUN <- verbose
out <- lapply(1:npart, hydromod.eval,
Particles=X,
iter=iter,
npart=npart,
maxit=maxit,
REPORT=REPORT,
verbose=verbose.FUN,
digits=digits,
model.FUN=model.FUN,
model.FUN.args=model.FUN.args
)
for (part in 1:npart){
GoF <- out[[part]][["GoF"]]
Xt.fitness[iter, part] <- GoF
ModelOut[[part]] <- out[[part]][["model.out"]]
if(is.finite(GoF)) nfn <- nfn + 1
} #FOR part end
} # ELSE end
if ( best.update == "sync" ) {
tmp <- sync.update.pgbests(x=X,
xt.fitness= Xt.fitness[iter, ],
MinMax= MinMax,
pbest.fit= pbest.fit,
gbest.fit= gbest.fit,
gbest.pos= gbest.pos,
x.best= X.best.part
)
pbest.fit <- tmp[["pbest"]]
X.best.part <- tmp[["x.best"]]
gbest.fit <- tmp[["gbest.fit"]]
gbest.pos <- tmp[["gbest.pos"]]
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
} # 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 ########################
##########################################################################
ifelse( (best.update == "async") & random.update,
index.part.upd <- sample(npart),
index.part.upd <- 1:npart)
for (j in index.part.upd) {
if (write2disk) {
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=" "),
formatC(ModelOut[[j]], format="E", digits=digits, flag=" ") ) ),
OFout.Text.file, sep=" ")
} else writeLines(as.character(c(iter, j, "NA", "NA" ) ), OFout.Text.file, sep=" ")
writeLines("", OFout.Text.file)
flush(OFout.Text.file)
# File 'Particles.txt' #
if(is.finite(GoF)) {
writeLines(as.character( c(iter, j,
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",
formatC(X[j, ], format="E", digits=digits, flag=" ")
) ), Particles.TextFile, sep=" ")
writeLines("", Particles.TextFile)
flush(Particles.TextFile)
# File 'Velocities.txt' #
if(is.finite(GoF)) {
writeLines( as.character( c(iter, j,
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",
formatC(V[j, ], format="E", digits=digits, flag=" ")
) ), Velocities.TextFile, sep=" ")
writeLines("", Velocities.TextFile)
flush(Velocities.TextFile)
} # IF end
if ( best.update == "async" ) {
tmp <- async.update.pgbests(x=X[j,],
x.pos=j,
xt.fitness= Xt.fitness[iter, j],
MinMax= MinMax,
l.pbest.fit= pbest.fit[j],
gbest.fit= gbest.fit,
gbest.pos= gbest.pos,
x.best= X.best.part[j, ]
)
pbest.fit[j] <- tmp[["pbest"]]
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 ( 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 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,
w.max=max(w.ini, w.fin),
w.min=min(w.ini, w.fin),
MinMax=MinMax
)
} else if (IW.type == "GLratio") {
w <- compute.w.with.GLratio(MinMax, gbest.fit, pbest.fit)
} # 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
ifelse( (topology=="lbest") & (iter <= iter.ini), ltopology <- "gbest",
ltopology <- topology)
V[j,] <- compute.veloc(
x= X[j, ],
v= V[j, ],
w= w,
c1= c1,
c2= c2,
CF= CF,
Pbest= X.best.part,
part.index=j,
gbest= X.best.part[gbest.pos, ],
topology=ltopology,
method=method,
MinMax=MinMax, # topology="ipso" | method="wfips"
neighs.index=X.neighbours[j, ], # method in c("fips", "wfips")
localBest=X.best.part[LocalBest.pos[j], ], # topology="lbest"
localBest.pos=LocalBest.pos[j], # topology=c("random", "lbest")
ngbest.fit=ngbest.fit, # topology="ipso"
ngbest=X.best.part[ngbest.pos, ], # topology="ipso"
lpbest.fit= pbest.fit[X.neighbours[j, ]] # method="wfips"
)
V[j,] <- velocity.boundary.treatment(v= V[j,], vmax=Vmax)
########################################################################
# 4.c) Moving the particles: X[j,] <- X[j,] + V[j,]
out <- position.update.and.boundary.treatment(x= X[j,], v=V[j,], x.MinMax=X.Boundaries, boundary.wall=boundary.wall)
X[j,] <- out[["x.new"]]
V[j,] <- out[["v.new"]]
} # FOR j end: Particles Loop
##########################################################################
################### Particles Loop (j) - End ##########################
##########################################################################
if ( plot ) {
ifelse(MinMax == "max", lgof <- max(GoF, na.rm=TRUE), lgof <- min(GoF, na.rm=TRUE))
colorRamp= colorRampPalette(c("darkred", "red", "orange", "yellow", "green", "darkgreen", "cyan"))
XX.Boundaries.current <- computeCurrentXmaxMin(X)
xlim <- range(XX.Boundaries.current)
ylim <- range(XX.Boundaries.current)
if (iter==1) {
plot(X[,1], X[,2], xlim=X.Boundaries[1,], ylim=X.Boundaries[2,],
main=paste("Iter= ", iter, ". GoF= ",
format(lgof, scientific=TRUE, digits=digits), sep=""),
col=colorRamp(npart), cex=0.5 )
} else plot(X[,1], X[,2], xlim=X.Boundaries[1,], ylim=X.Boundaries[2,],
main=paste("Iter= ", iter, ". GoF= ",
format(lgof, scientific=TRUE, digits=digits), sep=""),
col=colorRamp(npart), cex=0.5 )
#plotParticles2D(X)
} # IF 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 #
##########################################################################
do.RandomGeneration <- ( use.RG && (NormSwarmRadius < RG.thr)
&& (iter.rg >= RG.miniter) )
if (do.RandomGeneration) {
if (topology == "gbest") {
gbest.fit.bak <- gbest.fit
gbest.pos.bak <- gbest.pos
x.bak <- X[gbest.pos,]
v.bak <- V[gbest.pos,]
} # IF end
if (topology == "ipso") {
x.bak <- X[ngbest.pos,]
v.bak <- V[ngbest.pos,]
gbest.fit.bak <- ngbest.fit
} # IF end
if (verbose) message("[Re-grouping particles in the swarm (iter: ", iter, ") ...]")
tmp <- RegroupingSwarm(x=X,
gbest= X.best.part[gbest.pos, ],
x.Range=X.Boundaries,
#x.Range=X.Boundaries.current,
Lmax=Lmax,
RG.thr=RG.thr,
RG.r=RG.r)
X <- tmp[["X"]]
if (topology == "gbest") {
X[gbest.pos,] <- x.bak
#V[gbest.pos,] <- v.bak
gbest.fit <- gbest.fit.bak
gbest.pos <- gbest.pos.bak
} # IF end
if (topology == "ipso") {
X[ngbest.pos,] <- x.bak
gbest.fit <- gbest.fit.bak
gbest.pos <- gbest.pos.bak
} # IF end
V <- InitializateV(npart=npart, param.IDs=param.IDs,
x.MinMax=X.Boundaries, v.ini.type=Vini.type,
Xini=X)
GPbest.fit.rate <- +Inf
ifelse(MinMax=="max", gbest.fit.prior <- +Inf, gbest.fit.prior <- 0)
niter.tv <- maxit - iter
iter.tv <- 1
iter.rg <- 1
nregroup <- nregroup + 1
} # IF end
##########################################################################
# Updates required before the next iteration
##########################################################################
ifelse(MinMax=="max", abstol.conv <- gbest.fit >= abstol,
abstol.conv <- gbest.fit <= abstol )
if (reltol==0) {
reltol.conv <- FALSE
} else {
tmp <- abs(pbest.fit.iter.prior - pbest.fit.iter)
ifelse(tmp==0, reltol.conv <- FALSE, reltol.conv <- tmp <= abs(reltol) )
} # ELSE end
pbest.fit.iter.prior <- pbest.fit.iter
# Gbest was improved ?
ifelse(gbest.fit.prior==gbest.fit, improvement <- FALSE, improvement <- TRUE)
gbest.fit.prior <- gbest.fit
if (abstol.conv ) {
end.type.stg <- "Converged ('abstol' criterion)"
end.type.code <- 0
} else if (reltol.conv) {
end.type.stg <- "Converged ('reltol' criterion)"
end.type.code <- 1
} else if (nfn >= maxfn) {
end.type.stg <- "Maximum number of function evaluations reached"
end.type.code <- 2
} else if (iter >= maxit) {
end.type.stg <- "Maximum number of iterations reached"
end.type.code <- 3
} # ELSE end
if (write2disk) {
# File 'ConvergenceMeasures.txt'
writeLines(as.character( c(iter,
formatC(gbest.fit, format="E", digits=digits, flag=" "),
format( round(gbest.fit.rate*100, 3), nsmall=3, width=7, justify="right"),
formatC(pbest.fit.iter, format="E", digits=digits, flag=" "),
formatC(NormSwarmRadius, format="E", digits=digits, flag=" "),
format( round(GPbest.fit.rate*100, 3), nsmall=3, width=7, justify="right")
) ), ConvergenceMeasures.TextFile, sep=" ")
writeLines("", ConvergenceMeasures.TextFile)
flush(ConvergenceMeasures.TextFile)
# File 'BestParamPerIter.txt' #
GoF <- gbest.fit
if(is.finite(GoF)) {
writeLines( as.character( c(iter,
formatC(GoF, format="E", digits=digits, flag=" "),
formatC(X.best.part[gbest.pos, ], format="E", digits=digits, flag=" ")
) ), BestParamPerIter.TextFile, sep=" ")
} else writeLines( as.character( c(iter,
"NA",
formatC(X.best.part[gbest.pos, ], format="E", digits=digits, flag=" ")
) ), BestParamPerIter.TextFile, sep=" ")
writeLines("", BestParamPerIter.TextFile)
flush(BestParamPerIter.TextFile)
# File 'PbestPerIter.txt' #
GoF <- pbest.fit
writeLines( as.character( c(iter,
formatC(GoF, format="E", digits=digits, flag=" ")
) ), PbestPerIter.TextFile, sep=" ")
writeLines("", PbestPerIter.TextFile)
flush(PbestPerIter.TextFile)
# File 'LocalBestPerIter.txt' #
GoF <- LocalBest.fit
writeLines( as.character( c(iter,
formatC(GoF, format="E", digits=digits, flag=" ")
) ), LocalBestPerIter.TextFile, sep=" ")
writeLines("", LocalBestPerIter.TextFile)
flush(LocalBestPerIter.TextFile)
} # IF end
iter <- iter + 1
iter.tv <- iter.tv + 1
iter.rg <- iter.rg + 1
} # WHILE end
########################## END Main Iteration Loop #########################
if (write2disk) {
close(OFout.Text.file)
close(Particles.TextFile)
close(Velocities.TextFile)
close(ConvergenceMeasures.TextFile)
close(BestParamPerIter.TextFile)
close(PbestPerIter.TextFile)
close(LocalBestPerIter.TextFile)
if (use.RG) {
close(Xmin.Text.file)
close(Xmax.Text.file)
} # IF end
} # IF end
############################################################################
# Sorting the particles according to their best fit
############################################################################
ifelse(MinMax=="max", sorted.fit <- sort(pbest.fit, decreasing= TRUE),
sorted.fit <- sort(pbest.fit, decreasing= FALSE) )
sorted.index <- pmatch(sorted.fit, pbest.fit)
################### START WRITING OUTPUT FILES ###################
if (write2disk) {
if (verbose) message(" ")
if (verbose) message("[ Writing output files... ]")
if (verbose) message(" ")
niter.real <- iter - 1
PSOparam.TextFile <- file(PSOparam.fname, "a")
writeLines("================================================================================", PSOparam.TextFile)
writeLines(c("Ending Time :", date()), PSOparam.TextFile, sep=" ")
writeLines("", PSOparam.TextFile)
Time.Fin <- Sys.time()
writeLines("================================================================================", PSOparam.TextFile)
writeLines(c("Elapsed Time :", format(round(Time.Fin - Time.Ini, 2))), PSOparam.TextFile, sep=" ")
writeLines("", PSOparam.TextFile)
writeLines("================================================================================", PSOparam.TextFile)
close(PSOparam.TextFile)
# Writing the file 'BestParameterSet.txt'
tmp.fname <- paste(file.path(drty.out), "/", "BestParameterSet.txt", sep="")
tmp.TextFile <- file(tmp.fname , "w+")
writeLines(c("BestParticle", "GoF ", param.IDs), tmp.TextFile, sep=" ")
writeLines("", tmp.TextFile)
tmp <- formatC(c(gbest.fit, X.best.part[gbest.pos,]), format="E", digits=digits, flag=" ")
writeLines(as.character(c(gbest.pos, tmp)), tmp.TextFile, sep=" ")
writeLines("", tmp.TextFile)
close(tmp.TextFile)
# Writing a file with the maximum ranges used during PSO
fname <- paste(file.path(drty.out), "/", "XMinMax.txt", sep="")
write.table(format(X.Boundaries, scientific=TRUE, digits=digits), file=fname, col.names=TRUE, row.names=FALSE, sep=" ", quote=FALSE)
# Writing the file 'Particles_GofPerIter.txt', with the GoF for each particle in each iteration
tmp.fname <- paste(file.path(drty.out), "/", "Particles_GofPerIter.txt", sep="")
tmp.TextFile <- file(tmp.fname , "w+")
writeLines(paste("Iter", paste(colnames(Xt.fitness), collapse=" "), sep=" "), tmp.TextFile, sep=" ")
writeLines("", tmp.TextFile)
for ( i in (1:niter.real) ) {
tmp <- formatC(Xt.fitness[i, ], format="E", digits=digits, flag=" ")
writeLines(as.character(c(i, tmp)), tmp.TextFile, sep=" ")
writeLines("", tmp.TextFile)
} # FOR end
close(tmp.TextFile)
# Writing the file 'BestParamPerParticle.txt', with ...
fname <- paste(file.path(drty.out), "/", "BestParamPerParticle.txt", sep="")
tmp <- cbind(X.best.part, pbest.fit)
colnames(tmp)[ncol(tmp)] <- "GoF"
write.table(format(tmp, scientific=TRUE, digits=digits), file=fname, col.names=TRUE, row.names=FALSE, sep=" ", quote=FALSE)
# Writing the file 'X.neighbours.txt'
fname <- paste(file.path(drty.out), "/", "Particles_Neighbours.txt", sep="")
write.table(X.neighbours, file=fname, col.names=TRUE, row.names=TRUE, sep=" ", na="", quote=FALSE)
# Writing the file 'LocalBest.txt'
fname <- paste(file.path(drty.out), "/", "LocalBest.txt", sep="")
write.table(format(LocalBest.fit, scientific=TRUE, digits=digits), file=fname, col.names=TRUE, row.names=FALSE, sep=" ", quote=FALSE)
if (fn.name=="hydromod") {
hydroPSOparam.TextFile <- file(hydroPSOparam.fname, "a")
writeLines("================================================================================", hydroPSOparam.TextFile)
writeLines(c("Ending Time :", date()), hydroPSOparam.TextFile, sep=" ")
writeLines("", hydroPSOparam.TextFile)
writeLines("================================================================================", hydroPSOparam.TextFile)
Time.Fin <- Sys.time()
writeLines(c("Elapsed Time :", format(round(Time.Fin - Time.Ini, 2))), hydroPSOparam.TextFile, sep=" ")
writeLines("", hydroPSOparam.TextFile)
writeLines("================================================================================", hydroPSOparam.TextFile)
close(hydroPSOparam.TextFile)
} # IF 'fn.name' END
} # IF end
##################### END WRITING OUTPUT FILES #####################
############################################################################
if (verbose) message(" | ")
if (verbose) message("================================================================================")
if (verbose) message("[ Creating the R output ... ]")
if (verbose) message("================================================================================")
# Creating the R output
nelements <- 6
out <- vector("list", nelements)
out[[1]] <- X.best.part[gbest.pos,]
names(out[[1]]) <- param.IDs
out[[2]] <- gbest.fit
out[[3]] <- gbest.pos
out[[4]] <- c("function.calls"=nfn-1, "iterations"=iter-1, "regroupings"=nregroup)
out[[5]] <- end.type.code
out[[6]] <- end.type.stg
names(out)[1:nelements] <- c("par", # "Best.Parameter.Values",
"value", # "Global.Best.Value",
"best.particle", # "Global.Best.Position",
"counts",
"convergence",
"message")
if (out.with.pbest) {
out[[nelements+1]] <- X.best.part
out[[nelements+2]] <- pbest.fit
names(out)[(nelements+1):(nelements+2)] <- c("pbest.Parameter.Values", "pbest.fit")
nelements <- nelements + 2
} # IF end
if (out.with.fit.iter) {
out[[nelements+1]] <- Xt.fitness
names(out)[nelements+1] <- c("part.fit.per.iter")
} # IF end
############################################################################
if (fn.name=="hydromod") {
if (verbose) message(" ")
if (verbose) message(" | ")
if (verbose) message("================================================================================")
if (verbose) message("[ Running one last time the model with the 'best' parameter set ... ]")
if (verbose) message("================================================================================")
if (verbose) message(" | ")
if (verbose) message(" ")
model.FUN.args <- modifyList(model.FUN.args,
list(param.values=out[["par"]])
)
hydromod.out <- do.call(model.FUN, as.list(model.FUN.args))
if ("obs" %in% names(model.FUN.args)) {
fname <- paste(file.path(drty.out), "/", "Observations.txt", sep="")
obs <- model.FUN.args[["obs"]]
if (is.zoo(obs)) {
if (gof.Ini.exists) obs <- window( obs, start=as.Date(model.FUN.args[["gof.Ini"]]) )
if (gof.Fin.exists) obs <- window( obs, end=as.Date(model.FUN.args[["gof.Fin"]]) )
write.zoo(x=obs, file=fname)
} else {
obs <- cbind(1:length(obs), obs)
write.table(obs, file=fname, col.names=FALSE, row.names=FALSE, sep=" ", quote=FALSE)
} # ELSE end
} # IF end
} # IF end
############################################################################
# 7) Output #
############################################################################
return(out)
} # 'PSO' end