sce#
The Shuffled Complex Evolution (SCE) global optimizer
This code is based on a Fortran program of Qingyun Duan (2004), ported to Python by Stijn Van Hoey (2011). It was taken up, debugged, enhanced and is maintained by Matthias Cuntz while at Department of Computational Hydrosystems (CHS), Helmholtz Centre for Environmental Research - UFZ, Leipzig, Germany, and continued while at Institut National de Recherche pour l’Agriculture, l’Alimentation et l’Environnement (INRAE), Nancy, France.
- copyright:
Copyright 2004-2023 Qingyun Duan [1], Stijn Van Hoey, Matthias Cuntz, see AUTHORS.rst for details.
- license:
MIT License, see LICENSE for details.
References
Duan, Sorooshian and Gupta (1992) Effective and efficient global optimization for conceptual rainfall-runoff models, Water Resour Res 28, 1015-1031, https://doi.org/10.1029/91WR02985
The following functions are provided:
|
Shuffled Complex Evolution algorithm for finding the minimum of a multivariate function |
- History
Written in Fortran by Q Duan, Sep 2004
Ported to Python by Stijn Van Hoey, 2011 stijnvanhoey/Optimization_SCE
Synchronised with enhanced Fortran version of CHS, Oct 2013, Matthias Cuntz
Added functionality to call external executable, Nov 2016, Matthias Cuntz
Treat NaN and Inf in function output, Nov 2016, Matthias Cuntz
Possibility to exclude (mask) parameters from optimisation, Nov 2016, Matthias Cuntz
Added restart possibility, Nov 2016, Matthias Cuntz
Return also function value of best parameter set if maxit==True, Nov 2016, Matthias Cuntz
Removed functionality to call external executable, Dec 2017, Matthias Cuntz
Print out number of function evaluations with printit=1, Mar 2018, Matthias Cuntz
Mask parameters with degenerated ranges, e.g. upper<lower bound, Mar 2018, Matthias Cuntz
Use only masked parameters in calculation of geometric range, Mar 2018, Matthias Cuntz
Removed bug that calculated the size of the complexes using all parameters and not only the masked parameters, Mar 2018, Matthias Cuntz
Fixed bug where masked parameters were always out of bounds, Mar 2018, Matthias Cuntz
Allow scalar bounds, which will be taken for all parameters, Mar 2018, Matthias Cuntz
Get number of parameters from lower boundary in SampleInputMatrix, Mar 2018, Matthias Cuntz
Define number of parameters by inquiring x0 in case of restart, May 2018, Matthias Cuntz
Removed multiplication with one hundred in criter_change, regarded a bug compared to Fortran code, May 2018, Matthias Cuntz
Removed exec command to make restart work with Python 3, May 2020, Matthias Cuntz
Use underscore before private routines, May 2020, Matthias Cuntz
Code refactoring, Sep 2021, Matthias Cuntz
Added keywords args and kwargs to pass to function, Apr 2022, Matthias Cuntz
Pass RandomState to _SampleInputMatrix, Jul 2022, Matthias Cuntz
Different sampling of input parameters, Jul 2022, Matthias Cuntz
Use helper class to pass arguments to objective function, Dec 2022, Matthias Cuntz
Copy strtobool from distutils.util because distutils is deprecated, Dec 2022, Matthias Cuntz
Include number of complexes ngs in restartfile, Dec 2022, Matthias Cuntz
No restart files written by default, Dec 2022, Matthias Cuntz
Rewrite into class SCESolver, Dec 2022, Matthias Cuntz
Output OptimizeResult class, Dec 2022, Matthias Cuntz
Polish results with L-BFGS-B, Dec 2022, Matthias Cuntz
Warn only if lb > ub, simply set mask if lb == ub, May 2023, Matthias Cuntz
Exit if initial population failed twice, May 2023, Matthias Cuntz
random_sample(1)[0] to assure scalar, Jul 2023, Matthias Cuntz
call_func method to assure scalar output, Jul 2023, Matthias Cuntz
Require keyword names after mask, Jul 2023, Matthias Cuntz
Set maxn to N*log(N) formula per default, Sep 2023, Matthias Cuntz
- sce(func, x0, lb, ub=None, mask=None, *, args=(), kwargs={}, sampling='half-open', maxn=0, kstop=10, pcento=0.0001, peps=0.001, ngs=2, npg=0, nps=0, nspl=0, mings=0, seed=None, iniflg=True, alpha=0.8, beta=0.45, maxit=False, printit=2, polish=True, restart=False, restartfile1='', restartfile2='')[source]#
Shuffled Complex Evolution algorithm for finding the minimum of a multivariate function
The SCE or SCE-UA method is a general purpose global optimization, which can be used with high-dimensional problems. It was used successfully, for example, to calibrate hydrologic models with more than 50 parameters [5]. The algorithm has been described in detail in Duan et al. [1] and [2]. Another paper of Duan et al. [3] discusses how to use the method effectively. The implementation here also includes the recommendations of Behrangi et al. [4].
- Parameters:
func (callable) – Function in the form
func(x, *args, **kwargs)
, wherex
are the parameters in the form of an iterable.args
andkwargs
are passed to the function via the usual unpacking operators.x0 (array_like) – Parameter values with mask==1 used in initial complex if iniflg==1.
lb (array_like, sequence or Bounds) – Lower bounds of parameters if
ub
given. If ub is not given, then lb are the bounds of the parameters, either 1) as an instance of the Bounds class, or 2) as(min, max)
pairs for each element inx
, defining the finite lower and upper bounds for the parameters of func.ub (array_like, optional) – Upper bounds of parameters.
mask (array_like, optional) – Include (1, True) or exclude (0, False) parameters in minimization (default: include all parameters). The number of parameters
nopt
issum(mask)
.args (tuple, optional) – Extra arguments passed to the function func. Note that
args
must be iterable. args=scalar and args=(scalar) are not valid but should be, for example, args=(scalar,).kwargs (dict, optional) – Extra keyword arguments passed to the function func.
sampling (string or array_like of strings, optional) –
Options for sampling random numbers. Options can be one of:
’half-open’: same as ‘right-half-open’ [lb, ub)
’left-half-open’: sample random floats in half-open interval (lb, ub]
’right-half-open’: sample random floats in half-open interval [lb, ub)
’open’: sample random floats in open interval (lb, ub)
’log’: sample half-open interval [log(lb), log(ub)), which samples better intervals spanning orders or magnitude such as lb=1e-9 and ub=1e-4
The default is ‘half-open’.
maxn (int, optional) – Maximum number of function evaluations allowed during minimization (without polishing) (default: 6400 + 160 * nopt * log10(nopt)).
kstop (int, optional) – Maximum number of evolution loops before convergence (default: 10).
pcento (float, optional) – Percentage change allowed in kstop loops before convergence (default: 0.0001).
peps (float, optional) – Value of normalised geometric range needed for convergence (default: 0.001).
ngs (int, optional) – Number of complexes (default: 2).
npg (int, optional) – Number of points in each complex (default: 2*nopt+1).
nps (int, optional) – Number of points in each sub-complex (default: nopt+1).
mings (int, optional) – Minimum number of complexes required if the number of complexes is allowed to reduce as the optimization proceeds (default: ngs).
nspl (int, optional) – Number of evolution steps allowed for each complex before complex shuffling (default: 2*nopt+1).
seed ({None, int, numpy.random.Generator, numpy.random.RandomState}, optional) – If seed is None (or numpy.random), the numpy.random.RandomState singleton is used. If seed is an int, a new RandomState instance is used, seeded with seed. If seed is already a Generator or RandomState instance then that instance is used. Specify seed for repeatable results.
iniflg (bool, optional) – If True: include initial parameters
x0
in initial population (default: True).alpha (float, optional) – Parameter for reflection of points in complex (default: 0.8).
beta (float, optional) – Parameter for contraction of points in complex (default: 0.45).
maxit (bool, optional) – If True: maximize instead of minimize func (default: False).
printit (int, optional) –
Controlling print-out (default: 2):
0: print information for the best point of the population
1: print information for each function evaluation
2: no printing.
The default is 2.
polish (bool, optional) – If True (default), then scipy.optimize.minimize is used with the L-BFGS-B method to polish the result at the end, which can improve the minimization slightly. For large problems, polishing can take a long time due to the computation of the Jacobian.
restart (bool, optional) – If True, continue from saved state in restartfile1 and restartfile2 (default: False).
restartfile1 (str, optional) – Filename for saving state of array variables of optimizer (default: ‘’). If restart==True and restartfile1==’’ then restartfile1=’sce.restart.npz’ will be taken.
restartfile2 (int, optional) – Filename for saving state of non-array variables of optimizer (default: restartfile1 + ‘.txt’).
- Returns:
res – The optimization result represented as a OptimizeResult object. Important attributes are:
x
the solution array,success
a Boolean flag indicating if the optimizer exited successfully (0) andmessage
which describes the cause of the termination. See OptimizeResult for a description of other attributes. If polish was employed, and a lower minimum was obtained by the polishing, then OptimizeResult also contains thejac
attribute.- Return type:
OptimizeResult
References
[1]Duan QY, Sorooshian S, and Gupta VK, Effective and efficient global optimization for conceptual rainfall-runoff models, Water Resources Research 28(4), 1015-1031, 1992, https://doi.org/10.1029/91WR02985
[2]Duan QY, Gupta VK, and Sorooshian S, Shuffled Complex Evolution approach for effective and efficient global minimization, Journal of Optimization Theory and its Applications 76(3), 501-521, 1993, https://doi.org/10.1007/BF00939380
[3]Duan QY, Gupta VK, and Sorooshian S, Optimal use of the SCE-UA global optimization method for calibrating watershed models, Journal of Hydrology 158, 265-284, 1994, https://doi.org/10.1016/0022-1694(94)90057-4
[4]Behrangi A, Khakbaz B, Vrugt JA, Duan Q, and Sorooshian S, Comment on “Dynamically dimensioned search algorithm for computationally efficient watershed model calibration” by Bryan A. Tolson and Christine A. Shoemaker, Water Resources Research 44, W12603, 2008, http://doi.org/10.1029/2007WR006429
[5]Cuntz M, Mai J, Zink M, Thober S, Kumar R, Schäfer D, Schrön M, Craven J, Rakovec O, Spieler D, Prykhodko V, Dalmasso G, Musuuza J, Langenberg B, Attinger S, and Samaniego L, Computationally inexpensive identification of noninformative model parameters by sequential screening. Water Resources Research 51, 6417–6441, 2015, https://doi.org/10.1002/2015WR016907
Examples
Search the minimum of the Rosenbrock function, implemented in rosen in scipy.optimize.
>>> import numpy as np >>> from scipy.optimize import rosen
One has to provide the function rosen, an initial guess of the parameters, and the lower and upper limits of the parameters. The 2D version is:
>>> lb = np.array([-5., -2.]) >>> ub = np.array([5., 8.]) >>> x0 = np.array([-2., 7.]) >>> res = sce(rosen, x0, lb, ub, seed=1, maxn=1000, printit=2) >>> print(res.nfev) 298 >>> print('{:.3f}'.format(res.fun)) 0.001
A 10-dimensional version using (min, max) pairs for parameter bounds as well as setting a number of keyword parameters for the SCE algorithm is:
>>> nopt = 10 >>> lb = np.full(10, -5.) >>> ub = np.full(10, 5.) >>> x0 = np.full(10, 0.5) >>> res = sce(rosen, x0, zip(lb, ub), maxn=30000, kstop=10, pcento=0.0001, ... seed=12358, ngs=5, npg=5*nopt+1, nps=nopt+1, nspl=5*nopt+1, ... mings=2, iniflg=True, printit=2, alpha=0.8, beta=0.45) >>> print(res.nfev) 30228 >>> print('{:.3g}'.format(res.fun)) 3.38e-12