Home > src > expAnneal.m

# expAnneal

## PURPOSE

- exponentially-decaying temperature annealing object

## SYNOPSIS

This is a script file.

## DESCRIPTION

     - exponentially-decaying temperature annealing object

     copyright 2009-2012 Blair Armstrong, Christine Watson, David Plaut

        This file is part of SOS

        SOS is free software: you can redistribute it and/or modify
        it for academic and non-commercial purposes
        under the terms of the GNU General Public License as published by
        the Free Software Foundation, either version 3 of the License, or
        (at your option) any later version.  For commercial or for-profit
        uses, please contact the authors (sos@cnbc.cmu.edu).

        SOS is distributed in the hope that it will be useful,
        but WITHOUT ANY WARRANTY; without even the implied warranty of
        MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
        GNU General Public License for more details.

## CROSS-REFERENCE INFORMATION

This function calls:

- expAnneal - exponentially-decaying temperature annealing object
- genericAnneal - abstract interface for annealing objects
- verbosePrint - master print function that regulates cmd line output based on verbosity flags

This function is called by:

- expAnneal - exponentially-decaying temperature annealing object
- sos - SOS optimization object

## SUBFUNCTIONS

- function obj = expAnneal(varargin)
- function temp = getTemp(obj)
- function anneal(obj,curIt,cost,deltaCost)
- function p = expAnnealInputParser()
- function numSteps(initDeltaCost, finalDeltaCost, pDecrease)
- function maxpDecrease(initDeltaCost, finalDeltaCost,nStep)
- function p = parseConstructorArgs(varargin)

