www.gusucode.com > Ogive_optimization_1.0.6 > differentialevolution/Ogive_differentialevolution.m

    function varargout = Ogive_differentialevolution(varargin)
%DIFFERENTIALEVOLUTION  Start Differential Evolution optimization.
%   [bestmem, bestval, bestFctParams, nrOfIterations] =
%   DIFFERENTIALEVOLUTION(...) starts a Differential Evolution (DE) optimization
%   to minimize the cost returned by a given function. For a quick start, check
%   out and modify the functions DEMO1, DEMO2 and DEMO3.
%
%   Output arguments:
%   =================
%
%   bestmem:
%   Best population member.
%
%   bestval:
%   Lowest evaluated cost value.
%
%   bestFctParams:
%   Structure like input objFctParams containing the best parameter set.
%
%   nrOfIterations:
%   Number of iterations done.
%
%   resultFileName:
%   Name of file containing optimization results or empty string (if
%   DEParams.saveHistory is set to zero, see below).
%
%
%   Input arguments:
%   ================
%
%   DEParams (required):
%   Struct with parameters as returned by function GETDEFAULTPARAMS.
%
%   paramDefCell (required):
%   Cell specifying the parameters to optimize (see details below).
%
%   objFctHandle (required):
%   Handle to the objective function, which is called as follows:
%
%   value = objFctHandle(objFctSettings,    objFctParams) or
%   value = objFctHandle(objFctSettings{:}, objFctParams).
%
%   Here, objFctParams is a structure containing the current parameters (see the
%   input argument objFctParams below).
%
%   The second case is used if objFctSettings is a cell array, thus allowing for
%   an arbitrary number of additional constant input arguments (see input
%   argument objFctSettings below).
%
%   If the objective function handle is empty, the distance to a randomly chosen
%   optimal parameter vector is used as cost value (for testing purposes).
%
%   objFctSettings (optional):
%   Additional fixed settings to be passed (a cell array will be expanded using
%   {:}) to the objective function. If no additional settings are needed, set
%   objFctSettings to an empty cell: {}. If a cell array is needed as an
%   additional input, wrap it in another cell (e.g. objFctSettings = { myCell };
%
%   objFctParams (optional):
%   Struct with initial parameters in its fields. Each field needs to contain a
%   numeric scalar or column vector. Example:
%
%     objFctParams.parameter1 = 1;
%     objFctParams.parameter2 = 2;
%
%   emailParams (optional):
%   Struct with fields serveraddress, fromaddress, toaddress, and, if needed,
%   username and password. The parameters are used for sending E-mail
%   notifications about the optimization progress.
%
%   optimInfo (optional):
%   Info about the current optimization task. The fields 'title' and 'subtitle'
%   are displayed and included in saved files if existing. No influence on
%   optimization.
%
%   resultFileName (optional):
%   The result file resultFileName saved during a former optimization by
%   differentialevolution.m is loaded and the previous optimization is
%   continued. The population of parameter vectors saved in the file is
%   restored. The optimization parameters may be changed, but not every change
%   is allowed. CAUTION! Changing optimization parameters when continuing an
%   optimization may lead to wrong or misleading results! If any value of the
%   former input arguments is empty, the value saved in the result file is used.
%
%
%   Struct DEParams:
%   ================
%
%   The struct DEParams must contain the following fields (use function
%   GETDEFAULTPARAMS to generate a struct with default parameters):
%
%   VTR            "Value To Reach". The optimization is stopped if a cost
%                  value <= VTR in a minimization problem or a cost value >= VTR
%                  in a maximization problem is found. Set to empty matrix or
%                  NaN for no VTR.
%   NP             Number of population members (e.g. 10 * dimension).
%   F              DE-stepsize F from interval [0, 2]. A good initial guess
%                  is the interval [0.5, 1], e.g. 0.8.
%   CR             Crossover probability constant from interval [0, 1]. If
%                  the parameters are correlated, high values of CR work better.
%                  The reverse is true for no correlation.
%   strategy       1 --> DE/best/1/exp (def.)   6 --> DE/best/1/bin
%                  2 --> DE/rand/1/exp          7 --> DE/rand/1/bin
%                  3 --> DE/rand-to-best/1/exp  8 --> DE/rand-to-best/1/bin
%                  4 --> DE/best/2/exp          9 --> DE/best/2/bin
%                  5 --> DE/rand/2/exp          else  DE/rand/2/bin
%                  Experiments suggest that /bin likes to have a slightly larger
%                  CR than /exp
%   maxiter        Maximum number of iterations.
%   maxtime        Maximum time (in seconds) before finishing optimization.
%                  Set to empty or Inf for no time limit.
%   maxclock       Time (as returned by function clock.m) when to
%                  finish optimization. Set to empty for no end time.
%   minvalstddev   Population is reinitialized if the standard deviation of
%                  the cost values in the population is lower than minvalstddev.
%   minparamstddev Population is reinitialized if the maximum parameter
%                  standard deviation (normalized to the parameter range) is
%                  lower than minparamstddev.
%   nofevaliter    Population is reinitialized if there was no function
%                  evaluation during the last nofevaliter iterations.
%   nochangeiter   Population is reinitialized if there was no change in
%                  the population during the last nochangeiter iterations.
%   infoIterations Info is displayed and current state is saved every
%                  infoIterations iterations.
%   infoPeriod     Progress information is displayed every infoPeriod
%                  seconds.
%   sendMailPeriod Progress information is sent via E-mail every
%                  sendMailPeriod seconds (usually sendMailPeriod >>
%                  infoPeriod).
%   useInitParams  If one, the given parameters in struct objFctParams
%                  OR those in the fourth column of paramDefCell are used as one
%                  of the initial population members. If two, additionally the
%                  first twenty percent of the population members are computed
%                  as the given initial parameter vector plus small random
%                  noise.
%   saveHistory    Save intermediate results for reference or for continuing
%                  an interrupted optimization.
%   displayResults Draw graphs for visualization of the optimization
%                  result.
%   feedSlaveProc  Use slave process for parallel computation.
%   maxMasterEvals Maximum number of function evaluations to be done by the
%                  master process. Warning: Use this option with caution! If
%                  maxMasterEvals is set to a number less than the number of
%                  population members and one of the slave processes is
%                  interrupted, the optimization will get stuck!
%   slaveFileDir   Base directory for saving slave files.
%   minimizeValue  If true, the evaluation value is minimized, otherwise
%                  maximized.
%   validChkHandle Handle to a function which accepts the same arguments as
%                  the objective function (see input parameter objFctHandle
%                  above) and decides if a given parameter set is valid (e.g.
%                  subject to a constraint) or not. The function may only return
%                  1 (parameter set is valid/constraint is fulfilled) or 0
%                  (parameter set is invalid/constraint is not fulfilled) if
%                  not. Set validChkHandle to an empty string if no constraint
%                  is needed.
%   playSound      Play a short applause sound whenever a new best member
%                  was found.
%
%   If DEParams is empty or fields are missing, default parameters are used
%   (see function GETDEFAULTPARAMS) but warnings are displayed.
%
%
%   Cell array paramDefCell:
%   ========================
%
%   The cell array paramDefCell has to contain the names of the parameters to
%   optimize (first column), its ranges (second column), their quantizations
%   (third column) and optionally the initial values (fourth column). Each
%   parameter may be a real-valued scalar or column vector. See the examples
%   below for details.
%
%
%   Example 1 (only scalar parameters):
%
%   paramDefCell = {
%     'useSmoothing',     [0    1],     1,   0
%     'nrOfCoefficients', [5   20],     1,  10
%     'threshold',        [0.01 1], 0.001, 0.5 }
%
%   The first cell in each row contains the name of the parameter, the second a
%   two-element row vector specifying the allowed range, the third the
%   quantization and the fourth the initial values (the fourth column is
%   opotional).
%
%   The objective function objFctHandle will be called with a struct like
%   follows as last input argument:
%
%   objFctParams =
%         useSmoothing: 1
%     nrOfCoefficients: 17
%            threshold: 0.08
%
%   Provide a non-empty value either in objFctParams or in the fourth column of
%   paramDefCell as initial value. If both are present, a warning message is
%   issued and the value in paramDefCell is used. If objFctParams is empty and
%   no initial parameters are given in paramDefCell, the centers of the
%   parameter ranges are used as initial parameters.
%
%   Using parameter quantization allows for the use of binary variables like
%   'useSmoothing' above as well for parameters that are of integer nature, like
%   a number of coefficients. If the quantization of a parameter is set to zero,
%   the parameter is not quantized. Using a quantization grid for continuous
%   parameters can save computational effort. If DEParams.saveHistory is true,
%   all evaluated parameter vectors are saved with the corresponding cost value
%   and the same parameter value will never be evaluated twice. With
%   quantization, it is more likely that a generated parameter vector was
%   already evaluated and saved before.
%
%
%   Example 2 (vector parameter):
%
%   paramDefCell = {
%       'weight_vector', [0 1; 0 2], [0.01; 0.02], [0.5; 0.5] };
%
%   Here, the parameter 'weight_vector' is defined as a two-element column
%   vector. The ranges are set to [0, 1] for the first element and [0, 2]
%   for the second. The quantizations are 0.01 and 0.02 and the initial
%   values are both 0.5.
%
%   The provided structure objFctParams may contain further fixed parameters
%   and/or the current parameter values. The fields with the names of the
%   parameters given in paramDefCell are overwritten by the values of the
%   current parameters.
%
%
%   Example 3 (vector parameter):
%
%   paramDefCell = { '', [0 1; 0 2], [0.01; 0.02], [0.5; 0.5] };
%
%   In this special case (one single parameter with empty name), the
%   objective function is called as
%
%   value = objFctHandle(objFctSettings,    paramVec) or
%   value = objFctHandle(objFctSettings{:}, paramVec)
%
%   with the current parameters in column vector paramVec.
%
%
%   Miscellaneous:
%   ==============
%
%   If parameter DEParams.saveHistory is set to one, the current optimization
%   state including all tested members etc. is saved in the file
%   AAA_result_BBB_NN.mat, where AAA is the name of the objective function, BBB
%   is the name of the current host and NN is a number between 1 and 99 (to
%   avoid overwriting old results). The saved file can be used to continue a
%   former optimization run (see special calling modes below).
%
%   A 'time over'-file is saved at the start of the optimization. The
%   optimization is stopped if this file is deleted. Using this mechanism to
%   stop the simulation avoids interrupting Matlab during saving a file, which
%   can make a file unaccessible for the rest of the session and lead to
%   repeated warning messages. The name of the file to delete is
%   AAA_timeover_BBB.mat, where AAA is the name of the objective function and
%   BBB is the hostname. Result- and 'time over'-files are saved in directory
%   'data' if existing, otherwise in the current directory.
%
%   The optimization can be performed in parallel by more than one
%   processor/computer. Function DIFFERENTIALEVOLUTION has to be started in one
%   Matlab session, function DIFFERENTIALEVOLUTIONSLAVE in one or more other
%   Matlab sessions. Function DIFFERENTIALEVOLUTION acts as master and saves
%   information about which function to evaluate and which parameters to use
%   into files in a commonly accessible directory. The Distributed Computing
%   toolbox is not used. If input parameter slaveFileDir is empty, the directory
%   differentialevolution is used (or created) below the temporary directory
%   returned by function TEMPDIR2 (something like C:\Documents and
%   Settings\<UserName>\Local Settings\ Temp\<UserName>@<HostName>\MATLAB).
%
%   Function DIFFERENTIALEVOLUTION was developed for objective functions that
%   need relatively long for one function evaluation (several seconds or more).
%   When used with objective functions that evaluate very fast, memory problems
%   could occur. If DEParams.saveHistory is true, every evaluated parameter
%   vector is kept in memory. Further, the overhead for checking if a parameter
%   vector was already evaluated might be larger than a function evaluation
%   itself.
%
%
%   Special calling modes:
%   ======================
%
%   DIFFERENTIALEVOLUTION (without input arguments) or
%   DIFFERENTIALEVOLUTION(DEParams):
%   A demo optimization of Rosenbrock's saddle is run using default parameters
%   or the parameters in struct DEParams.
%
%   This function is based on the differential evolution (DE) algorithm of
%   Rainer Storn (http://www.icsi.berkeley.edu/~storn/code.html). The core
%   evolutionary algorithm was taken from function devec3.m.
%
%   <a href="differentialevolution.html">differentialevolution.html</a>
%   <a href="http://www.mathworks.com/matlabcentral/fileexchange/18593">File Exchange</a>
%   <a href="https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=KAECWD2H7EJFN">Donate via PayPal</a>
%
%   Markus Buehren
%   Last modified 30.08.2014
%
%   See also GETDEFAULTPARAMS, DEMO1, DEMO2, DEMO3, DISPLAYOPTIMIZATIONHISTORY,
%   DIFFERENTIALEVOLUTIONSLAVE.

TESTCASE=0;
if nargin==0
    load Ogive_differentialevolution_TESTDELETE
%     varargin{1}.maxiter=800;
%     varargin{1}.maxiterStablebest1=0;
%     varargin{1}.maxiterStablebest2=0;
    TESTCASE=1;
end


optimResult    = [];
resultFileName = '';
try
if ((nargin == 0) || ((nargin == 1) && isstruct(varargin{1}))) && TESTCASE==0
    
    % No input arguments given or parameter structure given as only input argument
    % for demo.
    if nargin == 1
        DEParams = varargin{1};
    else
        DEParams = Ogive_getdefaultparams;
    end
    
    % Set parameters set for demo.
    objFctParams.parameter1 = -1;
    objFctParams.parameter2 = -1;
    objFctHandle            = @rosenbrocksaddle;
    objFctSettings          = 100;
    paramDefCellInput       = {
        'parameter1', [-2 2], 0.05
        'parameter2', [-2 2], 0.05 };
    optimInfo.title         = 'Optimization of Rosenbrock''s saddle';
    emailParams             = [];
    DEParams.feedSlaveProc  = 1;
    DEParams.infoIterations = 1;
    DEParams.infoPeriod     = 10;  % in seconds
    DEParams.maxiter        = 100;
    DEParams.maxtime        = 60;  % in seconds
    
    % set random state to always use the same population members
    setrandomstate(1);
    
elseif (nargin == 1)
    
    error(textwrap2(sprintf([...
        'If only a single input argument is given, it must be a parameter struct or the file ', ...
        'name of a result file saved before.'])));
    
elseif ((nargin >= 3) && (nargin <= 8)) || TESTCASE==1
    
    % standard input parameters given
    DEParams          = varargin{1};
    paramDefCellInput = varargin{2};
    objFctHandle      = varargin{3};
    
    if nargin >= 4
        objFctSettings = varargin{4};
    else
        objFctSettings = {};
    end
    
    if nargin >= 5
        objFctParams = varargin{5};
    else
        objFctParams = [];
    end
    
    if nargin >= 6
        emailParams = varargin{6};
    else
        emailParams = [];
    end
    
    if nargin >= 7
        optimInfo = varargin{7};
    end
    
    if ~exist('optimInfo', 'var') || isempty(optimInfo) || ~isstruct(optimInfo)
        optimInfo       = [];
        optimInfo.title = 'DE optimization';
    end
    
    if nargin >= 8
        resultFileName = varargin{8};
    end
    
else
    
    error(textwrap2(sprintf([...
        'Input argument number/combination not supported. Please type ''help %s'' for more ', ...
        'information.'], mfilename)));
    
end

if ~isempty(resultFileName)
    
    % Result file name given for continuation of optimization.
    if exist(resultFileName, 'file')
        
        % load result file
        sem = setfilesemaphore(resultFileName, 'set always');
        load(resultFileName, 'optimResult');
        removefilesemaphore(sem);
        
        % check data saved in file
        if isempty(optimResult) || ~isfield(optimResult, 'fileFormatVersion')
            error(textwrap2(sprintf(...
                'Given file %s seems not to be generated by differentialevolution.m', resultFileName)));
        elseif abs(optimResult.fileFormatVersion - 1.0) > 1e-8
            error(textwrap2(sprintf('Given file %s has wrong file format version.', resultFileName)));
        end
    else
        error(textwrap2(sprintf('Given result file %s is not existing!', resultFileName)));
    end
    
    % optimization state has been loaded from file above
    changedParametersFound = false;
    
    if ~isempty(DEParams)
        checkDEParamsNewVsLoaded(DEParams, optimResult.DEParams);
    else
        DEParams = optimResult.DEParams;
    end
    
    if ~isempty(paramDefCellInput)
        changedParametersFound = changedParametersFound || ...
            ~isequalwithequalnans(paramDefCellInput, optimResult.paramDefCellInput);
        checkParamDefCellNewVsLoaded(paramDefCellInput, optimResult.paramDefCellInput);
    else
        paramDefCellInput = optimResult.paramDefCellInput;
    end
    
    if ~isempty(objFctHandle)
        changedParametersFound = changedParametersFound || ...
            ~isequalwithequalnans(objFctHandle, optimResult.objFctHandle);
    else
        objFctHandle = optimResult.objFctHandle;
    end
    
    if ~isempty(objFctSettings)
        changedParametersFound = changedParametersFound || ...
            ~isequalwithequalnans(objFctSettings, optimResult.objFctSettings);
    else
        objFctSettings = optimResult.objFctSettings;
    end
    
    if ~isempty(objFctParams)
        changedParametersFound = changedParametersFound || ...
            ~isequalwithequalnans(objFctParams, optimResult.objFctParams);
    else
        objFctParams = optimResult.objFctParams;
    end
    
    if isempty(optimInfo)
        optimInfo = optimResult.info;
    end
    
    if isempty(emailParams)
        emailParams = optimResult.emailParams;
    end
    
    
    if changedParametersFound
        disp(textwrap2(sprintf([...
            'Changed optimization parameters found. Please be careful with changing parameters ', ...
            'when continuing an optimization because changes may lead to errors or wrong results!'])));
    end
end


% get default DE parameters
DEParamsDefault = Ogive_getdefaultparams;

if isempty(DEParams)
    
    DEParams = DEParamsDefault;
    
else
    
    % backwards compatibility
    if isfield(DEParams, 'refreshiter')
        disp('Warning: Parameter refreshiter was renamed to infoIterations.');
        DEParams.infoPeriod = DEParams.refreshiter;
        DEParams = rmfield(DEParams, 'refreshiter');
    end
    
    if isfield(DEParams, 'refreshtime')
        disp('Warning: Parameter refreshtime was renamed to infoPeriod.');
        DEParams.infoPeriod = DEParams.refreshtime;
        DEParams = rmfield(DEParams, 'refreshtime');
    end
    
    if isfield(DEParams, 'refreshtime3')
        disp('Warning: Parameter refreshtime3 was renamed to sendMailPeriod.');
        DEParams.sendMailPeriod = DEParams.refreshtime3;
        DEParams = rmfield(DEParams, 'refreshtime3');
    end
    
    % complete missing fields of input DE parameter structure
    fieldNames = fieldnames(DEParamsDefault);
    for k = 1:length(fieldNames)
        if ~isfield(DEParams, fieldNames{k})
            DEParams.(fieldNames{k}) = DEParamsDefault.(fieldNames{k});
            disp(textwrap2(sprintf(...
                'Warning: Field ''%s'' not included in DEParams. Using default value.', fieldNames{k})));
        end
    end
    
    % check for unsupported fields in struct DEParams
    fieldNames = fieldnames(DEParams);
    errorFound = false;
    for k = 1:length(fieldNames)
        if ~isfield(DEParamsDefault, fieldNames{k})
            disp(textwrap2(sprintf(...
                'Field ''%s'' of struct DEParams not supported by %s.', fieldNames{k}, mfilename)));
            DEParams = rmfield(DEParams, fieldNames{k});
            errorFound = true;
        end
    end
    if errorFound
        error('Unsupported fields found in struct DEParams.');
    end
end

% check input parameters
checkinputs(paramDefCellInput, objFctParams);

% modify paramDefCell if there are vector-valued parameters
paramDefCell = paramDefCellInput;
k = 1;
parameterDimVector = [];
while k <= size(paramDefCell, 1)
    
    parameterDim = size(paramDefCell{k, 2}, 1);
    if parameterDim == 1
        
        % scalar parameter, save dimension
        parameterDimVector(k, 1) = 1; %#ok
        k = k + 1;
        
        if isempty(paramDefCell{1,1})
            % scalar parameter with empty name
            paramDefCell{1, 1} = '_1';
        end
        
    else
        
        % vector parameter, introduce new rows in paramDefCell
        parameterDimVector(k : k + parameterDim - 1, 1) = parameterDim; %#ok
        parameterName =  paramDefCell{k,1};
        paramDefCell  = [paramDefCell(1:k,:); cell(parameterDim-1, size(paramDefCell,2)); ...
            paramDefCell(k+1:end,:)];
        
        for d = parameterDim:-1:1
            paramDefCell{k+d-1, 1} = sprintf('%s_%d', parameterName, d);
            for col = 2:size(paramDefCell,2)
                paramDefCell{k+d-1,col} = paramDefCell{k, col}(d,:);
                if (col == 4) && isnan(paramDefCell{k+d-1,col}) % initial value = NaN
                    paramDefCell{k + d - 1, col} = [];
                end
            end
        end
        k = k + parameterDimVector(k,1);
        
    end
end

% initialize functions
getparametername (paramDefCell, parameterDimVector);
displaybestmember(paramDefCell);

% get parameter bounds
parameterBounds = cell2mat(paramDefCell(:,2));
parGridVector   = cell2mat(paramDefCell(:,3));
D               = size(parameterBounds, 1);
XVmin           = parameterBounds(:, 1)';
XVmax           = parameterBounds(:, 2)';

% check parameter bounds and quantization
minQuantizationUser = 1e-12;
checkBoundsAndQuantization(XVmin, XVmax, parGridVector, minQuantizationUser);

% compute number of possible parameter vectors
if all(parGridVector > 0)
    nrOfPossibleMembers = ...
        prod(floor((diff(parameterBounds, 1, 2) + 0.5 * parGridVector) ./ parGridVector) + 1);
else
    nrOfPossibleMembers = inf;
end

% get population size NP
if ~isempty(optimResult) && ~isempty(optimResult.currentPopulation)
    NP = size(optimResult.currentPopulation, 2);
else
    NP = min(DEParams.NP, nrOfPossibleMembers);
end

% get parameters
% TODO: pass struct DEParams to subfunctions instead of unwrapping everything.
VTR                 = DEParams.VTR;
useInitParams       = DEParams.useInitParams;
infoPeriod          = DEParams.infoPeriod;
sendMailPeriod      = DEParams.sendMailPeriod;
maxtime             = DEParams.maxtime;
maxclock            = DEParams.maxclock;
saveHistory         = DEParams.saveHistory;
displayResults      = DEParams.displayResults;
feedSlaveProc       = DEParams.feedSlaveProc;
slaveFileDir        = DEParams.slaveFileDir;
maxMasterEvals      = DEParams.maxMasterEvals;
playSound           = DEParams.playSound;
validChkHandle      = DEParams.validChkHandle;

%ADDED BY J.SIEVERS, 2015:
infoOutput          = DEParams.infoOutput;
saveHistoryFilename = DEParams.saveHistoryFilename;
maxiterStablebest1 = DEParams.maxiterStablebest1;
maxiterStablebest2 = DEParams.maxiterStablebest2;
taskIdentifier = DEParams.taskIdentifier;
taskIdentifier2 = DEParams.taskIdentifier2;
RelativeBounds = DEParams.RelativeBounds;
errordir = DEParams.errordir;
% semaphorefiles = DEParams.semaphorefiles;


if maxiterStablebest1~=0 && maxiterStablebest2~=0
    annealing_schedule=1./(linspace(1,3,DEParams.maxiter));
    annealing_schedule=round(interp1([max(annealing_schedule) min(annealing_schedule)],[maxiterStablebest1 maxiterStablebest2],annealing_schedule));
else
    annealing_schedule=ones(1,DEParams.maxiter)*(DEParams.maxiter);
end
%ALSO:
% 1)      (iterationNr <= DEParams.maxiter)  i.e.: less than, OR EQUAL TO!!


% check parameters
if (DEParams.maxiter <= 0)
    error('Parameter maxiter must be greater than zero.');
end
if displayResults && ~DEParams.saveHistory
    fprintf('Warning: Optimization history can not be displayed if not saved.\n');
    displayResults = 0;
end
infoIterations = floor(DEParams.infoIterations);

% get initial parameter vector
if useInitParams && (isempty(optimResult) || isempty(optimResult.currentPopulation))
    initialMem = zeros(1,D);
    if size(paramDefCell, 2) == 4
        % use initial parameters from fourth column of paramDefCell
        parNr = 1;
        while parNr <= D
            if ~isempty(paramDefCell{parNr, 4})
                % check if objFctParams also contains initial value
                parameterName = getparametername(parNr, 2);
                index = parNr:(parNr + parameterDimVector(parNr) - 1);
                initialMem(index) = cell2mat(paramDefCell(index,4))';
                
                % warn if overwriting initial values in objFctParams
                if isstruct(objFctParams) && isfield(objFctParams, parameterName) && ...
                        ~isempty(objFctParams.(parameterName)) && ~all(isnan(objFctParams.(parameterName)))
                    if ~isequal(objFctParams.(parameterName), initialMem(index))
                        disp(textwrap2(sprintf(...
                            ['Warning: Initial value of parameter ''%s'' in struct objFctParams was ', ...
                            'overwritten by settings in paramDefCell.'], parameterName)));
                    end
                elseif isnumeric(objFctParams) && ~isempty(objFctParams) && ~all(isnan(objFctParams))
                    if isscalar(objFctParams)
                        disp(textwrap2(sprintf(...
                            ['Warning: Initial parameter value objFctParams was overwritten by settings in', ...
                            'paramDefCell.'], parameterName)));
                    else
                        disp(textwrap2(sprintf(...
                            ['Warning: Initial parameter vector objFctParams was overwritten by settings in', ...
                            'paramDefCell.'], parameterName)));
                    end
                end
            end
            
            for d = 1:parameterDimVector(parNr)
                index = parNr + d - 1;
                if isnan(initialMem(index))
                    parameterName = getparametername(index, 1);
                    disp(textwrap2(sprintf(...
                        ['Warning: No initial value for parameter %s given. Using center of range interval', ...
                        'as initial value.'], parameterName)));
                    initialMem(index) = 0.5 * (XVmin(index) + XVmax(index));
                end
            end
            parNr = parNr + parameterDimVector(parNr);
        end
        checkInitialMem = true;
        
    elseif isempty(objFctParams)
        
        % no initial parameter set given
        disp('Warning: Option DEParams.useInitParams is true but no initial parameter set is given.');
        useInitParams = 0;
        checkInitialMem = false;
        
    else
        
        % check if initial values are given by objFctParams and collect them
        if isstruct(objFctParams)
            parNr = 1;
            while parNr <= D
                parameterDim  = parameterDimVector(parNr);
                index = parNr:parNr+parameterDim-1;
                parameterName = getparametername(parNr, 2);
                if isfield(objFctParams, parameterName)
                    initialMem(index) = objFctParams.(parameterName)';
                else
                    disp(textwrap2(sprintf(...
                        ['Warning: No initial value for parameter %s given. Using center of range interval', ...
                        'as initial value.'], parameterName)));
                    initialMem(index) = 0.5 * (XVmin(index) + XVmax(index));
                end
                parNr = parNr + parameterDim;
            end
        elseif strcmp(paramDefCell{1,1}, '_1')
            initialMem = objFctParams;
            for parNr = 1:D
                parameterName = getparametername(parNr, 1);
                if isnan(initialMem(parNr))
                    disp(textwrap2(sprintf(...
                        ['Warning: No initial value for parameter %s given. Using center of range interval', ...
                        'as initial value.'], parameterName)));
                    initialMem(parNr) = 0.5 * (XVmin(parNr) + XVmax(parNr));
                end
            end
        end
        checkInitialMem = true;
        
    end
    
    % check if initial member is on quantization grid
    if checkInitialMem
        [ignore, quantInitialMem] = evaluateParameterContraints(...
            objFctParams, paramDefCell, parameterDimVector, initialMem); %#ok
        for parNr = 1:D
            if (~isnan(initialMem(parNr))) && (paramDefCell{parNr,3} > 0) && ...
                    (abs(initialMem(parNr) - quantInitialMem(parNr)) > eps)
                disp(textwrap2(sprintf(...
                    ['Warning: Initial value of parameter %s (%g) not on quantization grid (next ', ...
                    'grid value: %g).'], getparametername(parNr, 1), initialMem(parNr), ...
                    quantInitialMem(parNr))));
            end
        end
    end
end

% check if validChkHandle is valid
if isempty(validChkHandle)
    validChkHandle = @alwaysvalid; % handle to function that always returns true
elseif ~isa(validChkHandle, 'function_handle')
    if ischar(validChkHandle)
        validChkHandle = str2func(validChkHandle);
    else
        error('validChkHandle is neither empty nor a string nor a function handle.');
    end
end

% get default width for wrapping displayed information
textWidth = textwrap2;

% display title
if isempty(optimResult)
    verb = 'Starting';
else
    verb = 'Continuing';
end
if infoOutput==1
    disp(repmat('*', 1, textWidth));
    dateString = datestr(clock, 'mmm dd, HH:MM');
    if isstruct(optimInfo) && isfield(optimInfo, 'title')
        disp(textwrap2(sprintf('%s ''%s'' at %s.', verb, optimInfo.title, dateString)));
        if isfield(optimInfo, 'subtitle')
            disp(textwrap2(optimInfo.subtitle));
        end
    else
        fprintf('%s optimization at %s.\n', verb, dateString);
    end
    
    
    % display number of possible parameter vectors
    if isfinite(nrOfPossibleMembers)
        fprintf('Number of possible parameter vectors: %g\n', nrOfPossibleMembers);
    else
        fprintf('Infinite number of possible parameter vectors.\n');
    end
end

% Quit if maxtime is less or equal zero (can be used to check if all initial parameter values
% are on the quantization grid).
if (DEParams.maxtime <= 0) || (~isempty(maxclock) && etime(clock, maxclock) > 0)
    disp(repmat('*', 1, textWidth));
    disp(textwrap2(sprintf(...
        'Function %s was left because parameter maxtime is less or equal zero.\n', mfilename)));
    if nargout > 0
        varargout = {[], [], [], 0, ''};
    end
    return
end

% get slave file directory
if feedSlaveProc
    % build name of slave file directory
    if isempty(slaveFileDir)
        slaveFileDir = concatpath(tempdir2, 'differentialevolution');
    end
    % create slave file directory if not existing
    if ~exist(slaveFileDir, 'dir')
        mkdir(slaveFileDir);
    end
else
    slaveFileDir = '';
end

% save 'time over'-file
if ~isempty(objFctHandle)
    objFctName = strrep(func2str(objFctHandle), '/', '_');
else
    objFctName = 'test';
end
rnd=round(rand(1)*1e3);
timeOverFileName = sprintf('%s_timeover_%s_%s_%s.mat', objFctName, gethostname,num2str(rnd),datestr(now,'yyyymmddHHMMSSFFF'));
% timeOverFileName=[semaphorefiles,timeOverFileName];
if exist('./data', 'dir')
    timeOverFileName = ['data/' timeOverFileName];
end
info = 'Delete this file to stop parameter optimization.'; %#ok
sem = setfilesemaphore(timeOverFileName, 'set always');
save(timeOverFileName, 'info');
removefilesemaphore(sem);

% get minMaxSign depending on parameter DEParams.minimizeValue
if DEParams.minimizeValue
    minMaxSign =  1; % minimization is default behavior
else
    minMaxSign = -1;
end

% initialize variables
valstddev         = inf;              % cost vector standard deviation
paramstddev       = inf;              % mean parameter standard deviation
nofevalCounter    = 0;                % number of iterations without any function evaluation
noChangeCounter   = 0;                % number of iterations without any population change
nfeval.overall    = 0;                % number of function evaluations
nfeval.last       = 0;                % number of function evaluations before current iteration
nfeval.saved      = 0;                % number of evaluations that were saved
nfeval.slave      = 0;                % number of evaluations performed by slave process

if isempty(optimResult)
    
    % initialize more variables
    pop             = zeros(NP, D);     % population array
    val             = nan(1, NP);       % cost vector
    bestval         = minMaxSign * inf; % best cost value so far
    bestvalhist     = [];               % history of best values
    bestvalhist_std = [];               % std of history of best values
    bestmem         = [];               % best member so far
    bestmemhist     = [];               % history of best member
    valstddevhist   = [];               % history of cost vector standard deviation
    paramstddevhist = [];               % history of mean parameter standard deviation
    allval          = [];               % vector with all computed cost values
    allmem          = [];               % matrix with all tested vectors as columns
    % note: parameter vectors are saved in pop as rows, in
    % allmem as columns!
else
    
    % restore variables from previous optimization run
    pop             = optimResult.currentPopulation';
    val             = optimResult.currentCostValues;
    bestval         = optimResult.bestEvaluationValue;
    bestvalhist     = optimResult.bestValueHistory;
    bestmem         = optimResult.bestMember';
    bestmemhist     = optimResult.bestMemberHistory;
    valstddevhist   = optimResult.costValueStdDevHistory;
    paramstddevhist = optimResult.parameterStdDevHistory;
    allval          = optimResult.allEvaluationValues;
    allmem          = optimResult.allTestedMembers;
    initval         = nan;
    initmem         = nan;
    
end

% clear persistent variables in subfunctions
clear getparametername timeovercheck displayprogressinfo
clear displaybestmember
saveoptimizationstate();
computeevaluationvalue();

% initialize function sendmailblat
clear sendmailblat
sendEmail = sendmailblat([], [], emailParams);

% save current time
startTime        = mbtime;
nextInfoTime     = startTime + infoPeriod;
lastInfoIterTime = -inf;

% save current (empty) state or state loaded from file
if isempty(optimResult)
    state = 'Empty state before first iteration.';
else
    state = sprintf('State loaded from file %s.', resultFileName);
end
if saveHistory
    saveoptimizationstate(...
        paramDefCellInput, paramDefCell, parameterDimVector, optimInfo, [], [], [], [], 0, 0, [], ...
        [], startTime, state, DEParams, [], [], objFctName, objFctHandle, objFctSettings, ...
        objFctParams, emailParams, infoOutput, 1,saveHistoryFilename);
end

%%%%%%%%%%%%%%%%%%%%%%%%%%%
% start main program loop %
%%%%%%%%%%%%%%%%%%%%%%%%%%%

    
if infoOutput==1
    disp(repmat('*', 1, textWidth));
end
iterationNr         = 0;
displayMeanEvalTime = true;
timeOver            = false;
startLoopTime       = mbtime;
sumbestvalhist=false;
bestvalhist_stdint=1;
popmed=[];
popstd=[];
popbestval=[];
popreinit=[];
        
while (iterationNr < DEParams.maxiter) && sumbestvalhist==0
%     (isempty(VTR) || isnan(VTR) || (bestval * minMaxSign > VTR * minMaxSign)) && sumbestvalhist==0
%         ~timeOver && ...
%         (iterationNr < DEParams.maxiter) && ...
%         (isempty(VTR) || isnan(VTR) || (bestval * minMaxSign > VTR * minMaxSign)) && sumbestvalhist==0
        
    
    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    % Initialize or re-initialize population %
    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    initialization   = (iterationNr == 0) && (isempty(optimResult) || isempty(pop));
    reinitialization = ...
        (valstddev       <  DEParams.minvalstddev)   || ...
        (paramstddev     <  DEParams.minparamstddev) || ...
        (noChangeCounter >= DEParams.nochangeiter)   || ...
        (nofevalCounter  >  DEParams.nofevaliter);
    
    if initialization
        
        % initialization
        if useInitParams > 0
            % first population member: current parameters
            pop(1,:) = initialMem;
            istart = 2;
        else
            % initialize all population members randomly
            istart = 1;
        end
        
        if (nrOfPossibleMembers <= NP) && (D == 1) && (paramDefCell{1,3} ~= 0)
            % if only one scalar parameter to optimize, set all possible members
            % directly (no random initialization)
            
            if useInitParams > 0
                % get and quantize first member
                [ignore, firstMem] = evaluateParameterContraints(...
                    objFctParams, paramDefCell, parameterDimVector, pop(1,:)); %#ok
            end
            
            % generate equidistant vector
            pop = (XVmin(1) : paramDefCell{1,3} : (XVmax(1) + 0.5 * paramDefCell{1,3}))';
            
            if useInitParams > 0
                % evaluate initial member first, after that those
                % that are next to initial member
                [ignore, sortIndex] = sort(abs(pop(:,1) - firstMem)); %#ok
                pop = pop(sortIndex,:);
                
                % do not use random initialization later
                istart = NP + 1;
            end
            pop = pop(1:NP, :);
            
        elseif useInitParams == 2
            
            % next population members: current parameter vector plus random noise
            NPAdd = min(round(0.4 * NP), NP - istart + 1);
            if NPAdd > 0
                memIndex = istart: (istart + NPAdd - 1);
                istart   = istart + NPAdd + 1;
                pop      = computerandominitialization(...
                    1, pop, memIndex, paramDefCell, objFctSettings, parameterDimVector, XVmax, XVmin, ...
                    validChkHandle);
            end
        end
        initialization = true;
        
    elseif reinitialization
        
        popreinit=[popreinit iterationNr];
        
        % re-initialization
        if infoOutput==1
            fprintf('Re-initializing population in iteration %d.\n', iterationNr);
            if valstddev < DEParams.minvalstddev
                fprintf('Evaluation value standard deviation below threshold (%g < %g).\n', ...
                    valstddev, DEParams.minvalstddev);
            elseif paramstddev < DEParams.minparamstddev
                fprintf('Mean parameter standard deviation below threshold (%g < %g).\n', ...
                    paramstddev, DEParams.minparamstddev);
            elseif noChangeCounter >= DEParams.nochangeiter
                fprintf('Population did not change during last %d iterations.\n', ...
                    DEParams.nochangeiter);
            elseif nofevalCounter > DEParams.nofevaliter
                fprintf('No function evaluations during the last %d iterations.\n', ...
                    DEParams.nofevaliter);
            end
            disp(' ');
        end
        
        if minMaxSign > 0
            [val, index] = sort(val);
        else
            [val, index] = sort(-val); % not using 'descend' for backwards compatibility
            val = -val;
        end
        
        istart = max(1, round(0.2 * NP)); % keep best twenty percent of the population members
        index = index(1:istart-1);
        pop(1:istart-1,:) = pop(index,:);
%         val(1:istart-1)   = val(index);
        
    end
    
    if initialization || reinitialization
        
        % initialize population members from istart to NP randomly
        pop = computerandominitialization(...
            2, pop, istart:NP, paramDefCell, objFctSettings, parameterDimVector, XVmax, XVmin, ...
            validChkHandle);
        
        % feed slave process
        if feedSlaveProc
            generatefilesforslaveprocess(...
                objFctHandle, objFctParams, objFctSettings, paramDefCell, parameterDimVector, pop, ...
                allmem, iterationNr, saveHistory, slaveFileDir, validChkHandle);
        end
        
%         % evaluate initial population members
%         testval = objFctHandle(objFctSettings{:}, pop);
%         ix_best=find(testval*minMaxSign==min(testval*minMaxSign),1,'first');
%         bestval = testval(ix_best);
%         bestmem = pop(ix_best,:);


        % evaluate initial population members
        
        
        %OLD VERSION
%         for memberNr = 1:NP
%             
%             % evaluate member
%             [val(memberNr), pop(memberNr,:), nfeval, allval, allmem] = computeevaluationvalue(...
%                 pop(memberNr,:), nfeval, timeOver, objFctParams, paramDefCell, parameterDimVector, ...
%                 objFctSettings, objFctHandle, saveHistory, allval, allmem, iterationNr, memberNr, ...
%                 NP, slaveFileDir, maxMasterEvals, validChkHandle, XVmin, XVmax);
%             
%             if initialization && (memberNr == 1)
%                 
%                 % set initial value
%                 bestval = val(1);
%                 if isnan(bestval)
%                     % set to highest possible value
%                     bestval = minMaxSign * Inf;
%                 elseif isinf(bestval)
%                     if (bestval > 0) && (minMaxSign < 0)
%                         error(textwrap2(sprintf([...
%                             'Objective function value of initial parameter vector may not be +Inf in ', ...
%                             'maximization problem.'])));
%                     elseif (bestval < 0) && (minMaxSign > 0)
%                         error(textwrap2(sprintf([...
%                             'Objective function value of initial parameter vector may not be -Inf in ', ...
%                             'minimization problem.'])));
%                     end
%                 end
%                 initval = bestval;
%                 
%                 % best member so far
%                 bestmem = pop(1,:);
%                 initmem = bestmem;
%                 
%                 % display initial member
%                 state = 'Initial parameter set.';
%                 if infoOutput==1
%                     displaybestmember(paramDefCell, parameterDimVector, initval, initmem, ...
%                         allval, initval, initmem, 1, state, optimInfo, sendEmail, playSound);
%                 end
%                 
%                 % display time needed for first function evaluation
%                 if mbtime - startLoopTime > 1
%                     fprintf('First function evaluation time: %s\n', formattime(mbtime - startLoopTime));
%                 end
%                 
%                 % save initial state
%                 if saveHistory
%                     saveoptimizationstate(...
%                         paramDefCellInput, paramDefCell, parameterDimVector, optimInfo, bestval, bestmem, ...
%                         bestval, bestmem, 0, 0, pop, val, startTime, state, DEParams, allval, allmem, ...
%                         objFctName, objFctHandle, objFctSettings, objFctParams, emailParams, infoOutput, 0,saveHistoryFilename);
%                 end
%                 
%             else
%                 
%                 % check if current member is overall best
%                 if isfinite(val(memberNr)) && ...
%                         (val(memberNr) * minMaxSign < bestval * minMaxSign)
%                     bestval = val(memberNr);
%                     bestmem = pop(memberNr,:);
%                 end
%                 
%                 % set current state
%                 if initialization && infoOutput==1
%                     state = sprintf('In initialization, %d of %d members checked.', ...
%                         memberNr, NP);
%                 else
%                     state = sprintf('In iteration %d, %d of %d members re-initialized.', ...
%                         iterationNr, memberNr, NP);
%                 end
%             end
%             
%             % display best member
%             if infoOutput==1
%                 displaybestmember(paramDefCell, parameterDimVector, bestval, bestmem, allval, ...
%                     initval, initmem, 0, state, optimInfo, sendEmail, playSound);
%             end
%             
%             % display current state and progress information
%             if mbtime - nextInfoTime >= 0
%                 nextInfoTime = nextInfoTime + infoPeriod * ...
%                     (1 + floor((mbtime - nextInfoTime) / infoPeriod));
%                 if infoOutput==1
%                     disp(state);
%                     displayprogressinfo(...
%                         startLoopTime, state, sendMailPeriod, maxtime, maxclock, timeOver, nfeval, ...
%                         nrOfPossibleMembers, pop, bestval, allval, optimInfo, sendEmail);
%                 end
%             end
%             
%             if infoOutput==1
%                 % display mean function evaluation time
%                 if displayMeanEvalTime && (nfeval.overall == 5) && (mbtime - startLoopTime > 1)
%                     fprintf('Mean function evaluation time after %d runs: %s\n', nfeval.overall, ...
%                         formattime((mbtime - startLoopTime) / nfeval.overall));
%                     displayMeanEvalTime = false;
%                 end
%             end
%             
%             if saveHistory
%                 saveoptimizationstate(...
%                     paramDefCellInput, paramDefCell, parameterDimVector, optimInfo, bestval, bestmem, ...
%                     bestval, bestmem, 0, 0, pop, val, startTime, state, DEParams, allval, allmem, ...
%                     objFctName, objFctHandle, objFctSettings, objFctParams, emailParams, infoOutput, 0,saveHistoryFilename);
%             end
%             
%             % check time
%             timeOver = timeovercheck(startTime, maxtime, maxclock, timeOverFileName, timeOver);
%             
%         end % for memberNr = 1:NP
        
        
        % NEW FASTER VECTORIZED VERSION
        for ijk=1:size(pop,2)
            pop(:,ijk)=min(max(paramDefCell{ijk,2}(1),pop(:,ijk)),paramDefCell{ijk,2}(2));
        end
        
%         try
%             Ncas=50;
%             sumixnok=nan(Ncas,1);
%             for ikl=1:Ncas
%                 mytimedwaitbar(ikl,Ncas)
%                 for ijk=1:size(pop,2)
%                     pop(:,ijk)=min(max(paramDefCell{ijk,2}(1),pop(:,ijk)),paramDefCell{ijk,2}(2));
%                 end

                if ~isempty(RelativeBounds)
                    if any(RelativeBounds(:)~=0)
                        fix=find(RelativeBounds(1,:)~=0);
                        for ijk=fix
                            if RelativeBounds(1,ijk)<0 && RelativeBounds(2,ijk)==0 % parameter must have opposite sign relative to other parameter
                                sgpop_ref=sign(pop(:,abs(RelativeBounds(1,ijk))));
                                sgpop_param=sign(pop(:,ijk));
                                ixc=sgpop_param==sgpop_ref;
                                pop(ixc,ijk)=pop(ixc,ijk)*(-1);
                            else % parameter must be larger or smaller by a fixed interval, relative to other parameter
                                if RelativeBounds(1,ijk)>0 %Parameter must be _larger_ than
                                    dif=pop(:,abs(RelativeBounds(1,ijk)))-pop(:,ijk);
                                    ixnok=dif>RelativeBounds(2,ijk);
    %                                 sumixnok(ikl)=sum(ixnok);
                                    if any(ixnok)
                                        pop(ixnok,ijk)=pop(ixnok,ijk)+(RelativeBounds(2,ijk)-dif(ixnok));
                                    end
                                else %Parameter must be _smaller_ than
                                    dif=pop(:,abs(RelativeBounds(1,ijk)))-pop(:,ijk);
                                    ixnok=dif<RelativeBounds(2,ijk);
    %                                 sumixnok(ikl)=sum(ixnok);
                                    if any(ixnok)
                                        pop(ixnok,ijk)=pop(ixnok,ijk)-(RelativeBounds(2,ijk)-dif(ixnok));
                                    end
                                end
                            end
                        end
                    end
                end

                % check cost of initial population
                [val,~] = objFctHandle(objFctSettings{:}, pop);   

%             end
%         
%         catch me
%            disp('stop') 
%         end
        
        
        
        
        
        
        
        [~,mnix]=min(val*minMaxSign);
        bestval=val(mnix(1));
        bestmem=pop(mnix(1),:);
        allmem=pop';
        allval=val;
        nfeval.overall=length(allval);
        
        
%         timeOver = timeovercheck(startTime, maxtime, maxclock, timeOverFileName, timeOver);
        
        iterationNr = iterationNr + 1;
        
    end % if initialization || reinitialization
    
    
%     if timeOver
%         break
%     end
    
    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    % compute competing population %
    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    % In function computenewpopulation, you can place your own favorite algorithm!
    
    popold = pop;
    popnew = computenewpopulation(pop, bestmem, DEParams);
    
    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    % check which vectors will survive %
    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    
    % feed slave process
    if feedSlaveProc
        generatefilesforslaveprocess(...
            objFctHandle, objFctParams, objFctSettings, paramDefCell, parameterDimVector, popnew, ...
            allmem, iterationNr, saveHistory, slaveFileDir, validChkHandle);
    end
    
    % OLD SERIAL EVALUATION
%     tic
%     for memberNr = 1:NP
%         disp(['iteration: ',num2str(memberNr)])
%         
%         % check cost of competitor
%         [tempval, popnew(memberNr,:), nfeval, allval, allmem] = computeevaluationvalue(...
%             popnew(memberNr,:), nfeval, timeOver, objFctParams, paramDefCell, parameterDimVector, ...
%             objFctSettings, objFctHandle, saveHistory, allval, allmem, iterationNr, memberNr, NP, ...
%             slaveFileDir, maxMasterEvals, validChkHandle);
%         
%         if isfinite(tempval)
%             % if competitor is better than value in cost array or old vector was not evaluated
%             % (tempval = NaN), replace old vector with new one (for new iteration) and save value in
%             % cost array
%             if (tempval * minMaxSign < val(memberNr) * minMaxSign) || ~isfinite(val(memberNr))
%                 pop(memberNr,:) = popnew(memberNr,:);
%                 val(memberNr)   = tempval;
%                 
%                 % if competitor is better than the best one ever, set new best value and new best
%                 % parameter vector ever
%                 if (tempval * minMaxSign < bestval * minMaxSign)
%                     bestval = tempval;
%                     bestmem = popnew(memberNr,:);
%                 end
%             end
%         elseif isinf(tempval)
%             if (tempval > 0) && (minMaxSign < 0)
%                 warning(['Objective function value of initial parameter vector may', ...
%                     'not be +Inf in maximization problem.']); %#ok
%             elseif (tempval < 0) && (minMaxSign > 0)
%                 warning(['Objective function value of initial parameter vector may ', ...
%                     'not be -Inf in minimization problem.']); %#ok
%             end
%         end
%         
%         
%         if infoOutput==1
%             
%             % display best member
%             state = sprintf('In iteration %d, %d of %d competitors checked.', iterationNr, memberNr, NP);
%             displaybestmember(paramDefCell, parameterDimVector, bestval, bestmem, ...
%                 allval, initval, initmem, 0, state, optimInfo, sendEmail, playSound);
%             
%             % display current state and progress information
%             if mbtime - nextInfoTime >= 0
%                 nextInfoTime = nextInfoTime + infoPeriod * (1 + floor((mbtime - nextInfoTime) / infoPeriod));
%                 disp(state);
%                 displayprogressinfo(...
%                     startLoopTime, state, sendMailPeriod, maxtime, maxclock, timeOver, nfeval, ...
%                     nrOfPossibleMembers, pop, bestval, allval, optimInfo, sendEmail);
%             end
%         end
%         
%         if saveHistory
%             saveoptimizationstate(...
%                 paramDefCellInput, paramDefCell, parameterDimVector, optimInfo, bestval, bestmem, ...
%                 bestvalhist, bestmemhist, valstddevhist, paramstddevhist, pop, val, startTime, state, ...
%                 DEParams, allval, allmem, objFctName, objFctHandle, objFctSettings, objFctParams, ...
%                 emailParams, infoOutput, 0,saveHistoryFilename);
%         end
%         
%         % check time
%         timeOver = timeovercheck(startTime, maxtime, maxclock, timeOverFileName, timeOver);
%     end % for memberNr = 1:NP
%     toc
    
    
    %NEW FASTER VECTORIZED EVALUATION
%     tic

    %impose parameter boundaries on competing population
    for ijk=1:size(popnew,2)
        popnew(:,ijk)=min(max(paramDefCell{ijk,2}(1),popnew(:,ijk)),paramDefCell{ijk,2}(2));
    end
    if ~isempty(RelativeBounds)
        if any(RelativeBounds(:)~=0)
            fix=find(RelativeBounds(1,:)~=0);
            for ijk=fix
                if RelativeBounds(1,ijk)<0 && RelativeBounds(2,ijk)==0 % parameter must have opposite sign relative to other parameter
                    sgpop_ref=sign(popnew(:,abs(RelativeBounds(1,ijk))));
                    sgpop_param=sign(popnew(:,ijk));
                    ixc=sgpop_param==sgpop_ref;
                    popnew(ixc,ijk)=popnew(ixc,ijk)*(-1);
                else % parameter must be larger or smaller by a fixed interval, relative to other parameter
                    if RelativeBounds(1,ijk)>0 %Parameter must be _larger_ than
                        dif=popnew(:,abs(RelativeBounds(1,ijk)))-popnew(:,ijk);
                        ixnok=dif>RelativeBounds(2,ijk);
                        if any(ixnok)
                            popnew(ixnok,ijk)=popnew(ixnok,ijk)+(RelativeBounds(2,ijk)-dif(ixnok));
                        end
                    else %Parameter must be _smaller_ than
                        dif=popnew(:,abs(RelativeBounds(1,ijk)))-popnew(:,ijk);
                        ixnok=dif<RelativeBounds(2,ijk);
                        if any(ixnok)
                            popnew(ixnok,ijk)=popnew(ixnok,ijk)-(RelativeBounds(2,ijk)-dif(ixnok));
                        end
                    end
                end
                
            end
        end
    end

    % check cost of all competitors
    testval = objFctHandle(objFctSettings{:}, popnew);
    
    % update population with competitors which are better
    ix_improved=testval*minMaxSign<val*minMaxSign;
    if sum(ix_improved)>0
        pop(ix_improved,:)=popnew(ix_improved,:);
        val(ix_improved)=testval(ix_improved);
        [~,mnix]=min(val*minMaxSign);
        bestval=val(mnix(end));
        bestmem=pop(mnix(end),:);
    end
    if size(pop,2)==4
        popmed=[popmed median(pop(:,1)-pop(:,4))];
        popstd=[popstd std(pop(:,1)-pop(:,4))];
        popbestval=[popbestval bestval];
    elseif size(pop,2)==7
        popmed=[popmed median(pop(:,1)-pop(:,4)+pop(:,5))];
        popstd=[popstd std(pop(:,1)-pop(:,4)+pop(:,5))];
        popbestval=[popbestval bestval];
    end
    allmem=[allmem popnew'];
    allval=[allval testval];
    nfeval.overall=length(allval);
%     timeOver = timeovercheck(startTime, maxtime, maxclock, timeOverFileName, timeOver);
    
%     toc
    
    
    %%%%%%%%%%%%%%%%%%%%
    % finish iteration %
    %%%%%%%%%%%%%%%%%%%%
    
    % compute cost value and population standard deviation
    index = isfinite(val);
    if any(index)
        valstddev   = std(val(index));
        paramstddev = max(std(pop(index,:),0,1)' ./ diff(cell2mat(paramDefCell(:,2)),1,2));
    else
        valstddev   = inf;
        paramstddev = inf;
    end
    
    % check if population has changed
    if isequal(pop, popold)
        noChangeCounter = noChangeCounter + 1;
    else
        noChangeCounter = 0;
    end
    
    % check if any function evaluation was done
    if nfeval.last == nfeval.overall
        nofevalCounter = nofevalCounter + 1;
    else
        nofevalCounter = 0;
    end
    
    maxiterStablebest=annealing_schedule(iterationNr);
    
    % save history
    if saveHistory
        bestvalhist    (end+1) = bestval;     %#ok
        if isempty(bestvalhist_std)
            bestvalhist_std=0;
        else
            bestvalhist_std(end+1) = std(bestvalhist(max(1,length(bestvalhist)-maxiterStablebest):length(bestvalhist)));
            if bestvalhist_std(end)<eps(max(abs(bestvalhist)))*10
                bestvalhist_std(end)=0;
            end
        end
        bestmemhist  (:,end+1) = bestmem';    %#ok
        valstddevhist  (end+1) = valstddev;   %#ok
        paramstddevhist(end+1) = paramstddev; %#ok
        
        bestvalhist_stdint(end+1)=bestvalhist_std(end)/nanmax(bestvalhist_std);           
        
        % check if all possible members have been computed
%         if length(allval) >= nrOfPossibleMembers
%             timeOver = true;
%         end
    end
    
    % check time
%     if timeOver
%         break
%     end
    
    % display current state
    if ((infoIterations > 0) && (rem(iterationNr, infoIterations) == 0)) && ...
            mbtime - lastInfoIterTime > 10
        lastInfoIterTime = mbtime; % avoid many lines of output if no evaluations were done
        fprintf('Iteration %d finished.\n', iterationNr);
    end
    
    % check stable solution
%     sumbestvalhist=~((sum(bestvalhist==bestvalhist(end))>=maxiterStablebest) && ... %ensure stable solution for maxiterStablebest iterations
%         (bestvalhist_stdint(end)<0.02 || isnan(bestvalhist_stdint(end)))); %ensure low running-std in solutions relative to maximum running-std reached. Interval=maxiterStablebest.
%         %length(unique(bestvalhist))>1); %ensure algorithm has actually reached better solutions relative to initial input. If initial input is also the optimal solution, the algorithm will stop at maxiter
        sumbestvalhist=(iterationNr >= annealing_schedule(1)) && ((sum(bestvalhist==bestvalhist(end))>=maxiterStablebest) && (bestvalhist_stdint(end)<0.02));
        
        
        
        if iterationNr<DEParams.maxiter && sumbestvalhist==0
            iterationNr = iterationNr + 1;
        else
            bestvalhist_stdint=bestvalhist_stdint(1:end-1);
            
%             if iterationNr<annealing_schedule(iterationNr)
%                 disp([taskIdentifier,'    ',num2str(sum(bestvalhist==bestvalhist(end))),'|',num2str(maxiterStablebest),'  /  ',num2str(bestvalhist_stdint(end)),'     bestvalhist_stdint(end)=(',num2str(bestvalhist_std(end)),'/',num2str(nanmax(bestvalhist_std)),')'])
%             end
        end
    
end % while (iterationNr < DEParams.maxiter) ...

% if iterationNr<annealing_schedule(iterationNr) || iterationNr<annealing_schedule(1)
%    disp(['error 2:   ',taskIdentifier,'    TO: ',num2str(timeOver),'    iter: ',num2str(iterationNr),'|(',num2str(annealing_schedule(1)),'|',num2str(annealing_schedule(iterationNr)),')|',num2str(maxiterStablebest),'       ',num2str(sum(bestvalhist==bestvalhist(end))),'|',num2str(maxiterStablebest),'  /  ',num2str(bestvalhist_stdint(end)),'     bestvalhist_stdint(end)=(',num2str(bestvalhist_std(end)),'/',num2str(nanmax(bestvalhist_std)),')    sumbestvalhist=',num2str(sumbestvalhist)])
% end


% ~timeOver && ...
%         (iterationNr < DEParams.maxiter) && ...
%         (isempty(VTR) || isnan(VTR) || (bestval * minMaxSign > VTR * minMaxSign)) && sumbestvalhist==0

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Calculate statistical error of fit %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

ixopt=find(popbestval==popbestval(end),1,'first');
if ~isempty(popreinit)
    popreinit2=popreinit-(1:length(popreinit));
    ixopt_std=find(popreinit2>ixopt,1,'first');
    if ~isempty(ixopt_std)
        if size(pop,2)==4
            fit_uncertainty=(popstd(popreinit2(ixopt_std))/abs(bestmem(1)-bestmem(4)))*100; %percent
        elseif size(pop,2)==7
            fit_uncertainty=(popstd(popreinit2(ixopt_std))/abs(bestmem(1)-bestmem(4)+bestmem(5)))*100; %percent
        end
    else 
        if size(pop,2)==4
            fit_uncertainty=(popstd(end)/abs(bestmem(1)-bestmem(4)))*100; %percent
        elseif size(pop,2)==7
            fit_uncertainty=(popstd(end)/abs(bestmem(1)-bestmem(4)+bestmem(5)))*100; %percent
        end
    end
else
    if size(pop,2)==4
        fit_uncertainty=(popstd(end)/abs(bestmem(1)-bestmem(4)))*100; %percent
    elseif size(pop,2)==7
        fit_uncertainty=(popstd(end)/abs(bestmem(1)-bestmem(4)+bestmem(5)))*100; %percent
    end
end
if isempty(fit_uncertainty)
    WS=ws2struct();save([errordir,filesep,'workspace_OgiveDE_emptyfituncertainty_',taskIdentifier2,'.mat'],'WS')
    disp('ERROR DETECTED!')
end


catch me
   WS=ws2struct();save([errordir,filesep,'workspace_',datestr(now,'yyyymmdd_HHMMSS_FFF'),'_OgiveDE_error',taskIdentifier2,'.mat'],'WS')
   disp('--------------------------------')
   disp(taskIdentifier)
   error_output(me,1);
   disp('--------------------------------')
end




% figure
% set(gcf,'color','w')
% plot(popstd)
% hold on
% ax=axis;
% plot([popreinit2(ixopt_std) popreinit2(ixopt_std)],[ax(3) ax(4)],'--r')
% plot(popreinit2(ixopt_std),popstd(popreinit2(ixopt_std)),'or','markersize',10,'linewidth',2)
% xlabel('iterations')
% ylabel('flux standard deviation')
% title(['final uncertainty on fit: ',num2str(fit_uncertainty),' %'])
% export_fig('fit_uncertainty_example3.jpg','-r300');



%%%%%%%%%%%%%%%%%%%%%%%%
% display final result %
%%%%%%%%%%%%%%%%%%%%%%%%

% show why optimization was finished
if infoOutput==1
    disp(' ');
    disp(repmat('*', 1, textWidth));
    if iterationNr >= DEParams.maxiter
        state = sprintf('''%s'' finished after given maximum number of %d iterations.', ...
            optimInfo.title, DEParams.maxiter);
    elseif sumbestvalhist
        state = sprintf('''%s'' finished at %d iterations due to stability of best solution.', ...
            optimInfo.title, iterationNr);
    elseif ~isempty(VTR) && (bestval * minMaxSign <= VTR * minMaxSign)
        state = sprintf('''%s'' finished after specified cost value of %2.6g was reached.', ...
            optimInfo.title, VTR);
    elseif length(allval) >= nrOfPossibleMembers
        state = sprintf('''%s'' finished after all possible %d members have been tested.', ...
            optimInfo.title, nrOfPossibleMembers);
    elseif timeOver
        if ~isempty(maxtime) && mbtime - startTime > maxtime
            state = sprintf('''%s'' finished after given amount of time.', optimInfo.title);
        elseif ~isempty(maxclock) && etime(clock, maxclock) > 0
            state = sprintf('''%s'' finished at given end time.', optimInfo.title);
        elseif ~isempty(timeOverFileName) && ~existfile(timeOverFileName);
            state = sprintf('''%s'' finished after ''time over''-file was deleted.', optimInfo.title);
        end
    end
    disp(textwrap2(state));
    displayprogressinfo(startLoopTime, state, [], maxtime, maxclock, 1, ...
        nfeval, nrOfPossibleMembers, pop, bestval, allval, optimInfo, sendEmail);
    state = sprintf('Final result after %d iteration(s).', iterationNr);
    displaybestmember(paramDefCell, parameterDimVector, bestval, bestmem, allval, ...
        initval, initmem, 1, state, optimInfo, sendEmail, playSound);
end

% save final result
if saveHistory
    saveoptimizationstate(...
        paramDefCellInput, paramDefCell, parameterDimVector, optimInfo, bestval, bestmem, ...
        bestvalhist, bestmemhist, valstddevhist, paramstddevhist, pop, val, startTime, state, ...
        DEParams, allval, allmem, objFctName, objFctHandle, objFctSettings, objFctParams, ...
        emailParams, infoOutput, 1,saveHistoryFilename);
end
if infoOutput==1
    disp(repmat('*', 1, textWidth));
end

% display optimization parameter history
if displayResults && saveHistory
    displayoptimizationhistory(paramDefCell, allmem, allval);
end

% remove all remaining slave files
if exist(slaveFileDir, 'dir')
    remainingSlaveFiles = findfiles(slaveFileDir, 'iteration_*_member_*_*.mat', 'nonrecursive');
    deletewithsemaphores(remainingSlaveFiles);
end

% remove time-over file
if existfile(timeOverFileName)
    mbdelete(timeOverFileName,0,0);
end

if nargout > 0
    
    % compute parameter set with best member
    [bestFctParams, bestmem] = evaluateParameterContraints(...
        objFctParams, paramDefCell, parameterDimVector, bestmem);
    
    % get result file name
    if saveHistory
        resultFileName = saveoptimizationstate();
    else
        resultFileName = '';
    end
    
    varargout = {bestmem', bestval, bestFctParams, iterationNr, resultFileName, bestvalhist_stdint, bestvalhist, fit_uncertainty};
end




%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function timeOver = timeovercheck(startTime, maxtime, maxclock, timeOverFile, timeOver)

persistent lastCheckTime

if isempty(lastCheckTime)
    lastCheckTime = mbtime;
end

if timeOver
    return
end

curTime = mbtime;
if curTime - lastCheckTime > 1
    % only check once a second to save computation time
    timeOver = ...
        (~isempty(maxtime)      && ((curTime - startTime) > maxtime || maxtime == 0)) || ...
        (~isempty(maxclock)     &&  etime(clock, maxclock) > 0) || ...
        (~isempty(timeOverFile) && ~existfile(timeOverFile));
    lastCheckTime = curTime;
end


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function valid = alwaysvalid(varargin) %#ok

valid = true;


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function checkinputs(paramDefCell, objFctParams)

% check dimensions of paramDefCell
if ~iscell(paramDefCell)
    error('Input argument paramDefCell has to be a cell array.');
end
if isempty(paramDefCell)
    error('Input argument paramDefCell must not be empty.');
end
if size(paramDefCell, 2) < 3 || size(paramDefCell, 2) > 4
    error('Input argument paramDefCell has to consist of three or four columns.');
end

% check parameter names
for m = 1:size(paramDefCell, 1)
    for n = m+1:size(paramDefCell, 1)
        if strcmp(paramDefCell{m,1}, paramDefCell{n,1})
            error(textwrap2(sprintf(...
                'Parameter names in paramDefCell have to be unique. Parameter name %s was found twice.', ...
                paramDefCell{m,1})));
        end
    end
end

% check dimensions of cell contents
for k = 1:size(paramDefCell, 1)
    if (k > 1 && (isempty((paramDefCell{k,1})) || ~ischar(paramDefCell{k,1}))) || ...
            k == 1 && ~ischar(paramDefCell{k,1})
        error(textwrap2(sprintf([...
            'All cells in the first column of paramDefCell have to contain non-empty strings ', ...
            '(except when there is only one row).'])));
    end
    if isempty(paramDefCell{k,2}) || size(paramDefCell{k,2}, 2) ~= 2
        error(textwrap2([...
            'All cells in the second column of paramDefCell have to contain matrices with two ', ...
            'columns (the parameter limits).']));
    end
    if any(~isfinite(paramDefCell{k,2}))
        error(textwrap2([...
            'The parameter limit matrices may not contain Inf or NaN. You have to provide hard ', ...
            'parameter bounds in any case, sorry.']));
    end
    if isempty(paramDefCell{k,3}) || size(paramDefCell{k,3}, 2) ~= 1
        error(textwrap2([...
            'All cells in the third column of paramDefCell have to contain scalars or column vectors' ,...
            '(the parameter quantizations).']));
    end
    if size(paramDefCell{k,2}, 1) ~= size(paramDefCell{k,3}, 1)
        error(textwrap2([...
            'All vectors or matrices in the second, third and fourth row of paramDefCell have to ', ...
            'have the same number of rows.']));
    end
    if size(paramDefCell, 2) == 4
        if ~isempty(paramDefCell{k,4}) && size(paramDefCell{k,4}, 2) ~= 1
            error(textwrap2([...
                'All cells in the fourth column of paramDefCell have to be empty or contain scalars ', ...
                'or column vectors (the initial values).']));
        end
        if size(paramDefCell{k,2}, 1) ~= size(paramDefCell{k,4}, 1)
            error(textwrap2([...
                'All vectors or matrices in the second, third and fourth row of paramDefCell have to ', ...
                'have the same number of rows.']));
        end
    end
end

% check dimensions of objFctParams
if ~isempty(objFctParams) && isstruct(objFctParams)
    fieldNames = fieldnames(objFctParams);
    for k = 1:length(fieldNames)
        if ~isempty(objFctParams.(fieldNames{k})) && ...
                size(objFctParams.(fieldNames{k}), 2) ~= 1
            error('Only column vectors are allowed as parameters in objFctParams, sorry.');
        end
    end
end


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function checkDEParamsNewVsLoaded(DEParams, DEParamsLoaded)

if DEParams.NP ~= DEParamsLoaded.NP
    error(textwrap2(sprintf(...
        'Number of population members NP may not be changed when continuing optimization.')));
end

if DEParams.minimizeValue ~= DEParamsLoaded.minimizeValue
    error(textwrap2(sprintf(...
        'Value of parameter minimizeValue may not be changed when continuing optimization.')));
end

if ~isequal(DEParams.validChkHandle, DEParamsLoaded.validChkHandle)
    error(textwrap2(sprintf(...
        'Validity check function handle validity may not be changed when continuing optimization.')));
end


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function checkParamDefCellNewVsLoaded(paramDefCellInput, paramDefCellInputLoaded)

if ~isequal(paramDefCellInput(:,1), paramDefCellInputLoaded(:,1))
    error(textwrap2(sprintf(...
        'First column of paramDefCell may not be changed when continuing optimization.')));
end

for col = 2:size(paramDefCellInput, 2)
    for paramNr = 1:size(paramDefCellInput, 1)
        if any(size(paramDefCellInput{paramNr, col}) ~= size(paramDefCellInput{paramNr, col}))
            error(textwrap2(sprintf([...
                'Dimensions of range, quantization and initial values in paramDefCell may not be ', ...
                'changed when continuing optimization.'])));
        end
    end
end


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function checkBoundsAndQuantization(XVmin, XVmax, parGridVector, minQuantizationUser)

errorFound = false;
D = length(XVmin);
for parNr = 1:D
    if XVmin(parNr) > XVmax(parNr)
        disp(textwrap2(sprintf(...
            'Error: Lower bound (%g) of parameter %s is larger than upper bound (%g).', ...
            XVmin(parNr), getparametername(parNr, 1), XVmax(parNr))));
        errorFound = true;
    end
    if parGridVector(parNr) < 0
        disp(textwrap2(sprintf(...
            'Error: Negative quantization values are not allowed (parameter %s).', ...
            getparametername(parNr, 1))));
        errorFound = true;
    end
    
    if parGridVector(parNr) > 0 && (parGridVector(parNr) < minQuantizationUser)
        disp(textwrap2(sprintf(...
            'Error: Minimum quantization step size is %g (parameter %s).\n', minQuantizationUser, ...
            getparametername(parNr, 1))));
        errorFound = true;
    end
end
if errorFound
    error('Erroneous input parameters found.');
end


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function str = getparametername(varargin)

persistent paramDefCell parameterDimVector

if iscell(varargin{1})
    % initialization
    paramDefCell       = varargin{1};
    parameterDimVector = varargin{2};
    return
else
    % normal operation
    parNr    = varargin{1};
    nameMode = varargin{2};
end

if strcmp(paramDefCell{1,1}, '_1')
    str = sprintf('%d', parNr);
elseif parameterDimVector(parNr) > 1
    switch nameMode
        case 1
            % return for example "bla(2)" for parameter name "bla_2"
            str = regexprep(paramDefCell{parNr,1}, '_(\d)+$', '($1)');
        case 2
            % return for example "bla" for parameter name "bla_2"
            str = regexprep(paramDefCell{parNr,1}, '_\d+$', '');
        otherwise
            error('Name mode %d unknown.', nameMode);
    end
else
    str = paramDefCell{parNr,1};
end


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function pop = computerandominitialization(...
    randMode, pop, memIndex, paramDefCell, objFctSettings, parameterDimVector, XVmax, XVmin, ...
    validChkHandle)

if isempty(memIndex)
    return
end

switch randMode
    case 1
        % use first population member plus random noise
        baseMem = pop(1,:);
        randStdDev1   = 0.1;
        randStdDevAdd = 0.9;
    case 2
        % only use random numbers
        baseMem = XVmin;
        randStdDev1   = 1;
        randStdDevAdd = 0;
    otherwise
        error('Random initialization mode %d unknown.', randMode);
end

% initialize population randomly
D = size(pop, 2);
for n = memIndex
    pop(n,:) = baseMem + randStdDev1 * rand(1,D) .* (XVmax - XVmin);
end

% quantize all population vectors
quantPop = pop;
objFctParamsCell = cell(size(pop,1), 1);
for n = 1:size(pop,1)
    [objFctParamsCell{n}, quantPop(n,:)] = ...
        evaluateParameterContraints([], paramDefCell, parameterDimVector, pop(n,:)); %#ok
end

% check for multiple occurences and invalid parameter vectors and recompute random vectors
nindex = find(memIndex > 1, 1);
maxNrOfTests = min(1000 * D, 10 * length(memIndex));
nrOfRecomputations = 0;
for k = 1:maxNrOfTests
    if nindex == length(memIndex)
        break
    end
    n = memIndex(nindex);
    
    if any(all(abs(quantPop(1:n-1, :) - quantPop(n(ones(n-1, 1)), :)) < eps, 2)) || ...
            ~paramvecvalidity(paramDefCell, objFctSettings, objFctParamsCell{n}, ...
            quantPop(n,:), validChkHandle)
        
        % quantized member invalid or already in population, recompute member
        
        % increase random standard deviation
        randStdDev = randStdDev1 + nrOfRecomputations/maxNrOfTests*randStdDevAdd;
        nrOfRecomputations = nrOfRecomputations + 1;
        
        % compute new random parameter vector
        randmem = baseMem + randStdDev*rand(1,D).*(XVmax - XVmin);
        
        % consider parameter quantization
        [objFctParamsCell{n}, quantPop(n,:), quantmem2] = ...
            evaluateParameterContraints([], paramDefCell, parameterDimVector, randmem); %#ok
        pop(n,:) = quantmem2;
    else
        % quantized member unique, step to next member
        nindex = nindex + 1;
    end
end


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function displayprogressinfo(...
    startLoopTime, state, sendMailPeriod, maxtime, maxclock, timeOver, nfeval, ...
    nrOfPossibleMembers, pop, bestval, allval, optimInfo, sendEmail) %#ok

persistent nextSendMailTime

% elapsed time
elapsedTime = mbtime - startLoopTime;
str = sprintf('Elapsed time:                   %s\n', formattime(elapsedTime));

% time left
if ~timeOver
    timeLeft = inf;
    if ~isempty(maxtime) && isfinite(maxtime)
        timeLeft = min(timeLeft, maxtime - elapsedTime);
    end
    if ~isempty(maxclock)
        timeLeft = min(timeLeft, -etime(clock, maxclock));
    end
    if isfinite(timeLeft) && timeLeft > 0
        str = [str, sprintf('Time left:                      %s\n', formattime(timeLeft))];
    end
end

% function evaluations
str   = [str, sprintf('Number of function evaluations: %d\n',   nfeval.overall)];
if nfeval.slave > 0
    str = [str, sprintf('Number of slave evaluations:    %d\n',   nfeval.slave)];
end
percentage = round(nfeval.overall / nrOfPossibleMembers * 100);
if percentage > 0
    str = [str, sprintf('Percentage of members computed: %d %%\n', percentage)];
end
if nfeval.overall - nfeval.slave > 0
    str = [str, sprintf('Mean function evaluation time:  %s\n', ...
        formattime(elapsedTime / (nfeval.overall - nfeval.slave)))];
end

if ~isempty(allval)
    sameEvaluationValue = length(find(allval == bestval));
    if sameEvaluationValue > 1
        str = [str, sprintf('Vectors with best value:        %d\n', sameEvaluationValue)];
    end
end

disp(' ');
disp(str);

% send E-mail
if sendEmail && ~isempty(sendMailPeriod)
    if isempty(nextSendMailTime)
        nextSendMailTime = mbtime + sendMailPeriod;
    elseif mbtime - nextSendMailTime >= 0
        if ~isempty(sendMailPeriod)
            nextSendMailTime = nextSendMailTime + sendMailPeriod * ...
                (1 + floor((mbtime - nextSendMailTime) / sendMailPeriod));
        end
        subject = 'Progress information';
        if isfield(optimInfo, 'title')
            subject = [subject, sprintf(' (%s, host %s)', optimInfo.title, gethostname)];
        else
            subject = [subject, sprintf(' (host %s)', gethostname)];
        end
        sendmailblat(subject, [state, sprintf('\n'), str]);
    end
end


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function varargout = saveoptimizationstate(...
    paramDefCellInput, paramDefCell, parameterDimVector, optimInfo, bestval, bestmem, bestvalhist, ...
    bestmemhist, valstddevhist, paramstddevhist, pop, val, startTime, state, DEParams, allval, ...
    allmem, objFctName, objFctHandle, objFctSettings, objFctParams, emailParams, ...
    forceFileNameDisplay, forceSaveFile,saveHistoryFilename) %#ok

persistent resultFileName nextSaveTime %#ok

if nargin == 0
    if nargout == 0
        % initialization
        nextSaveTime   = NaN;
        resultFileName = '';
    else
        % return resultFileName
        varargout = {resultFileName};
    end
    return
end

% only save after a certain period of time
fileSavePeriod = 60; % in seconds
if isnan(nextSaveTime)
    nextSaveTime = mbtime + fileSavePeriod;
end

if forceSaveFile || mbtime - nextSaveTime >= 0
    nextSaveTime = mbtime + fileSavePeriod;
    
    D = size(paramDefCell, 1);
    hostname = gethostname;
    
    % save all interesing values in a structure using more meaningful variable names
    optimResult.info                     = optimInfo;
    optimResult.state                    = state;
    optimResult.startTime                = datestr(mbdatevec(startTime), 31);
    optimResult.startClock               = mbdatevec(startTime);
    optimResult.currentTime              = datestr(clock, 31);
    optimResult.DEParams                 = DEParams;
    optimResult.paramDefCellInput        = paramDefCellInput;
    optimResult.paramDefCell             = paramDefCell;
    optimResult.parameterDimVector       = parameterDimVector;
    optimResult.hostname                 = hostname;
    optimResult.bestMember               = bestmem'; % note: transposed!!
    optimResult.bestFctParams            = objFctParams; % to be modified below
    optimResult.objFctParams             = objFctParams;
    optimResult.objFctHandle             = objFctHandle;
    optimResult.objFctSettings           = objFctSettings;
    optimResult.boundaryValuesReached    = zeros(D,1); % to be overwritten below
    optimResult.bestEvaluationValue      = bestval;
    optimResult.bestMemberHistory        = bestmemhist;
    optimResult.bestValueHistory         = bestvalhist;
    optimResult.costValueStdDevHistory   = valstddevhist;
    optimResult.parameterStdDevHistory   = paramstddevhist;
    optimResult.currentPopulation        = pop'; % note: transposed!!
    optimResult.currentCostValues        = val;
    optimResult.allEvaluationValues      = allval;
    optimResult.allTestedMembers         = allmem;
    optimResult.emailParams              = emailParams;
    optimResult.fileFormatVersion        = 1.0; % modify check accordingly!
    
    if ~isempty(bestmem)
        
        % save quantized version of bestmem
        [ignore, bestmemQuantized] = evaluateParameterContraints(...
            [], paramDefCell, parameterDimVector, bestmem); %#ok
        optimResult.bestMemberQuantized = bestmemQuantized';
        
        % overwrite values in bestFctParams with best member
        if strcmp(paramDefCell{1,1}, '_1')
            % why was that?? optimResult = rmfield(optimResult, 'objFctParams');
        else
            parNr = 1;
            while parNr <= D
                index = parNr : (parNr + parameterDimVector(parNr) - 1);
                optimResult.bestFctParams.(getparametername(parNr, 2)) = bestmemQuantized(index);
                parNr = parNr + parameterDimVector(parNr);
            end
        end
        
        % check which boundard values are reached
        for parNr = 1:D
            optimResult.boundaryValuesReached(parNr) = ...
                any(bestmemQuantized(parNr) == paramDefCell{parNr,2});
        end
    end
    
    % get file number to avoid overwriting old results
    if isempty(resultFileName)
        if ~isempty(saveHistoryFilename)
            resultFileName=saveHistoryFilename;
            forceFileNameDisplay = false;
        else
            fileName = sprintf('%s_lastresultnumber.mat', objFctName);
            if exist('./data', 'dir')
                fileName = ['data/', fileName];
            end

            % save current result file number
            sem = setfilesemaphore(fileName, 'set always');
            if existfile(fileName)
                load(fileName);
                resultFileNr = mod(resultFileNr, 99) + 1; %#ok
            else
                resultFileNr = 1;
            end
            save(fileName, 'resultFileNr');
            removefilesemaphore(sem);

            % build file name
            resultFileName = sprintf('%s_result_%s_%02d.mat', objFctName, hostname, resultFileNr);
            if exist('./data', 'dir')
                resultFileName = ['data/', resultFileName];
            end
            forceFileNameDisplay = true;
        end
    end
    
    if forceFileNameDisplay
        fprintf('Results are saved in file %s.\n', resultFileName);
    end
    
    % save data
    sem = setfilesemaphore(resultFileName, 'set always');
    save(resultFileName, 'optimResult');
    removefilesemaphore(sem);
    
    % the following code is deactivated, as it uses a Perl script and an
    % external FTP program to upload the current results to a server. Contact
    % me if you are interested in this script.
    %
    % try %#ok
    %   % put file to server
    %   % (this is a file access that is not protected by a semaphore, but
    %   % different Matlab processes use different result file names)
    %   system(sprintf('start /B putfiletoserver.pl %s', resultFileName));
    % end
    
end % if forceSaveFile || mbtime - nextSaveTime >= 0


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function displaybestmember(...
    paramDefCell, parameterDimVector, bestval, bestmem, allval, initval, initmem, ...
    forceParameterDisplay, state, optimInfo, sendEmail, playSound)

persistent lastbestmem lastSoundTime lastEmailTime lastSubject lastStr
persistent maxNameLength hostname username

minTimeBetweenEmails = 30; % avoid sending many E-mails shortly after another

D = size(paramDefCell, 1);

if nargin == 1
    % initialize values
    lastbestmem   = NaN;
    lastEmailTime = -inf;
    lastSoundTime = mbtime;
    hostname = gethostname;
    username = getusername;
    
    % get maximum name length for proper display
    maxNameLength = 0;
    for parNr = 1:D
        maxNameLength = max(maxNameLength, length(getparametername(parNr, 1)));
    end
    return
end

% display current best member if it has changed or if display is forced
if ~any(isnan(lastbestmem)) && any(size(bestmem) ~= size(lastbestmem))
    error('Internal error: bestmem and lastbestmem are of different size!');
end
if any(bestmem ~= lastbestmem) || forceParameterDisplay
    sendEmailThisTime = 1;
    lastbestmem = bestmem;
    
    % display state
    str = sprintf('%s\n', state);
    
    % get quantized parameter vector for display
    [ignore, bestmem] = ...
        evaluateParameterContraints([], paramDefCell, parameterDimVector, bestmem); %#ok
    
    switch [username '@' hostname]
        case 'Markus@Edison'
            prefixString = 'param.';
        otherwise
            prefixString = '';
    end
    str = [str, sprintf('Best member:\n')];
    if all(bestmem == initmem) && isempty(strfind(state, 'Initial'))
        str = [str(1:end-2), sprintf(' (same as initial member):\n')];
    end
    for parNr=1:D
        if any(bestmem(parNr) == paramDefCell{parNr, 2});
            markStr = '% (boundary value)';
        else
            markStr = '';
        end
        if strcmp(paramDefCell{1,1}, '_1')
            str = [str, sprintf('%10g; %s\n', bestmem(parNr), markStr)]; %#ok
        else
            parameterName = getparametername(parNr, 1);
            str = [str, sprintf('%s%s = %g; %s\n', prefixString, [ parameterName, ...
                repmat(' ', 1, maxNameLength - length(parameterName))], ...
                bestmem(parNr), markStr)]; %#ok
        end
    end
    if bestval >= 1e-5
        str = [str, sprintf('Evaluation value: %2.6f\n', bestval)]; % always print zeros
    else
        str = [str, sprintf('Evaluation value: %2.6g\n', bestval)]; % use exponential notation for small values
    end
    if (bestval == initval) && (isempty(strfind(state, 'Initial')))
        str = [str(1:end-1), sprintf(' (same as initial value)\n')];
    end
    
    if ~isempty(allval)
        sameEvaluationValue = length(find(allval == bestval));
        if sameEvaluationValue > 1
            str = [str, sprintf('Number of vectors with same evaluation value: %d\n', ...
                sameEvaluationValue)];
        end
    end
    
    % display information
    disp(str);
    
    % play sound
%     if playSound && ~isempty(lastSoundTime) && mbtime - lastSoundTime > 60
%         [x, fs, bits] = wavread('applause.wav');
%         soundsc(x, fs, bits);
%         pause(length(x) / fs + 1);
%         lastSoundTime = mbtime;
%     end
else
    sendEmailThisTime = 0;
end

if ~sendEmail
    return
end

% send E-mail notification
if sendEmailThisTime
    % build subject and body
    if bestval >= 1e-5
        formatString = '%2.6f'; % always print zeros
    else
        formatString = '%2.6g'; % use exponential notation for small values
    end
    if forceParameterDisplay
        if ~isempty(strfind(lower(state), 'initial'))
            subject = sprintf(sprintf('Initial eval. value: %s', formatString), bestval);
        else
            subject = sprintf(sprintf('Best eval. value: %s', formatString), bestval);
        end
    else
        subject = sprintf(sprintf('New best eval. value: %s', formatString), bestval);
    end
    if isfield(optimInfo, 'title')
        subject = [subject, sprintf(' (%s, host %s)', optimInfo.title, gethostname)];
    else
        subject = [subject, sprintf(' (host %s)', gethostname)];
    end
    
    if mbtime - lastEmailTime < minTimeBetweenEmails
        % do not send now, save data for sending later
        lastSubject       = subject;
        lastStr           = str;
        sendEmailThisTime = 0;
    end
    
elseif ~isempty(lastSubject) && mbtime - lastEmailTime >= minTimeBetweenEmails
    % restore data that was not sent until now
    subject           = lastSubject;
    str               = lastStr;
    sendEmailThisTime = 1;
end

if sendEmailThisTime
    sendmailblat(subject, str);
    lastEmailTime = mbtime;
    lastSubject   = [];
    lastStr       = [];
end


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function [objFctParams, paramVec, paramVec2] = evaluateParameterContraints(...
    objFctParams, paramDefCell,  parameterDimVector, paramVec)

paramVec2 = paramVec; % paramVec2: not quantized

for parNr = 1:length(paramVec)
    % hard bound constraint
    parBounds = paramDefCell{parNr, 2};
    paramVec (parNr) = min(max(paramVec(parNr), parBounds(1)), parBounds(2));
    paramVec2(parNr) = paramVec(parNr);
    
    % parameter quantization
    minQuantization = 1e-14;
    parGrid = paramDefCell{parNr, 3};
    
    % quantize with at least some value larger eps, see also checkinputs
    parGrid = max(parGrid, minQuantization);
    paramVec(parNr) = parGrid * ...
        round((paramVec(parNr) - parBounds(1)) / parGrid) + parBounds(1);
end

% set parameter vector in objFctParams (always use quantized value here!)
if ~strcmp(paramDefCell{1,1}, '_1')
    parNr = 1;
    while parNr <= length(paramVec)
        index = parNr:parNr+parameterDimVector(parNr)-1;
        objFctParams.(getparametername(parNr,2)) = paramVec(index)';
        parNr = parNr + parameterDimVector(parNr);
    end
end


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function generatefilesforslaveprocess(...
    objFctHandle, objFctParams, objFctSettings, paramDefCell, parameterDimVector, ...
    pop, allmem, iterationNr, saveHistory, slaveFileDir, validChkHandle)

if ~exist(slaveFileDir, 'dir')
    return
end

% remove all existing slave files
existingSlaveFiles = findfiles(slaveFileDir, 'iteration_*_member_*_*.mat', 'nonrecursive');
deletewithsemaphores(existingSlaveFiles);

% build slave file name
slaveFileNameTemplate = ...
    concatpath(slaveFileDir, sprintf('iteration_%02d_member_XX_parameters.mat', iterationNr));

% generate new slave files
NP = size(pop,1);
if saveHistory
    allmem = [allmem, nan(size(pop,2), NP)];
else
    allmem = nan(size(pop,2), NP);
end
nrOfCols = size(allmem,2);

for memberNr = NP:-1:1
    testmem = pop(memberNr,:);
    
    % get constrained parameter vector
    [objFctParams, testmem] = evaluateParameterContraints(...
        objFctParams, paramDefCell, parameterDimVector, testmem); %#ok
    
    if ~paramvecvalidity(paramDefCell, objFctSettings, objFctParams, testmem, validChkHandle)
        % parameter vector invalid
        continue
    end
    
    % check if the current parameter vector was tested before
    index = find(all(abs(allmem - repmat(testmem', 1, nrOfCols)) < eps, 1));
    
    if length(index) > 1
        disp('Warning: More than one equal test vector in allmem (internal error?).');
    elseif ~isempty(index)
        continue
    end
    
    % save testmem in allmem, so that no two files with the same parameters are saved
    allmem(:,nrOfCols-memberNr+1) = testmem';
    
    % build cell array of function arguments
    if strcmp(paramDefCell{1,1}, '_1')
        % pass parameters as vector
        if iscell(objFctSettings)
            argumentCell = [objFctSettings, {testmem}];
        else
            argumentCell = {objFctSettings,  testmem};
        end
    else
        % pass parameters as structure objFctParams
        if iscell(objFctSettings)
            argumentCell = [objFctSettings, {objFctParams}];
        else
            argumentCell = {objFctSettings,  objFctParams};
        end
    end
    
    % save file
    memberNrString = sprintf(sprintf('%%0%dd', ceil(log10(NP+1))), memberNr);
    slaveFileName = strrep(slaveFileNameTemplate, 'XX', memberNrString);
    
    % save slave file
    sem = setfilesemaphore(slaveFileName, 'set always');
    objFctHandle; %#ok
    argumentCell; %#ok
    save(slaveFileName, 'objFctHandle', 'argumentCell');
    removefilesemaphore(sem);
end


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function valid = paramvecvalidity(...
    paramDefCell, objFctSettings, objFctParams, testmem, validChkHandle)

if strcmp(paramDefCell{1,1}, '_1')
    % pass parameters as vector
    if iscell(objFctSettings)
        valid = validChkHandle(objFctSettings{:}, testmem');
    else
        valid = validChkHandle(objFctSettings,    testmem');
    end
else
    % pass parameters as structure objFctParams
    if iscell(objFctSettings)
        valid = validChkHandle(objFctSettings{:}, objFctParams);
    else
        valid = validChkHandle(objFctSettings,    objFctParams);
    end
end

if ~isscalar(valid) || (~isnumeric(valid) && ~islogical(valid)) || ...
        ((abs(valid) > 1e-6) && (abs(valid - 1.0) > 1e-6))
    error('Function %s must return scalar value 0 or 1.', func2str(validChkHandle));
end


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function [testval, testmem, nfeval, allval, allmem] = computeevaluationvalue(...
    testmem, nfeval, timeOver, objFctParams, paramDefCell, parameterDimVector, objFctSettings, ...
    objFctHandle, saveHistory, allval, allmem, iterationNr, memberNr, NP, slaveFileDir, ...
    maxMasterEvals, validChkHandle, XVmin, XVmax)

persistent optParVector nrOfMasterEvaluations lastIterationNr

pauseTime    = 0.1;
maxPauseTime = 1;

pauseTimeSum = 0.0;
warningDisplayed = false;

if nargin == 0
    lastIterationNr       = NaN;
    nrOfMasterEvaluations = 0;
    return
end

% get constrained parameter vector
[objFctParams, testmem, testmem2] = evaluateParameterContraints(...
    objFctParams, paramDefCell, parameterDimVector, testmem);

% check if current parameter vector is valid
if ~paramvecvalidity(paramDefCell, objFctSettings, objFctParams, testmem, validChkHandle)
    testval = NaN;
    
    % write non-quantized value into population
    testmem = testmem2;
    return
end

% check if current parameter vector was tested before
if saveHistory && ~isempty(allmem)
    allmemIndex = find(all(abs(allmem - repmat(testmem', 1, size(allmem, 2))) < eps, 1));
    if length(allmemIndex) > 1
        disp('Warning: More than one equal test vector in allmem (internal error?).');
        allmemIndex = allmemIndex(1);
    end
else
    allmemIndex = [];
end

if ~isempty(allmemIndex)
    % parameter vector was tested before
    testval      = allval(allmemIndex);
    nfeval.saved = nfeval.saved + 1;
else
    % parameter vector was not tested before, compute evaluation value or
    % read from slave
    
    % build slave file name
    if ~exist(slaveFileDir, 'dir')
        slaveFileDir = '';
    end
    if lastIterationNr ~= iterationNr
        lastIterationNr = iterationNr;
        nrOfMasterEvaluations = 0;
    end
    if ~isempty(slaveFileDir)
        memberNrString = sprintf(sprintf('%%0%dd', ceil(log10(NP+1))), memberNr);
        slaveFileName = concatpath(slaveFileDir, sprintf(...
            'iteration_%02d_member_%s_result.mat', iterationNr, memberNrString));
        
        % remove slave parameter file if existing
        if nrOfMasterEvaluations < maxMasterEvals
            slaveParameterFileName = strrep(slaveFileName, 'result', 'parameters');
            deletewithsemaphores(slaveParameterFileName);
        end
    end
    
    if ~isempty(objFctHandle)
        testval = [];
        
        % check if the current parameter vector was tested before by slave process
        if ~isempty(slaveFileDir)
            while 1
                sem = setfilesemaphore(slaveFileName, 'set if existing');
                if existfile(slaveFileName)
                    load(slaveFileName, 'testval');
                    mbdelete(slaveFileName, 0);
                end
                removefilesemaphore(sem);
                
                if ~isempty(testval)
                    % result of slave process was loaded
                    nfeval.overall = nfeval.overall + 1;
                    nfeval.slave   = nfeval.slave   + 1;
                    break
                end
                if nrOfMasterEvaluations < maxMasterEvals
                    % master will evaluate current member
                    break
                else
                    % Wait until member was evaluated by slave.
                    % Caution! If any of the slave processes is interrupted, this loop will never be left!!
                    % Limiting the number of master evaluations is not safe!!
                    pause(pauseTime);
                    pauseTimeSum = pauseTimeSum + pauseTime;
                    pauseTime = min(2 * pauseTime, maxPauseTime);
                    
                    if (warningDisplayed == false) && (pauseTimeSum > 30)
                        disp(' ');
                        disp(textwrap2(sprintf([...
                            'Master is waiting for slave process because given maximum number of master ', ...
                            'evaluations (maxMasterEvals = %d) was reached.'], maxMasterEvals)));
                        disp(textwrap2(sprintf([...
                            'Caution!!! Limiting the maximum number of master evaluations is not safe, the ', ...
                            'optimization can get stuck if any slave process gets interrupted!'])));
                        warningDisplayed = true;
                    end
                    
                end
            end
        end
        
        % evaluate objective function
        if isempty(testval) && (nrOfMasterEvaluations < maxMasterEvals) && ~timeOver
            
            % run function
            if strcmp(paramDefCell{1,1}, '_1')
                % pass parameters as vector
                if iscell(objFctSettings)
                    testval = objFctHandle(objFctSettings{:}, testmem');
                else
                    testval = objFctHandle(objFctSettings,    testmem');
                end
            else
                % pass parameters as structure objFctParams
                if iscell(objFctSettings)
                    testval = objFctHandle(objFctSettings{:}, objFctParams);
                else
                    testval = objFctHandle(objFctSettings,    objFctParams);
                end
            end
            nrOfMasterEvaluations = nrOfMasterEvaluations + 1;
            nfeval.overall = nfeval.overall + 1;
            
            % check returned value
            if isempty(testval)
                error('Objective function returned empty evaluation value!');
            elseif ~isscalar(testval)
                error('Objective function returned vector as evaluation value!');
            end
        end
        
    else
        
        % compute distance to randomly chosen vector for testing
        if isempty(optParVector)
            optParVector = XVmin + rand(1, length(XVmin)) .* (XVmax - XVmin);
        end
        testval = sqrt(sum(testmem - optParVector).^2);
        pause(0.2);
        
    end % if ~isempty(objFctHandle)
    
    
    if ~isempty(testval)
        % save tested vector and resulting cost value
        if saveHistory
            allmem(:,end+1) = testmem';
            allval  (end+1) = testval;
        end
    else
        testval = NaN;
    end
end % if ~isempty(allmemIndex)

% write non-quantized value into population
testmem = testmem2;