## SOURCE CODE

    0001 % - exponentially-decaying temperature annealing object
    0002 %
    0003 % copyright 2009-2012 Blair Armstrong, Christine Watson, David Plaut
    0004 %
    0005 %    This file is part of SOS
    0006 %
    0007 %    SOS is free software: you can redistribute it and/or modify
    0008 %    it for academic and non-commercial purposes
    0009 %    under the terms of the GNU General Public License as published by
    0010 %    the Free Software Foundation, either version 3 of the License, or
    0011 %    (at your option) any later version.  For commercial or for-profit
    0012 %    uses, please contact the authors (sos@cnbc.cmu.edu).
    0013 %
    0014 %    SOS is distributed in the hope that it will be useful,
    0015 %    but WITHOUT ANY WARRANTY; without even the implied warranty of
    0016 %    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    0017 %    GNU General Public License for more details.
    0018
    0019 %    You should have received a copy of the GNU General Public License
    0020 %    along with SOS (see COPYING.txt).
    0021 %    If not, see <http://www.gnu.org/licenses/>.
    0022
    0023
    0024
    0025 classdef expAnneal < genericAnneal
    0026     %% Provides support for exponentially decaying temperature annealing
    0027     %
    0028     %  Provides support for an exponential anneal function governed by the
    0029     %  following equation:
    0030     %
    0031     %       temp = N*e^(-lambda*curStep);
    0032     %
    0033     % The Schedule operates as follows:
    0034     %   {blockSize} iterations are run with temperature set to Inf (the -1
    0035     %   value of curStep, which reflects the current temperature step).
    0036     %   provides an initial sample of the types of cost values encountered
    0037     %   when making purely random switches.  From this sample, the maximum
    0038     %   delta cost in the block is calculated by subtracting the biggest
    0039     %   cost from the smallest and multiplying this value by 10.  The x10
    0040     %   multiple is applied because in the context of the logicstic
    0041     %   function, a temperature 10x greater than deltaCost provides a good
    0042     %   approximation of random behavior.
    0043     %
    0044     %   Next, to fit the lambda term in the equation
    0045     %   the user must express how large of a decrease in this initial temp
    0046     %    is desired on the next step, as a probability.  For slower annealing, the
    0047     %   decrease in temperature should be small, and values should be close
    0048     %   to 1to 0.  For faster descent, values closer to 1 should be used.
    0049     %
    0050     %   Once the values for the variable in the formula have been derived,
    0051     %   the curStep is set to '0' and the initial temperature is calculated
    0052     %   using the formula (in this case = N).  Thus, the '0' step should
    0053     %   also basically yield random.
    0054     %
    0055     %   Subsequent changes in temperature occur when the state of the
    0056     %   optimizer is said to have reached thermal equilibrium and a new
    0057     %   temperature step begins.  This
    0058     %   approximated in the algorithm as when the previous two 'blocks' of
    0059     %   cost values are non-significantly different from one another
    0060     %   according to an independent samples t-test.  The value of this
    0061     %   t-test can be adjusted to make it easier or harder to reject the
    0062     %   null hypothesis.  In the present case, thermal equilibrium is
    0063     %   reached when we fail to reject the null hypothesis, and thus one
    0064     %   could also make a Type-II error and incorrectly fail to reject a
    0065     %   false null hypothesis.  This can be avoided by using p-values
    0066     %   closer to 1.  It doesn't take that much to cause a p-value to
    0067     %   exceed even the standard cutoff of 0.05 though if blockSizse
    0068     %   becomes large (e.g., 1000), so keep that in mind, otherwise thermal
    0069     %   equilibrium may never be reached
    0070     %
    0071     %   It is worth noting, however, that this measurement of
    0072     %   thermal equilibrium is merely intended to serve as a quick and
    0073     %   readily-interpretable approximation thereof.  A failure to reject
    0074     %   the null hypothesis does not stricly == confirmation of the null
    0075     %   hypothesis, and there are no explicit checks of the t-test
    0076     %   assumptions to have a strong basis for believing that the exact
    0077     %   p-value set is the true p-value for a given data set.  Again
    0078     %   though, for present purposes this approximation has proven to
    0079     %   adequately satisfy its intended purpose.
    0080     %
    0081     %
    0082     % PROPERTIES:
    0083     %     blockSize % size of the block of cost values used to determine initial max Delta cost and assess thermal equilibrium
    0084     %     pval % p-value for the test of equality of cost; p-values greater than this are indicative of thermal equilibrium.
    0085     %     N  %  N from exponential decay equation
    0086     %     lambda % lambda from exponental decay equation
    0087     %     curStep % current temperatuer step
    0088     %     pDecrease % proportion decrease in temperature on next step.
    0089     %     tempLog  % log of all temperature values produced by the algorithm, and the iteration they were set at
    0090     %     prevBlock % history of cost values from previous block
    0091     %     curBlock % history of cost values from current block
    0092     %     startDeltaCost % history of delta cost values from the first block for equation calibration.
    0093     %
    0094     %METHODS:
    0095     %   expAnneal(varargin) - CONSTRUCTOR
    0096     %   temp = getTemp(obj)  - Returns current temperature
    0097     %   anneal(obj,curIt,cost,deltaCost) - anneal current temperature using the exponentially decay annealing schedule.
    0098     %
    0099     %METHODS (Static)
    0100     %   numSteps(initDeltaCost, finalDeltaCost, pDecrease) % calculates the number of steps that would be necessary to go from initDeltaCost to finaldeltaCost
    0101     %   maxpDecrease(initDeltaCost, finalDeltaCost,nStep) % calculates the maxDecrease that would be necessary to go from initDeltaCost to finaldeltaCost using at least 3 drops in temperature.
    0102
    0103     %% PROPERTIES
    0104     properties
    0105         blockSize % size of the block of cost values used to determine initial max Delta cost and assess thermal equilibrium
    0106         pval % p-value for the test of equality of cost; p-values greater than this are indicative of thermal equilibrium.
    0107         N  %  N from exponential decay equation
    0108         lambda % lambda from exponental decay equation
    0109         curStep % current temperature step
    0110         pDecrease % proportion decrease in temperature on next step.
    0111         tempLog  % log of all temperature values produced by the algorithm, and the iteration they were set at
    0112         prevBlock % history of cost values from previous block
    0113         curBlock % history of cost values from current block
    0114         startDeltaCost % history of delta cost values from the first block for equation calibration.
    0115         overrideInitDeltaCost % user-specified override for the calculated initDeltaCost value.
    0116     end
    0117
    0118
    0119     methods
    0120         %% expAnneal CONSTRUCTOR
    0121         function obj = expAnneal(varargin)
    0122             % creates and initializes an expAnneal object
    0123             %
    0124             %PARAMETERS:
    0125             %Optional:
    0126             %   'blockSize'/integer - size of blocks to use when estimating the initial temperature and thermal equilibrium. Default: 1000
    0127             %   'pVal'/numeric - p-value to use when testing for thermal equilibrium. Default = 0.05
    0128             %   'pDecrease'/numeric - % decrease in previous temperature when temperature is decreased
    0129             %   'schedule'/'exp' - name of annealing schedule
    0130
    0131             verbosePrint('Creating exponential decay temperature annealing function...',...
    0132                 'expAnneal_constructor_startObjCreation');
    0133
    0134             p = expAnneal.parseConstructorArgs(varargin);
    0135
    0136             % potentially altered by user input
    0137             obj.blockSize = p.Results.blockSize; % must be >=2
    0138             obj.pval = p.Results.pval;
    0139             obj.pDecrease = p.Results.pDecrease;
    0140
    0141
    0142             if(any(strcmp(p.UsingDefaults,'overrideInitDeltaCost')))
    0143                 obj.overrideInitDeltaCost = NaN;
    0144             else
    0145                 obj.overrideInitDeltaCost = p.Results.overrideInitDeltaCost;
    0146             end
    0147
    0148
    0149             % variables for expDecay equation
    0150             obj.curStep = -1;
    0151             obj.N = NaN;
    0152             obj.lambda = NaN;
    0153
    0154             obj.tempLog = [];
    0155             obj.temp = Inf;
    0156             obj.tempLog = [obj.temp 0];
    0157
    0158             obj.curBlock = nan(obj.blockSize,1);
    0159             obj.startDeltaCost = nan(obj.blockSize,1);
    0160         end
    0161
    0162         %% temp = getTemp()  METHOD
    0163         function temp = getTemp(obj)
    0164             %Returns current temperature
    0165             temp = obj.temp;
    0166         end
    0167
    0168         %% anneal(obj,sosIt,cost) METHOD
    0169         function anneal(obj,curIt,cost,deltaCost)
    0170             %anneal current temperature using the exponentially decay annealing schedule.
    0171             %
    0172             % PARAMETERS:
    0173             %   curIt - current iteration in sosObj
    0174             %   cost - cost value produced during optimization
    0175             %   deltaCost - deltaCost value during optimization
    0176
    0177             if(mod(curIt,obj.blockSize)) == 0
    0178                 curIndex = obj.blockSize;
    0179             else
    0180                 curIndex = mod(curIt,obj.blockSize);
    0181             end
    0182
    0183             obj.curBlock(curIndex) = cost;
    0184
    0185
    0186             if(curIt <= obj.blockSize)
    0187                 obj.startDeltaCost(curIt) = deltaCost;
    0188             end
    0189
    0190             % if < 1 stepSize of iterations have been run, temp = inf to
    0191             % derive an initial estimation of typical cost values.  After
    0192             % this block, we can fit the decay equation
    0193             if(mod(curIt,obj.blockSize) == 0 && (curIt)/obj.blockSize == 1 )
    0194
    0195                 % The safest thing to do is to always use the largest
    0196                 % possible difference (maxCost - minCost in the set) as the
    0197                 % largest possible delta cost.  However, this  makes it
    0198                 % harder to reliably replicate a given run because the
    0199                 % initial calibration can be influenced by those two data
    0200                 % points alone.  So instead, use the 90th-10th percentile
    0201                 % as the basis for calibrating the annealing equation.
    0202
    0203                 percentiles = [2.5 97.5];
    0204                 scores = prctile(obj.startDeltaCost, percentiles);
    0205
    0206                 DeltaCost95 = scores(2) - scores(1);
    0207
    0208               %apply override if it has been specified;
    0209
    0210                if isnan(obj.overrideInitDeltaCost) == 0
    0211                    DeltaCost95 = obj.overrideInitDeltaCost;
    0212
    0213                    verbosePrint('Applying user-specified override to initDeltaCost', ...
    0214                     'expAnneal_anneal_calibration');
    0215                end
    0216
    0217                 % fit the decay function.
    0218                 % for the logistic funciton, if temp is 10x greater than
    0219                 % the largest cost, even the  minCost
    0220                 % would only have a 0.0525 chance of eliciting a swap.
    0221
    0222
    0223
    0224                 obj.N = DeltaCost95;
    0225
    0226                 step1Cost = (1-obj.pDecrease)*obj.N;
    0227                 obj.lambda = -1*log((step1Cost/obj.N))/1;
    0228
    0229                 obj.curStep = 0;
    0230
    0231                 obj.temp = obj.N*exp(-obj.lambda*obj.curStep);
    0232                 obj.tempLog = [obj.tempLog ; obj.temp curIt];
    0233
    0234                 obj.prevBlock = obj.curBlock;
    0235                 obj.curBlock = nan(obj.blockSize,1);
    0236
    0237
    0238                 verbosePrint([sprintf('%i) ', curIt), ...
    0239                     'Annealing Equation calibrated, changing temperature from ', ...
    0240                     num2str(obj.tempLog(length(obj.tempLog)-1),1), ...
    0241                     ' to ', num2str(obj.temp)], ...
    0242                     'expAnneal_anneal_calibration');
    0243
    0244             % otherwise, if a new block has been completed, see if thermal
    0245             % thermal equilibrium has been reached, i.e., cost is no longer
    0246             % descending
    0247             elseif (mod(curIt,obj.blockSize) == 0 && (curIt)/obj.blockSize > 1 )
    0248
    0249                 [H,p] = ttest2(obj.prevBlock,obj.curBlock,obj.pval,'both',...
    0250                             'unequal');
    0251
    0252                 verbosePrint([sprintf('%i) ', curIt), ...
    0253                     'p(thermEquil): ', num2str(p), ...
    0254                     '  prevBlock m = ', num2str(mean(obj.prevBlock)), ...
    0255                     ' (se = ', num2str(std(obj.prevBlock)/length(obj.prevBlock)), ...
    0256                     ') curBlock m = ', num2str(mean(obj.curBlock)), ...
    0257                     ' (se = ', num2str(std(obj.curBlock)/length(obj.curBlock)), ...
    0258                     ')'], ...
    0259                                 'expAnneal_anneal_pthermalEquil');
    0260
    0261                 %we've reached our operational definition of thermal
    0262                 %equilibrium if H == 0
    0263                 if H == 0
    0264                     obj.curStep = obj.curStep + 1;
    0265                     obj.temp = obj.N*exp(-obj.lambda*obj.curStep);
    0266                     obj.tempLog = [obj.tempLog ; obj.temp curIt];
    0267
    0268                     verbosePrint([sprintf('%i) ', curIt), ...'
    0269                         'Thermal Equilibrium Reached - Dropping temperature from ', ...
    0270                         num2str(obj.tempLog(length(obj.tempLog)-1,1)), ...
    0271                         ' to ', num2str(obj.temp)], ...
    0272                         'expAnneal_anneal_dropTemp');
    0273                 end
    0274
    0275                 obj.prevBlock = obj.curBlock;
    0276                 obj.curBlock = nan(obj.blockSize,1);
    0277
    0278             end
    0279         end % anneal
    0280     end
    0281
    0282
    0283     methods (Static)
    0284
    0285         %% p = expAnnealInputParser()
    0286         function p = expAnnealInputParser()
    0287             % creates an input parser for the constructor args
    0288             %
    0289             %PARAMETERS:
    0290             %   see constructor args
    0291
    0292             p = inputParser;
    0293
    0294             p.addParamValue('blockSize',1000, ...
    0295                 @(blockSize)validateattributes(blockSize, {'numeric'}, ...
    0296                 {'scalar', 'integer', 'positive', '>', 1}));
    0297             p.addParamValue('pval',0.05, ...
    0298                 @(pval)validateattributes(pval, {'numeric'}, ...
    0299                 {'scalar', 'positive', '>', 0, '<',1}));
    0300             p.addParamValue('pDecrease',0.5,...
    0301             @(pDecrease)validateattributes(pDecrease, {'numeric'}, ...
    0302                 {'scalar', 'positive', '>', 0, '<',1}));
    0303             p.addParamValue('schedule','exp', ...
    0304                 @(schedule)strcmp(schedule,'exp'));
    0305             %override value should be overriden later to set it to Nan
    0306             p.addParamValue('overrideInitDeltaCost',0,...
    0307                         @(overrideInitDeltaCost)validateattributes(overrideInitDeltaCost, {'numeric'}, ...
    0308                 {'scalar'}));
    0309
    0310         end
    0311
    0312
    0313         %% numSteps(initDeltaCost, finalDeltaCost, pDecrease) STATIC FUNCTION
    0314         function numSteps(initDeltaCost, finalDeltaCost, pDecrease)
    0315             % calculates the number of steps that would be necessary to go
    0316             % from initDeltaCost to finaldeltaCost, given a particular
    0317             % pDecrease.
    0318             %
    0319             % The intended use of this function is to help determine the
    0320             % value of pDecrease.  To do so, a couple of steps are
    0321             % invovled.  First, run sos with an exponential anneal function
    0322             % for expAnneal.blockSize iterations.  During this first block,
    0323             % temperature is set to infinitie, so cost values are changed
    0324             % randomly. Once blockSize iteractions have been completed,
    0325             % run <sosObj>.deltaCostPercentiles to see the  deltaCost value
    0326             % for the 97.5th - 2.5th percentile, which is the deltaCost
    0327             % value used by the exponential anneal object during it's
    0328             % calibration of the initial temperature value.  The next step
    0329             % is determining the finalDeltaCost value.  To determine that
    0330             % value, run SOS again, this time in greedy mode, and examine
    0331             % the distribution of deltaCosts once the algorithm reaches a
    0332             % frozen state.  For the stochastic annealing to find a better
    0333             % solution than what was found by the exponential annealer, it
    0334             % must approach that frozen state slowly.  For the frozen state
    0335             % to have been reached, by definition no swaps occured and
    0336             % therefore all delta costs should have an upper bound of zero.
    0337             %  For a very slow anneal, you could try to reach the point at
    0338             %  which a large number of swaps would have occured quite slowly,
    0339             % which corresponds to the delta cost from a high decile like 90%).
    0340             % This could take a while though. Alternatively, you could try
    0341             % to reach a lower decile instead (e.g., 10%).  A good
    0342             % compromise might be to aim for the 50th percentile so that
    0343             % you approach that point more slowly.  So to sum up to this
    0344             % point, input the initdeltaCost for the 97.5th to the 2.5th
    0345             % percentile from the first block in an
    0346             % exponential anneal optimization and the finalDeltaCost from
    0347             % a perceintile of your choice as the from the percentiles
    0348             % listed when a greedy anneal was run to a frozen state.
    0349             %
    0350             % Now, you have to decide what the pDecrease value will be.  It
    0351             % must be bounded between 0-1, and it should lead to at least 3
    0352             % steps for the exponential anneal to really be effective at
    0353             % gradually lowering temperature.  of course, more steps than 3
    0354             % will result in even slower and potentially better annealing.
    0355             % (1 step at inf, 1 intermediate step, and 1 step at a
    0356             % temperature low enough to cause freezing in a greedy anneal).
    0357             % Try a few different values to see how they would correspond
    0358             % to this constraint and the amount of time you're willing to
    0359             % wait while the algorithm runs.  Lowever values should lead to
    0360             % more steps, whereas higher value will lead to fewer steps.
    0361             %
    0362             %
    0363             % PARAMETERS
    0364             %   -initDeltaCost - the initial delta cost for the first
    0365             %      block of optimizatoin
    0366             %   -finalDeltaCost - the approximate delta cost value that you
    0367             %   wish to approach slowly to avoid premature freezing
    0368             %   -pDecrease - the reduction in the previous temperature to be
    0369             %       applied to generate the new temperature
    0370             %
    0371             %
    0372
    0373
    0374
    0375             validateattributes(initDeltaCost, {'numeric'}, ...
    0376                 {'scalar', 'positive', '>', 0});
    0377             validateattributes(finalDeltaCost, {'numeric'}, ...
    0378                 {'scalar', 'positive', '>', 0});
    0379             validateattributes(pDecrease, {'numeric'}, ...
    0380                 {'scalar', 'positive', '>', 0, '<',1});
    0381
    0382             if(finalDeltaCost >= initDeltaCost)
    0383                 error('final delta cost must be < init delta cost.  Consult the manual if this is not the case for your data.');
    0384             end
    0385
    0386
    0387
    0388             % calibrate the expAnneal equation
    0389             N = initDeltaCost*1;      %#ok<PROP>
    0390             step1Cost = (1-pDecrease)*N; %#ok<PROP>
    0391             lambda = -1*log((step1Cost/N))/1; %#ok<PROP>
    0392
    0393             %calculate initial temperature;
    0394             initTemp = N*exp(-lambda*0);   %#ok<PROP>
    0395
    0396             %calculate the ifnal temperature.
    0397             finalTemp = (initTemp * (finalDeltaCost/(initDeltaCost*10)))*10;
    0398
    0399             %calculate the number of steps.
    0400             nStep = -1*log(finalTemp/N)/lambda; %#ok<PROP>
    0401             nStep = upper(nStep);
    0402
    0403             msg = sprintf('\n%g steps needed to reach a temp low enough to freeze given finalDeltaCost\n', ...
    0404                         nStep);
    0405
    0406             verbosePrint(msg, ...
    0407                         'expAnneal_numSteps_nStep');
    0408
    0409             if(nStep < 3)
    0410                 verbosePrint(['Warning: pDecrease should be lowered until nStep >= 3 ',...
    0411                              char(10),'         at least if exponentially decaying annealing ',...
    0412                              char(10),'         is to have an appreciable effect on annealing'],...
    0413                              'expAnneal_numSteps_Warn');
    0414             end
    0415
    0416         end
    0417
    0418         %% maxpDecrease(initDeltaCost, finalDeltaCost) STATIC FUNCTION
    0419         function maxpDecrease(initDeltaCost, finalDeltaCost,nStep)
    0420             % calculates the maxDecrease that would be necessary to go
    0421             % from initDeltaCost to finaldeltaCost using at least 3 drops
    0422             % in temperature.
    0423             %
    0424             % The intended use of this function is to help determine the
    0425             % value of pDecrease.  To do so, a couple of steps are
    0426             % invovled.  First, run sos with an exponential anneal function
    0427             % for expAnneal.blockSize iterations.  During this first block,
    0428             % temperature is set to infinitie, so cost values are changed
    0429             % randomly. Once blockSize iteractions have been completed,
    0430             % run <sosObj>.deltaCostPercentiles to see the  deltaCost value
    0431             % for the 97.5th - 2.5th percentile, which is the deltaCost
    0432             % value used by the exponential anneal object during it's
    0433             % calibration of the initial temperature value.  The next step
    0434             % is determining the finalDeltaCost value.  To determine that
    0435             % value, run SOS again, this time in greedy mode, and examine
    0436             % the distribution of deltaCosts once the algorithm reaches a
    0437             % frozen state.  For the stochastic annealing to find a better
    0438             % solution than what was found by the exponential annealer, it
    0439             % must approach that frozen state slowly.  For the frozen state
    0440             % to have been reached, by definition no swaps occured and
    0441             % therefore all delta costs should have an upper bound of zero.
    0442             %  For a very slow anneal, you could try to reach the point at
    0443             %  which a large number of swaps would have occured quite slowly,
    0444             % which corresponds to the delta cost from a high decile like 90%).
    0445             % This could take a while though. Alternatively, you could try
    0446             % to reach a lower decile instead (e.g., 10%).  A good
    0447             % compromise might be to aim for the 50th percentile so that
    0448             % you approach that point more slowly.  So to sum up to this
    0449             % point, input the initdeltaCost for the 97.5th to the 2.5th
    0450             % percentile from the first block in an
    0451             % exponential anneal optimization and the finalDeltaCost from
    0452             % a perceintile of your choice as the from the percentiles
    0453             % listed when a greedy anneal was run to a frozen state.
    0454             %
    0455             % From this point, the algorithm will determine what the value
    0456             % of pDecrease would be if you were to have 3 steps in
    0457             % temperature during the annealing.  This is probably the
    0458             % minimum number that youèd wnat oth ave to be useful
    0459             % (otherwise you simply go from a first step of near-random
    0460             % behavior to a next step of basically stochastic behavior).
    0461             % If desired, you can then experiment with how many steps you
    0462             %
    0463             %
    0464             % PARAMETERS
    0465             %   -initDeltaCost - the initial delta cost for the first
    0466             %      block of optimizatoin
    0467             %   -finalDeltaCost - the approximate delta cost value that you
    0468             %   wish to approach slowly to avoid premature freezing
    0469             %   -pDecrease - the reduction in the previous temperature to be
    0470             %       applied to generate the new temperature
    0471             %
    0472             %
    0473
    0474
    0475
    0476             validateattributes(initDeltaCost, {'numeric'}, ...
    0477                 {'scalar', 'positive', '>', 0});
    0478             validateattributes(finalDeltaCost, {'numeric'}, ...
    0479                 {'scalar', 'positive', '>', 0});
    0480             validateattributes(nStep, {'numeric'}, ...
    0481                 {'integer', 'scalar', 'positive', '>', 0});
    0482
    0483             if(finalDeltaCost >= initDeltaCost)
    0484                 error('final delta cost must be < init delta cost.  See the manual for what to do if this is the case');
    0485             end
    0486
    0487             if(nStep < 3)
    0488                 error('nStep should be >=3 for exponentially-decaying annealing to have an appreciable effect');
    0489             end
    0490
    0491             % calibrate the expAnneal equation
    0492             N = initDeltaCost*1;      %#ok<PROP>
    0493
    0494             %calculate initial temperature;
    0495             initTemp = N*exp(0);   %#ok<PROP>
    0496
    0497             %calculate the ifnal temperature
    0498             finalTemp = (initTemp * (finalDeltaCost/(initDeltaCost*10)))*10;
    0499
    0500
    0501             lambda= -1*log(finalTemp/N)/(nStep); %#ok<PROP>
    0502
    0503             step1Cost = N*exp(-lambda*1);  %#ok<PROP>
    0504
    0505             pDecrease = -1*(step1Cost/N -1); %#ok<PROP>
    0506
    0507
    0508             msg = sprintf('\n%f is max pDecrease to ensure %d steps during exp anneal', ...
    0509                         pDecrease,nStep); %#ok<PROP>
    0510
    0511             verbosePrint(msg, ...
    0512                         'expAnneal_maxpDecrease_maxpDecrease');
    0513
    0514
    0515         end
    0516
    0517
    0518     end
    0519
    0520     methods (Static, Access = private)
    0521
    0522         %% parseConstructorArgs(varargin)
    0523         function p = parseConstructorArgs(varargin)
    0524             % parsers the constructor arguments
    0525             %
    0526             %PARAMETERS:
    0527             %   see constructor args
    0528
    0529             varargin = varargin{1};
    0530             p = expAnneal.expAnnealInputParser();
    0531             p.parse(varargin{:});
    0532         end
    0533     end
    0534 end
    0535