Home > src > sos.m

# sos

## PURPOSE

- SOS optimization object

## SYNOPSIS

This is a script file.

## DESCRIPTION

     - SOS optimization 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:

- dataFrame - dataframe object
- expAnneal - exponentially-decaying temperature annealing object
- genericStatTest - parent class for statistical test objects
- greedyAnneal - greedy annealing (i.e., T = 0) object
- logisticpSwapFunction - swap function based on the logistic curve
- randPopulationAndSampleCandidateSelection - random population and sample selection method for swaps
- randPopulationCandidateSelection - random population selection method for selecting swaps
- randSampleCandidateSelection - random sample method for selecting swaps
- sample - sample object
- seconds2human - human readable time output
- sos - SOS optimization object
- sosHistory - object for storing the detailed history of an optimization
- sosPlots - object used to create detailed plots of SOS optimization
- sos_gui - sos main GUI
- verbosePrint - master print function that regulates cmd line output based on verbosity flags

This function is called by:

- sos - SOS optimization object

## SUBFUNCTIONS

- function obj = sos(varargin)
- function obj = addSample(obj, sample)
- function present = containsSample(obj, sample)
- function constraint = addConstraint(obj, varargin)
- function present = containsConstraint(obj, constraint)
- function obj = initFillSamples(obj)
- function validItem = checkHardConstraintsFilling(obj,sample,sItemIndex,newItemDataFrame,newItemIndex)
- function swCost = checkHardConstraintsSwapping(obj,sample,sItemIndex,newItemDataFrame,newItemIndex)
- function swCost = checkSoftConstraintsSwapping(obj,targSample,targSampleIndex,feederdf, feederdfIndex)
- function swCost = checkMetaConstraintsSwapping(obj,~,~,~,~)
- function [colName,colMean,colStd,allData] = normalizeData(obj)
- function cost = initCost(obj)
- function cost = dispCost(obj)
- function setAnnealSchedule(obj,varargin)
- function setSampleCandidateSelectionMethod(obj,methodName)
- function setFeederdfCandidateSelectionMethod(obj,methodName)
- function setpSwapFunction(obj,swFunctionName)
- function goodEnding = optimize(obj,varargin)
- function doReport(obj,tStart,startIt)
- function createPlots(obj,dispIt)
- function updatePlots(obj)
- function createHistory(obj)
- function updateHistory(obj,curIt,cost,deltaCost,pFlip,temp)
- function writeHistory(obj,outFile)
- function setBufferedHistoryOutfile(obj,outFile)
- function enableBufferedHistoryWrite(obj)
- function disableBufferedHistoryWrite(obj)
- function writeSamples(obj)
- function writePopulations(obj)
- function writeAll(obj)
- function addttest(obj, varargin)
- function addztest(obj, varargin)
- function addkstest(obj, varargin)
- function pass = doStatTests(obj,varargin)
- function deltaCostPercentiles(obj)
- function p = sosInputParser()
- function p = parseConstructorArgs(varargin)

## SOURCE CODE

    0001 % - SOS optimization 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 classdef sos < genericStatTest
    0024     % Creates and supports optimization objects
    0025     %
    0026     % Inherits from handle so that by-reference passing can be used with
    0027     % the object
    0028     %
    0029     % PROPERTIES
    0030     %     samples % array of samples linked to SOS object
    0031     %     hardConstraints % array of hard constraint objects
    0032     %     softConstraints % array of soft constraint objects
    0033     %     metaConstraints % array of meta constraint objects
    0034     %     cost % current cost
    0035     %     sCandObj % object used to identify the target item in a sample which may be swapped
    0036     %     feederCandObj % object used to identify the item in a population/other sample to be swapped with the target sample item
    0037     %     pSwapObj  % object which determines the probability of making a swap based on deltaCost
    0038     %     annealObj % object used to anneal temperature in pSwap
    0039     %     maxIt % maximum number of iterations that an optimization will run for
    0040     %     allData % merge of all data from all samples/ pops linked to sosobj
    0041     %     allDataColName % name of columns in allData
    0042     %     allDataColMean % mean for each column in allData
    0043     %     allDataColStd  % stdev for each column in all data
    0044     %     reportInterval % number of iterations between progress reports
    0045     %     curIt % current optimization iteration
    0046     %     curFreezeIt % number of iterations cost has been frozen at a particular value
    0047     %     stopFreezeIt % number of frozen iterations before algorithm stops
    0048     %     sosstattests % array of handles to sos  stat tests requested by user
    0049     %     statInterval % number of iterations between stat reports
    0050     %     statTestReportStyle % style of report ('short' or 'full')
    0051     %     deltaCost % delta cost from soft constraints from last attempted flip that met all hard constraints
    0052     %     blockSize % number of iterations in a 'block' of trials for which average flip history /minDeltaCost stats are calculated
    0053     %     nFlip % number of flips so far in the block
    0054     %     deltaCostLog % log of deltaCost values for delta cost distribution analysis
    0055     %     oldNumIt % number of iterations requested on the last optimization.  This is the default number for future optimizations.
    0056     %     plotObj % sos object responsible for plotting
    0057     %     histObj % object that contains detailed optimization history data
    0058     %
    0059     % METHODS:
    0060     %   sos(varargin) -  Constructor
    0061     %   addSample(sample) adds a sample to the SOS object so that its items can be optimized.
    0062     %   present = containsSample(sample) evaluates whether the sos object already contains the specified sample
    0063     %   constraint = addConstraint(varargin) % Adds a constraint to be optimized and returns it
    0064     %   initFillSamples() % fills all samples to their specified capacity
    0065     %   validItem = checkHardConstraintsFilling(sample,sItemIndex,newItemDataFrame,newItemIndex) returns a flag indicating if newIem can be added to sample during the initial filling of samples.
    0066     %   swCost = checkHardConstraintsSwapping(sample,sItemIndex,newItemDataFrame,newItemIndex) returns the hard constraint cost of swapping item from newItemDataframe with item in sample.
    0067     %   swCost = checkSoftConstraintsSwapping(targSample,targSampleIndex,feederdf, feederdfIndex)  % calculates the cost of a swap on the soft constraints
    0068     %   swCost = checkMetaConstraintsSwapping(~,~,~,~)  % calcualtes the cost of a swap on the meta constraints
    0069     %   [colName,colMean,colStd,allData] = normalizeData() % Normalizes the data in the samples and populations linked to the SOS object to provide some coarse balancing of initial cost values.
    0070     %   cost = initCost()  %initializes and reports hard/soft/meta cost contraints
    0071     %   setpSwapFunction(obj,swFunctionName) %sets the pSwap function for the sos obj.
    0072     %   setSampleCandidateSelectionMethod(methodName) % sets the sample Candidate selection method
    0073     %   setFeederdfCandidateSelectionMethod(methodName)  % sets the feeder candidate selection method
    0074     %   setAnnealSchedule(varargin) % sets the anneal schedule for the SOS object
    0075     %   goodEnding = optimize()  % Optimizes samples based on specified constraints
    0076     %   doReport(tStart)  % displays a progress report from the last iteration in optimization
    0077     %   writeSamples() % writes the data from the samples to text files specified in their 'outFile' property
    0078     %   writePopulations() % writes the data from the populations to text files specified in their 'outFile' property
    0079     %   writeAll() write all populations and samples associated with SOS object to disk
    0080     %   addttest(obj, varargin) %adds a t-test to the list of analyses to run
    0081     %   addztest(varargin) %adds a z-test to the list of analyses to run
    0082     %   pass = doStatTests(varargin) % runs the stat tests and indicates if all passed the user hypotheses.
    0083     %   present = containsConstraint(constraint) % determines whether <constraint> is a constraint associated with the current SOSobj
    0084     %   cost = dispCost()  %reports hard/soft/meta cost contraints
    0085     %   deltaCostPercentiles() % displays the breakdown of deltaCost values per decile
    0086     %   createPlots(dispIt) % creates plots for several optimization parameters
    0087     %   updatePlots(curIt,cost,deltaCost,pFlip,temp) %updates the contents of the plot
    0088     %   createHistory() % creates plots for several optimization parameters
    0089     %   updateHistory(curIt,cost,deltaCost,pFlip,temp) %updates the contents of the plot
    0090     %   writeHistory(fileName) %writes all history saved to date to file 'fileName'
    0091     %   setBufferedHistoryOutfile(outFile) % writes the history on-line, one update at a time, to outfile
    0092     %   enableBufferedHistoryWrite() % enables writing of buffered history.
    0093     %   disbleBufferedHistoryWrite() % disables writing of buffered history.
    0094     %
    0095     % METHODS (STATIC,Acess = private)
    0096     %   p = parseConstructorArgs(varargin) - parses the sos constructor arguments
    0097
    0098     %% PROPERTIES
    0099     properties
    0100         samples % array of samples linked to SOS object
    0101         hardConstraints % array of hard constraint objects
    0102         softConstraints % array of soft constraint objects
    0103         metaConstraints % array of meta constraint objects
    0104         cost % current cost
    0105         sCandObj % object used to identify the target item in a sample which may be swapped
    0106         feederCandObj % object used to identify the item in a population/other sample to be swapped with the target sample item
    0107         pSwapObj  % object which determines the probability of making a swap based on deltaCost
    0108         annealObj % object used to anneal temperature in pSwap
    0109         maxIt % maximum number of iterations that an optimization will run for
    0110         allData % merge of all data from all samples/ pops linked to sosobj
    0111         allDataColName % name of columns in allData
    0112         allDataColMean % mean for each column in allData
    0113         allDataColStd  % stdev for each column in all data
    0114         reportInterval % number of iterations between progress reports
    0115         curIt % current optimization iteration
    0116         curFreezeIt % number of iterations cost has been frozen at a particular value
    0117         stopFreezeIt % number of frozen iterations before algorithm stops
    0118         sosstattests % array of handles to sos  stat tests requested by user
    0119         statInterval % number of iterations between stat reports
    0120         statTestReportStyle % style of report ('short' or 'full')
    0121         deltaCost % delta cost from soft constraints from last attempted flip that met all hard constraints
    0122         blockSize % number of iterations in a 'block' of trials for which average flip history /minDeltaCost stats are calculated
    0123         nFlip % number of flips so far in the block
    0124         deltaCostLog % log of deltaCost values for delta cost distribution analysis
    0125         oldNumIt % number of iterations requested on the last optimization.  This is the default number for future optimizations.
    0126         plotObj % object responsible for plotting
    0127         histObj % object that contains detailed optimization history data
    0128         targSampleCandSelectMethod % name of sample replacement method
    0129         feederdfCandSelectMethod % name of neighbor method
    0130         queryStopOptimize % how often to probe the gui to see if the stop button was pressed
    0131     end
    0132
    0133     %% PROPERTIES (Constant)
    0134     properties (Constant)
    0135         maxIt_def = 10000; % default
    0136         pSwapFunction_def = 'logistic'; % default
    0137         targSampleCandSelectMethod_def = 'random'; % default
    0138         feederdfCandSelectMethod_def = 'randomPopulationAndSample'; % default
    0139         reportInterval_def = 1000; % default
    0140         stopFreezeIt_def = 10000; % default
    0141         statInterval_def = 10000; % default
    0142         statTestReportStyle_def = 'short'; % default
    0143         blockSize_def = 1000; % default
    0144         queryStopOptimize_def = 100; % default
    0145     end
    0146
    0147     methods
    0148
    0149         %% sos CONSTRUCTOR
    0150         function obj = sos(varargin)
    0151             % Constructor
    0152             %
    0153             % SYNOPSIS:
    0154             % Creates an SOS object
    0155             %
    0156             %PARAMETERS:
    0157             %Optional:
    0158             %   'maxIt'/integer - maximum number of iterations to run the optimizer
    0159             %   'pSwapFunction'/string - name of pSwapFunction to use.
    0160             %   'targSampleCandSelectMethod'/string - name of target Sample Candidate selection method
    0161             %   'feederdfCandSelectMethod'/string - name of feeder dataframe candidate selection method
    0162             %   'reportInterval'/int - number of iterations between general cost reports
    0163             %   'stopFreezeIt'/int - operationalized number of sequential iterations cost value must remain the same for state to be considered 'frozen'
    0164             %   'statInterval'/int - number of iterations between stat reports
    0165             %   'statTestReportStyle'/string - style of stat reports ('short' or 'full')
    0166             %   'blockSize'/int - number of iterations in a block; used to determine length of deltaCostLog
    0167
    0168             verbosePrint([char(10) 'Creating sos Object'], ...
    0169                 'sos_constructor_startObjCreation');
    0170
    0171             p = sos.parseConstructorArgs(varargin);
    0172
    0173             %potentially user-specified variables
    0174             obj.maxIt = p.Results.maxIt;
    0175             obj.oldNumIt = obj.maxIt;
    0176             obj.reportInterval = p.Results.reportInterval;
    0177             obj.stopFreezeIt = p.Results.stopFreezeIt;
    0178             obj.statInterval = p.Results.statInterval;
    0179             obj.statTestReportStyle = p.Results.statTestReportStyle;
    0180             obj.blockSize = p.Results.blockSize;
    0181
    0182             obj.queryStopOptimize = obj.queryStopOptimize_def;
    0183
    0184             setpSwapFunction(obj,p.Results.pSwapFunction);
    0185             setSampleCandidateSelectionMethod(obj,...
    0186                 p.Results.targSampleCandSelectMethod);
    0187             setFeederdfCandidateSelectionMethod(obj,...
    0188                 p.Results.feederdfCandSelectMethod);
    0189
    0190             obj.targSampleCandSelectMethod = p.Results.targSampleCandSelectMethod;
    0191             obj.feederdfCandSelectMethod = p.Results.feederdfCandSelectMethod;
    0192
    0193
    0194             obj.curIt = 0;
    0195             obj.samples = [];
    0196             obj.hardConstraints = [];
    0197             obj.softConstraints = [];
    0198             obj.metaConstraints = [];
    0199             obj.sosstattests = [];
    0200             obj.curFreezeIt = 0;
    0201             obj.deltaCost = NaN;
    0202             obj.nFlip = NaN;
    0203             obj.deltaCostLog = nan(obj.blockSize,1);
    0204
    0205             %set default anneal schedule to greedy
    0206             obj.setAnnealSchedule();
    0207
    0208             verbosePrint(['Creation of sos object complete' char(10)], ...
    0209                 'sos_constructor_endObjCreation');
    0210         end
    0211
    0212
    0213         %% addSample METHOD
    0214         function obj = addSample(obj, sample)
    0215             % adds a sample to the SOS object so that its items can be optimized.
    0216             %
    0217             % CALL:
    0218             % <sosObj>.addSample(<sampleObj>)
    0219             %
    0220             % PARAMETERS:
    0221             % sample - a sample object
    0222
    0223             p = inputParser;
    0224             p.addRequired('obj');
    0225             p.addRequired('sample', ...
    0226                  @(sample)strcmp(class(sample),'sample'));
    0227             p.parse(obj,sample);
    0228
    0229             if(isempty(sample.population)==1)
    0230                 verbosePrint('Warning: Sample has not been linked with a population', ...
    0231                     'sos_addSample_NoPopForSampleWarn');
    0232             end
    0233
    0234             present = obj.containsSample(sample);
    0235
    0236             if(present == 1)
    0237                 verbosePrint('Warning: Sample has already been added.  It cannot be added again', ...
    0238                     'sos_addSample_SampleAlreadyAddedWarn');
    0239             else
    0240                 obj.samples = [obj.samples sample];
    0241                 verbosePrint('Adding new Sample...', ...
    0242                     'sos_addSample_sampleAdded');
    0243             end
    0244
    0245         end %addSample
    0246
    0247
    0248         %% present = containsSample(sample) METHOD
    0249         function present = containsSample(obj, sample)
    0250             % evaluates whether the sos object already contains the specified sample
    0251             %
    0252             % PARAMETERS:
    0253             %   sample - a sample object
    0254
    0255             p = inputParser;
    0256             p.addRequired('obj');
    0257             p.addRequired('sample', ...
    0258                  @(sample)strcmp(class(sample),'sample'));
    0259             p.parse(obj,sample);
    0260
    0261             present = max(ismember(obj.samples,sample));
    0262
    0263         end %addSample
    0264
    0265
    0266         %% addConstraint(varargin) METHOD
    0267         function constraint = addConstraint(obj, varargin)
    0268            % Adds a constraint to be optimized
    0269            %
    0270            % PARAMETERS:
    0271            % varies dependig on object to be created.  See
    0272            % genericConstraint and the specific constraint you wish to
    0273            % create for options.
    0274
    0275            constraint = genericConstraint.createConstraint('sosObj',obj,varargin{:});
    0276
    0277            if(strcmp(constraint.constraintType,'hard'))
    0278                obj.hardConstraints = [obj.hardConstraints {constraint}];
    0279            elseif(strcmp(constraint.constraintType,'soft'))
    0280                obj.softConstraints = [obj.softConstraints {constraint}];
    0281            elseif(strcmp(constraint.constraintType,'meta'))
    0282                obj.metaConstraints = [obj.metaConstraints {constraint}];
    0283            else
    0284                error('The type of the new constraint is not supported by the sos object.  Supported types are hard/soft/meta');
    0285            end
    0286
    0287         end
    0288
    0289         %% present = containsConstraint(constraint) METHOD
    0290         function present = containsConstraint(obj, constraint)
    0291             % determines whether <constraint> is a constraint associated with the current SOSobj
    0292             %
    0293             % Returns 1 if <constraint> is present, 0 otherwise
    0294
    0295             present = 0;
    0296
    0297             for i=1:length(obj.hardConstraints)
    0298                 if(obj.hardConstraints{i} == constraint)
    0299                     present = 1;
    0300                     return;
    0301                 end
    0302             end
    0303
    0304             for i=1:length(obj.softConstraints)
    0305                 if(obj.softConstraints{i} == constraint)
    0306                     present = 1;
    0307                     return;
    0308                 end
    0309             end
    0310
    0311             for i=1:length(obj.metaConstraints)
    0312                 if(obj.metaConstraints{i} == constraint)
    0313                     present = 1;
    0314                     return;
    0315                 end
    0316             end
    0317
    0318         end
    0319
    0320         %% initFillSamples()  METHOD
    0321         function obj = initFillSamples(obj)
    0322             % fills all samples to their specified capacity
    0323             %
    0324
    0325             verbosePrint('Filling All Samples...','sos_initFillSamples_start');
    0326
    0327             if(isempty(obj.samples))
    0328                  error('Error: No Samples in SOS Object!');
    0329             end
    0330
    0331             %total add stores references to the number of items left to
    0332             %fill in to all of the different samples.
    0333             totalAdd = [];
    0334             for i=1:length(obj.samples)
    0335                %find out how many observations are needed,
    0336                %how many have already been filled,
    0337                %and then fill the remainder
    0338
    0339                n = obj.samples(i).n;
    0340
    0341                if(isempty(obj.samples(i).data))
    0342                    curN= 0;
    0343                else
    0344                 curN = length(obj.samples(i).data{1});
    0345                end
    0346
    0347                toAdd = n-curN;
    0348                totalAdd = [totalAdd ones(1,toAdd)*i]; %#ok<AGROW>
    0349
    0350             end
    0351
    0352            %now add all of those observations from the appropriate
    0353            %population, enforcing hard bounds
    0354
    0355            while(isempty(totalAdd) ==0)
    0356                %select a sample at random
    0357                toAddIndex=floor((length(totalAdd)*rand)+1);
    0358                sIndex= totalAdd(toAddIndex);
    0359
    0360                %randomly select an item from it's population:
    0361                 %make sure that the target population has at least one
    0362                 %item still in it
    0363                 if(isempty(obj.samples(sIndex).population))
    0364                     error(['Sample ''',obj.samples(sIndex).name,''' is not filled to capacity, but has not been linked to a population to fill it']);
    0365                 end
    0366
    0367
    0368                 if(isempty(obj.samples(sIndex).population.data)==1)
    0369                     error(['sos.initFillSamples Failed because ', ...
    0370                         'a population was depeleted of items but ',...
    0371                         'more items were still needed']);
    0372                 else
    0373                     pItemIndex = ...
    0374                      floor(length(obj.samples(sIndex).population.data{1})*rand+1);
    0375                 end
    0376
    0377                 if(isempty(obj.samples(sIndex).data))
    0378                     sItemIndex = 1;
    0379                 else
    0380                     sItemIndex = length(obj.samples(sIndex).data{1});
    0381                 end
    0382
    0383                 %pass it the current sample, where the item will go in it,
    0384                 %then the population, and the item from the pop's index.
    0385                 validItem = obj.checkHardConstraintsFilling( ...
    0386                     obj.samples(sIndex),sItemIndex, ...
    0387                     obj.samples(sIndex).population,pItemIndex);
    0388
    0389                 if(validItem == 1)
    0390                     %add that population item to the sample list; remove it
    0391                     %from the population.
    0392                     totalAdd(toAddIndex)=[]; %#ok<AGROW>
    0393                     pItem = obj.samples(sIndex).population.popItem(pItemIndex);
    0394                     obj.samples(sIndex).appendItem(pItem);
    0395                 end
    0396            end
    0397         end % initFillSamples
    0398
    0399
    0400         %% validItem = checkHardConstraintsFilling(obj,sample,sItemIndex,newItemDataFrame,newItemIndex)
    0401         function validItem = checkHardConstraintsFilling(obj,sample,sItemIndex,newItemDataFrame,newItemIndex)
    0402             % returns a flag indicating if newItem can be added to sample during the initial filling of samples.
    0403             %
    0404             % Should only be invoked when initially filling the samples
    0405             %
    0406             %
    0407             %   sample - the target sample
    0408             %   sItemIndex - row index of item to swap
    0409             %   newItemDataframe - dataframe (sample/pop) containin the item to fill with.
    0410             %   newItemIndex - row index of item to swap.
    0411             validItem = 1;
    0412
    0413             for i=1:length(obj.hardConstraints)
    0414                 if(obj.hardConstraints{i}.s1 == sample)
    0415                     if (obj.hardConstraints{i}.itemCostFilling(...
    0416                             sample,sItemIndex, ...
    0417                             newItemDataFrame,newItemIndex) == 1)
    0418
    0419                         validItem = 0;
    0420                     end
    0421                 end
    0422             end
    0423         end % checkHardConstraintsFilling
    0424
    0425
    0426         %% swCost = checkHardConstraintsSwapping(obj,sample,sItemIndex,newItemDataFrame,newItemIndex)
    0427         function swCost = checkHardConstraintsSwapping(obj,sample,sItemIndex,newItemDataFrame,newItemIndex)
    0428             % returns the hard constraint cost of swapping item from newItemDataframe with item in sample.
    0429             %
    0430             % Generally, if swCost > 0 the swap should not be executed
    0431             %   sample - the target sample
    0432             %   sItemIndex - row index of item to swap
    0433             %   newItemDataframe - dataframe (sample/pop) containin the item to fill with.
    0434             %   newItemIndex - row index of item to swap.
    0435             curCost = 0;
    0436             newCost = 0;
    0437             for i=1:length(obj.hardConstraints)
    0438                 if(obj.hardConstraints{i}.s1 == sample)
    0439
    0440                     curCost = curCost + obj.hardConstraints{i}.cost;
    0441                     newCost = newCost + obj.hardConstraints{i}.swapCost(...
    0442                         sample,sItemIndex,newItemDataFrame,newItemIndex);
    0443                 elseif (obj.hardConstraints{i}.s1 == newItemDataFrame)
    0444                     curCost = curCost + obj.hardConstraints{i}.cost;
    0445                     newCost = newCost + obj.hardConstraints{i}.swapCost(...
    0446                         newItemDataFrame,newItemIndex,sample,sItemIndex);
    0447
    0448                 end
    0449             end
    0450
    0451             swCost = newCost - curCost ;
    0452
    0453         end
    0454
    0455         %% swCost =  checkSoftConstraintsSwapping(targSample,targSampleIndex,feederdf, feederdfIndex)
    0456         function swCost = checkSoftConstraintsSwapping(obj,targSample,targSampleIndex,feederdf, feederdfIndex)
    0457             % calculates the cost of a swap on the soft constraints
    0458             %
    0459             % PARAMETERS:
    0460             %   targSample - the target sample
    0461             %   targSampleIndex - row index of item to swap
    0462             %   feederdf - dataframe (sample/pop) containin the item to fill with.
    0463             %   feederdfIndex - row index of item to swap.
    0464             %
    0465             % RETURNS:
    0466             % swCost - cost of making the swap
    0467
    0468             swCost = 0;
    0469
    0470             for j=1:length(obj.softConstraints)
    0471                 if ((obj.softConstraints{j}.s1 == targSample ||  ...
    0472                         obj.softConstraints{j}.s2 == targSample || ...
    0473                         obj.softConstraints{j}.s1 == feederdf || ...
    0474                         obj.softConstraints{j}.s2 == feederdf ))
    0475                     swCost = swCost + ...
    0476                       obj.softConstraints{j}.swapCost(...
    0477                        targSample,targSampleIndex,feederdf, feederdfIndex);
    0478                 else
    0479                     swCost = swCost +obj.softConstraints{j}.cost;
    0480                 end
    0481             end
    0482         end
    0483
    0484         %% swCost = checkMetaConstraintsSwapping(~,~,~,~) METHOD
    0485         function swCost = checkMetaConstraintsSwapping(obj,~,~,~,~)
    0486             % calcualtes the cost of a swap on the meta constraints
    0487             %
    0488             %Parameters:
    0489             % parameters are the same as for hard and soft constraints, but
    0490             % are ignored.  They are accepted as arguments merely to
    0491             % increase the consistency of the argument.
    0492
    0493             %checking meta constraints is extremely computationally cheap,
    0494             %so they are calculated every time.
    0495
    0496            swCost = 0;
    0497
    0498            for j=1:length(obj.metaConstraints)
    0499                swCost = swCost + obj.metaConstraints{j}.swapCost();
    0500            end
    0501         end
    0502
    0503
    0504         %% [colName,colMean,colStd,allData] = normalizeData() METHOD
    0505         function [colName,colMean,colStd,allData] = normalizeData(obj)
    0506             % Normalizes the data in the samples and populations linked to the SOS object to provide some coarse balancing of initial cost values.
    0507
    0508             verbosePrint('Normalizing Population and Sample Data', ...
    0509                         'sos_normalizeData_start');
    0510
    0511             %empty data frame
    0512             allData = dataFrame();
    0513
    0514             alreadyMerged = {};
    0515
    0516             %go through each of the samples, and their populations.
    0517             for i=1:length(obj.samples)
    0518                 %first, check the population:
    0519
    0520                 popPresent = 0;
    0521                 if(isempty(alreadyMerged))
    0522                     popPresent = 0;
    0523                 else
    0524                     for j=1:length(alreadyMerged)
    0525                         if(alreadyMerged{j} == obj.samples(i).population)
    0526                             popPresent = 1;
    0527                         end
    0528                     end
    0529                 end
    0530
    0531                 %population has not already been added, so add it
    0532                 if(popPresent == 0)
    0533                     %only add the population if the sample does in fact
    0534                     %have a population
    0535                     if isempty(obj.samples(i).population) ~= 1
    0536                         allData = dataFrame.aContainsb(allData,obj.samples(i).population);
    0537                         allData = dataFrame.aContainsbData(allData,obj.samples(i).population);
    0538                         alreadyMerged = [alreadyMerged {obj.samples(i).population}]; %#ok<AGROW>
    0539                     end
    0540                 end
    0541
    0542                 %now add the sample
    0543                 allData = dataFrame.aContainsb(allData,obj.samples(i));
    0544                 allData = dataFrame.aContainsbData(allData,obj.samples(i));
    0545                 %we don't need to check that the sample hasn't been added
    0546                 %stricly speaking, because samples can only appear once.
    0547                 %However, this may be necessary in a future version of
    0548                 %the code...
    0549                 alreadyMerged = [alreadyMerged {obj.samples(i)}]; %#ok<AGROW>
    0550
    0551
    0552             end
    0553
    0554             %we now have all of the data in a single dataframe; each column
    0555             %can now be normalized and descriptive statistics stored.
    0556
    0557             colName = cell(1,length(allData.data));
    0558             colMean = NaN(1,length(allData.data));
    0559             colStd =  NaN(1,length(allData.data));
    0560
    0561
    0562             for i=1:length(allData.data)
    0563                 %if it's a numeric vector, calculate mean/stdev
    0564                 colName{i} = allData.header{i};
    0565
    0566                 if(strcmp(allData.format{i},'%f'))
    0567                    colMean(i) = nanmean(allData.data{i});
    0568                    colStd(i) = nanstd(allData.data{i});
    0569                 end
    0570             end
    0571
    0572             %configure the z-data field in each sample and population to
    0573             %reflect the new changes.
    0574
    0575             for i=1:length(alreadyMerged)
    0576                %link the current normalization to this object
    0577                 alreadyMerged{i}.sosObj = obj; %#ok<AGROW>
    0578                 alreadyMerged{i}.zdata = {}; %#ok<AGROW>
    0579
    0580                for j=1:length(alreadyMerged{i}.data)
    0581                    col = alreadyMerged{i}.data{j};
    0582
    0583                   if(strcmp(alreadyMerged{i}.format{j},'%f'))
    0584                       m= NaN;
    0585                       std = NaN;
    0586                       %get the relevant coefficients:
    0587                       for k=1:length(colName)
    0588                          if (strcmp(colName{k},alreadyMerged{i}.header{j}))
    0589                             m = colMean(k);
    0590                             std = colStd(k);
    0591                              break;
    0592                          end
    0593                       end
    0594
    0595                       %check that m and std exist
    0596                       if(isnan(m) || isnan(std))
    0597                           error('Normalization failed because either the mean or stdeviation was NaN');
    0598                       end
    0599
    0600                       %they exist, so normalization can proceed
    0601
    0602
    0603                       if std == 0
    0604                           verbosePrint(['Warning: No variance in column: ', alreadyMerged{i}.header{j}],...
    0605                             'sos_normalizeData_noVarWarn');
    0606                           std = 1;
    0607                       end
    0608
    0609                       col = (col-m)/std;
    0610
    0611                   end
    0612
    0613                   alreadyMerged{i}.zdata{j} = col; %#ok<AGROW>
    0614
    0615                end
    0616             end
    0617
    0618             obj.allData = allData;
    0619             obj.allDataColName = colName;
    0620             obj.allDataColMean = colMean;
    0621             obj.allDataColStd = colStd;
    0622
    0623         end %normalizeData
    0624
    0625
    0626         %% initCost() METHOD
    0627         function cost = initCost(obj)
    0628             %initializes and reports hard/soft/meta cost contraints
    0629
    0630             verbosePrint([char(10),'Initializing Constraints',char(10)],...
    0631                 'sos_initCost_startInit');
    0632
    0633
    0634
    0635             % hard constraints
    0636             hardConstraintCost = 0;
    0637             for j = 1:length(obj.hardConstraints)
    0638                 try
    0639                     tempCost = obj.hardConstraints{j}.initCost();
    0640                 catch exception
    0641                     if strcmp(exception.identifier, ...
    0642                             'MATLAB:cellRefFromNonCell')
    0643                         error(['ERROR: Data needed to calculate hard constraint cost #' num2str(j),' is missing.',...
    0644                             char(10),'       Have samples been filled and normalized?']);
    0645
    0646                     else
    0647                         throw exception
    0648                     end
    0649
    0650                 end
    0651
    0652                 verbosePrint(['   Hard Constraint #: ',num2str(j),...
    0653                     ' Cost: ' num2str(tempCost),'   ',obj.hardConstraints{j}.name], ...
    0654                         'sos_initCost_indivHardCost');
    0655                 hardConstraintCost = hardConstraintCost + tempCost;
    0656             end
    0657
    0658             verbosePrint(['Hard Constraint Total: ', num2str(hardConstraintCost)], ...
    0659                         'sos_initCost_totalHardCost');
    0660
    0661             % soft constraints
    0662             softConstraintCost = 0;
    0663             for j=1:length(obj.softConstraints)
    0664                 try
    0665                     tempCost = obj.softConstraints{j}.initCost();
    0666                 catch exception
    0667                     if strcmp(exception.identifier, ...
    0668                             'MATLAB:cellRefFromNonCell')
    0669                         error(['ERROR: Data needed to calculate soft constraint cost #' num2str(j),' is missing.',...
    0670                             char(10),'       Have samples been filled and normalized?']);
    0671
    0672                     else
    0673                         throw exception
    0674                     end
    0675
    0676                 end
    0677
    0678                 verbosePrint(['   Soft Constraint #: ',num2str(j),...
    0679                     ' Cost: ' num2str(tempCost),'   ',obj.softConstraints{j}.name], ...
    0680                         'sos_initCost_indivSoftCost');
    0681                softConstraintCost = softConstraintCost + tempCost;
    0682             end
    0683
    0684             verbosePrint(['Soft Constraint Total: ', num2str(softConstraintCost)], ...
    0685                         'sos_initCost_totalSoftCost');
    0686
    0687             % meta constraints
    0688             metaConstraintCost = 0;
    0689             for j=1:length(obj.metaConstraints)
    0690                 try
    0691                     tempCost = obj.metaConstraints{j}.initCost();
    0692                 catch exception
    0693                     if strcmp(exception.identifier, ...
    0694                             'MATLAB:cellRefFromNonCell')
    0695                         error(['ERROR: Data needed to calculate meta constraint cost #' num2str(j),' is missing.',...
    0696                             char(10),'       Have samples been filled and normalized?']);
    0697
    0698                     else
    0699                         throw exception
    0700                     end
    0701
    0702                 end
    0703
    0704                 verbosePrint(['   Meta Constraint #: ',num2str(j),...
    0705                     ' Cost: ' num2str(tempCost),'   ',obj.metaConstraints{j}.name], ...
    0706                         'sos_initCost_indivMetaCost');
    0707                metaConstraintCost = metaConstraintCost + tempCost;
    0708             end
    0709
    0710             verbosePrint(['Meta Constraint Total: ', num2str(metaConstraintCost)], ...
    0711                         'sos_initCost_totalMetaCost');
    0712
    0713
    0714             cost = softConstraintCost + metaConstraintCost;
    0715             obj.cost=cost;
    0716
    0717             verbosePrint([char(10),'TOTAL COST (soft + meta): ', num2str(cost), char(10)], ...
    0718                 'sos_initCost_totalSoftMetaCost');
    0719         end
    0720
    0721         %% dispCost() METHOD
    0722         function cost = dispCost(obj)
    0723             %reports hard/soft/meta cost contraints
    0724
    0725             verbosePrint([char(10),'Displaying Constraint Costs',char(10)],...
    0726                 'sos_dispCost_start');
    0727
    0728             % hard constraints
    0729             hardConstraintCost = 0;
    0730
    0731             for j = 1:length(obj.hardConstraints)
    0732                 tempCost = obj.hardConstraints{j}.cost;
    0733                 verbosePrint(['   Hard Constraint #: ',num2str(j),...
    0734                     ' Cost: ' num2str(tempCost),'   ',obj.hardConstraints{j}.name], ...
    0735                         'sos_dispCost_indivHardCost');
    0736                 hardConstraintCost = hardConstraintCost + tempCost;
    0737             end
    0738
    0739             verbosePrint(['Hard Constraint Total: ', num2str(hardConstraintCost)], ...
    0740                         'sos_dispCost_totalHardCost');
    0741
    0742             % soft constraints
    0743             softConstraintCost = 0;
    0744
    0745
    0746             for j=1:length(obj.softConstraints)
    0747                 tempCost = obj.softConstraints{j}.cost;
    0748                 verbosePrint(['   Soft Constraint #: ',num2str(j),...
    0749                     ' Cost: ' num2str(tempCost),'   ',obj.softConstraints{j}.name], ...
    0750                         'sos_dispCost_indivSoftCost');
    0751                softConstraintCost = softConstraintCost + tempCost;
    0752             end
    0753
    0754
    0755
    0756             verbosePrint(['Soft Constraint Total: ', num2str(softConstraintCost)], ...
    0757                         'sos_dispCost_totalSoftCost');
    0758
    0759             % meta constraints
    0760             metaConstraintCost = 0;
    0761
    0762
    0763             for j=1:length(obj.metaConstraints)
    0764                 tempCost = obj.metaConstraints{j}.cost;
    0765                 verbosePrint(['   Meta Constraint #: ',num2str(j),...
    0766                     ' Cost: ' num2str(tempCost),'   ',obj.metaConstraints{j}.name], ...
    0767                         'sos_dispCost_indivMetaCost');
    0768                metaConstraintCost = metaConstraintCost + tempCost;
    0769             end
    0770
    0771
    0772             verbosePrint(['Meta Constraint Total: ', num2str(metaConstraintCost)], ...
    0773                         'sos_dispCost_totalMetaCost');
    0774
    0775
    0776             cost = softConstraintCost + metaConstraintCost;
    0777             %obj.cost=cost;
    0778
    0779             verbosePrint([char(10),'TOTAL COST (soft + meta): ', num2str(cost), char(10)], ...
    0780                 'sos_dispCost_totalSoftMetaCost');
    0781
    0782             if isnan(cost)
    0783                 verbosePrint([char(10), ...
    0784                     'Warning: Cost was NaN.  This should not happen if cost terms ',...
    0785                     char(10),'         are present and cost has been initialized',...
    0786                     char(10)], 'sos_dispCost_warnCostNaN');
    0787             end
    0788
    0789         end %dispCost
    0790
    0791         %% setAnnealSchedule(varargin) METHOD
    0792         function setAnnealSchedule(obj,varargin)
    0793             % sets the anneal schedule for the SOS object
    0794             %
    0795             % PARAMETERS:
    0796             % Required:
    0797             % 'schedule'/scheduleName - param/value pair indicating the name of the anneal schedule to use.  Defaults to greedy'
    0798             %
    0799             % Optional:
    0800             %  - As required by specific schedule to create.  See its
    0801             %  constructor for details.
    0802
    0803             p = inputParser;
    0804             p.addRequired('obj', @(obj)strcmp(class(obj),'sos'));
    0805             p.addParamValue('schedule','greedy', ...
    0806                 @(schedule)ischar(schedule));
    0807             p.KeepUnmatched = true;
    0808
    0809             % in case no parameters are passed to varargin, must make the
    0810             % following decision
    0811             if(isempty(varargin) == false)
    0812                  p.parse(obj,varargin{:});
    0813             else
    0814                 p.parse(obj);
    0815             end
    0816
    0817             scheduleName = p.Results.schedule;
    0818
    0819             if any(strcmp(p.UsingDefaults,'schedule'))
    0820                 verbosePrint(['    Defaulting to ', scheduleName, ' annealing...'], ...
    0821                     'sos_setAnnealSchedule_defaultAnneal');
    0822             end
    0823
    0824            if(strcmp(scheduleName, 'greedy') == 1)
    0825                obj.annealObj = greedyAnneal(varargin{:});
    0826            elseif (strcmp(scheduleName, 'exp') == 1)
    0827                 obj.annealObj = expAnneal(varargin{:});
    0828            else
    0829                error(['There is no schedule named: ' schedule])
    0830            end
    0831         end
    0832
    0833
    0834         %% setSampleCandidateSelectionMethod(methodName) METHOD
    0835         function setSampleCandidateSelectionMethod(obj,methodName)
    0836             % sets the sample Candidate selection method
    0837             %
    0838             %PARAMETERS:
    0839             % Name of a sampleCandidateSelectionMethod
    0840
    0841             if (ischar(methodName) == false)
    0842                 error('{methodName} must be a string');
    0843             end
    0844
    0845            if (strcmp(methodName, 'random') == 1)
    0846                 obj.sCandObj = randSampleCandidateSelection(obj);
    0847            else
    0848                error(['Specified methodName ',methodName,' does not exist']);
    0849            end
    0850         end
    0851
    0852
    0853         %% setFeederdfCandidateSelectionMethod(obj,methodName)
    0854         function setFeederdfCandidateSelectionMethod(obj,methodName)
    0855             % sets the feeder candidate selection method
    0856             %
    0857             %PARAMETERS:
    0858             % name of a feederCandidateSelectionMethod
    0859
    0860             if (ischar(methodName) == false)
    0861                 error('{methodName} must be a string');
    0862             end
    0863
    0864            if (strcmp(methodName, 'randomPopulation') == 1)
    0865                 obj.feederCandObj= randPopulationCandidateSelection();
    0866                 obj.feederdfCandSelectMethod = methodName;
    0867            elseif (strcmp(methodName, 'randomPopulationAndSample') == 1)
    0868                 obj.feederCandObj= randPopulationAndSampleCandidateSelection(obj);
    0869                 obj.feederdfCandSelectMethod = methodName;
    0870            else
    0871                 error('Specified {methodName} does not exist');
    0872            end
    0873
    0874         end
    0875
    0876          %% setpSwapFunction(methodName) METHOD
    0877          function setpSwapFunction(obj,swFunctionName)
    0878              %sets the pSwap function for the sos obj.
    0879              %
    0880              %PARAMETERS:
    0881              %  swFunctionName - name of swap function.  Currently, 'logicistic' is the only supported function.
    0882
    0883             if (ischar(swFunctionName) == false)
    0884                 error('SOS:setSwapFunction {swFunctionName} is not a valid string');
    0885             end
    0886
    0887            if (strcmp(swFunctionName, 'logistic'))
    0888                 obj.pSwapObj = logisticpSwapFunction();
    0889            else
    0890                 error('SOS:setpSwapFunction: specified function does not exist');
    0891            end
    0892         end %setpSwapFunction
    0893
    0894
    0895         %% optimize() METHOD
    0896         function goodEnding = optimize(obj,varargin)
    0897             % Optimizes samples based on specified constraints
    0898             %
    0899             % PARAMETERS
    0900             %   numIt - number of iterations to run (otherwises uses
    0901             %           default from obj init)
    0902             %   'isGui' / 1 or 0 - flag denoting whether there is an active gui or not
    0903             % RETURNS:
    0904             %   1 if ended because statistical constraints reached, zero
    0905             %   otherwise
    0906
    0907             % It would be possible to seperate the normalization and
    0908             % costInitialization procedures so that they need not be run
    0909             % every time you begin optimizing.  In fact, the current code
    0910             % probably enforces such a constraint and should generate an
    0911             % error if normalization is attempted anyways.  Nevertheless,
    0912             % it costs little to enforce it at this point in time given
    0913             % that most time should be spent trying to make swaps, so it's
    0914             % left that way in this version of the code.  In the future, it
    0915             % may be useful to avoid any possible redundancy here, and also
    0916             % consider adding the fillSamples() command to the
    0917             % pre-optimization procedure.
    0918
    0919             verbosePrint(['Setting up optimization procedure...', ...
    0920                         char(10)], 'sos_optimize_begin');
    0921
    0922
    0923             %get all parameters passed to the alogirthm
    0924
    0925             p = inputParser;
    0926             p.addOptional('numIt',-1);
    0927             p.addParamValue('isGui',NaN);
    0928             p.parse(varargin{:});
    0929
    0930             if any(strcmp(p.UsingDefaults,'numIt'))
    0931                 % do nothing, allow defaults to be used
    0932             else
    0933                 numIt = p.Results.numIt;
    0934                 validateattributes(numIt, {'numeric'}, ...
    0935                     {'scalar', 'integer', 'positive', '>', 0})
    0936                 obj.maxIt = obj.curIt + numIt;
    0937                 obj.oldNumIt = numIt;
    0938             end
    0939
    0940             if any(strcmp(p.UsingDefaults,'isGui'))
    0941                 % do nothing, no gui
    0942                 isGui = 0;
    0943             else
    0944                 isGui = p.Results.isGui;
    0945
    0946                 if isGui == 1
    0947                     mainWindowHandle = sos_gui; %this connects/ launches the gui
    0948                     mainWindowData = guidata(mainWindowHandle);
    0949                     set(mainWindowData.pushbutton_stopOptimize,'UserData',0)
    0950                 elseif isGui == 0
    0951                     % do nothing
    0952                 else
    0953                     error('isGui should be a flag with value 1 or 0).');
    0954                 end
    0955             end
    0956
    0957
    0958             % flag indicating whether the optimization should be
    0959             % stopped or not, as inidicated in the GUI
    0960             stopOptimize = 0;
    0961
    0962             goodEnding = 0;
    0963
    0964             % make sure that there are samples linked with the object
    0965             % before running.
    0966
    0967             if isempty(obj.samples)
    0968                 error('Cannot start optimization - there are no samples to optimize');
    0969             end
    0970
    0971            if isempty(obj.pSwapObj)
    0972                 error('Cannot start optimization - the annealing schedule must be set (e.g., greedy, exp)');
    0973             end
    0974
    0975             % next, make sure that all of the samples have been filled.
    0976
    0977             for i=1:length(obj.samples)
    0978                 if isempty(obj.samples(i).data)
    0979                     error(['Cannot start optimization - sample ''',...
    0980                         obj.samples(i).name,''' is empty']);
    0981                 elseif length(obj.samples(i).data{1}) < obj.samples(i).n
    0982                     error(['Cannot start optimization - sample ''',...
    0983                         obj.samples(i).name,''' is missing items.  Did you initFillSamples()?']);
    0984                 end
    0985             end
    0986
    0987
    0988             if(obj.curIt == obj.maxIt)
    0989                 obj.maxIt = obj.maxIt+obj.oldNumIt;
    0990             elseif obj.curIt > obj.maxIt
    0991                 error('Cannot start Optimization - curIt should never be greater than maxIt.  Increase by <SOSobj>.maxIt = <larger val>?');
    0992             end
    0993
    0994
    0995             if(obj.curFreezeIt == obj.stopFreezeIt)
    0996                 obj.curFreezeIt = 0;
    0997                 verbosePrint('curFreezeIt was at maximum value at start of optimization; resetting to 0', ...
    0998                 'sos_optimize_resetFreezeIt');
    0999             end
    1000
    1001             obj.normalizeData();
    1002             obj.initCost();
    1003
    1004             % set up the sample and neighbor replacement methods
    1005             obj.setSampleCandidateSelectionMethod(obj.targSampleCandSelectMethod);
    1006             obj.setFeederdfCandidateSelectionMethod(obj.feederdfCandSelectMethod);
    1007
    1008
    1009
    1010             verbosePrint(['Optimizing for ', num2str(obj.maxIt-obj.curIt), ' iterations'], ...
    1011                 'sos_optimize_startOptimization');
    1012
    1013             tStart = tic;
    1014             startIt = obj.curIt;
    1015             allStatsPass = NaN;
    1016
    1017             reportHeader = [char(10), ' Iteration              Cost  %Complete       Elapsed   Remaining'];
    1018             verbosePrint(reportHeader,'sos_optimize_reportHeader');
    1019
    1020             while obj.curIt<obj.maxIt && ...
    1021                     obj.curFreezeIt < obj.stopFreezeIt && ...
    1022                     allStatsPass ~= 1 && ...
    1023                     stopOptimize == 0
    1024                 obj.curIt=obj.curIt+1;
    1025
    1026                 if mod(obj.curIt,obj.reportInterval) == 0  || obj.curIt == 1
    1027                     obj.doReport(tStart,startIt);
    1028                      obj.doStatTests('reportStyle','none');
    1029
    1030                     if isempty(obj.histObj) == 0
    1031                         %updatePlots
    1032                         pFlip = obj.nFlip/obj.reportInterval;
    1033                         obj.updateHistory(obj.curIt,obj.cost,...
    1034                               obj.deltaCost,pFlip,obj.annealObj.getTemp());
    1035                         obj.nFlip = 0;
    1036
    1037                         if isempty(obj.plotObj) == 0
    1038                             obj.updatePlots();
    1039                         end
    1040                     end
    1041                 end
    1042
    1043
    1044                 %select items to swap
    1045                 [targSample,targSampleIndex] = obj.sCandObj.getCandidateIndex();
    1046                 [feederdf, feederdfIndex] = obj.feederCandObj.getCandidateIndex(targSample);
    1047
    1048
    1049                 % check to see how swap fares with regard to hard
    1050                 % constraints.  Abort swap if it would lead to an
    1051                 % (increased) violation of hard constraints.
    1052                 sumHardswCost = obj.checkHardConstraintsSwapping(...
    1053                        targSample,targSampleIndex,feederdf, feederdfIndex);
    1054
    1055                 %if hard constraint was not violated or improved continue.
    1056                 %A value < 0 indicates that hard constraint was improved so
    1057                 %there will be a swap no matter what the soft cost.
    1058                 if sumHardswCost <= 0
    1059                    curCost = obj.cost;
    1060
    1061                     sumSoftswCost = obj.checkSoftConstraintsSwapping(...
    1062                        targSample,targSampleIndex,feederdf, feederdfIndex);
    1063
    1064                     sumMetaswCost = obj.checkMetaConstraintsSwapping(...
    1065                        targSample,targSampleIndex,feederdf, feederdfIndex);
    1066
    1067                     swCost = sumSoftswCost + sumMetaswCost;
    1068                     %sign flipped so that if swCost < curCost, we get a
    1069                     %negative value, and negative values descend in cost
    1070                     %space
    1071
    1072                     deltaCost = -1*(curCost - swCost); %#ok<PROP>
    1073
    1074                     % if a swap is possible based on hard constraints, but
    1075                     % not necessary, base decision to swap on soft
    1076                     % constraints
    1077                     if sumHardswCost == 0
    1078                         shouldSwap = obj.pSwapObj.shouldSwap(...
    1079                             deltaCost,obj.annealObj.getTemp()); %#ok<PROP>
    1080
    1081                         obj.deltaCost = deltaCost; %#ok<PROP>
    1082
    1083
    1084
    1085                     else %swap is necessary based on hard constraints.
    1086                         shouldSwap = 1;
    1087
    1088                     end
    1089
    1090                     if shouldSwap == 1
    1091
    1092                         obj.nFlip = obj.nFlip + 1;
    1093
    1094
    1095                         %we need to swap items
    1096                         targSample.swapItems(...
    1097                         targSampleIndex,feederdf, feederdfIndex,obj);
    1098
    1099                         %update constraints
    1100                         for j = 1:length(obj.hardConstraints)
    1101                             obj.hardConstraints{j}.acceptSwap();
    1102                         end
    1103
    1104                         for j=1:length(obj.softConstraints)
    1105                             obj.softConstraints{j}.acceptSwap();
    1106                         end
    1107
    1108                         for j=1:length(obj.metaConstraints)
    1109                             obj.metaConstraints{j}.acceptSwap();
    1110                         end
    1111
    1112                         % see if the set is frozen
    1113                         if sumHardswCost < 0
    1114                             obj.curFreezeIt = 0;
    1115                         elseif obj.cost ~= swCost
    1116                             obj.curFreezeIt = 0;
    1117                         else % we're swapping items with the same cost
    1118                             obj.curFreezeIt = obj.curFreezeIt +1;
    1119                         end
    1120
    1121                         obj.cost = swCost;
    1122                     else
    1123                         % reject the swap:
    1124                         for j = 1:length(obj.hardConstraints)
    1125                             obj.hardConstraints{j}.rejectSwap();
    1126                         end
    1127
    1128                         for j=1:length(obj.softConstraints)
    1129                             obj.softConstraints{j}.rejectSwap();
    1130                         end
    1131
    1132                         for j=1:length(obj.metaConstraints)
    1133                             obj.metaConstraints{j}.rejectSwap();
    1134                         end
    1135
    1136                         obj.curFreezeIt = obj.curFreezeIt + 1;
    1137
    1138                     end
    1139                 else
    1140                     for j = 1:length(obj.hardConstraints)
    1141                             obj.hardConstraints{j}.rejectSwap();
    1142                     end
    1143
    1144                     obj.curFreezeIt = obj.curFreezeIt + 1;
    1145                 end
    1146                 %on some subset of the intervals, display relevant
    1147                 %statistics.
    1148
    1149                 %mod indexing needed to have deltaCostLog loop after
    1150                 %blockSize updates.
    1151                 obj.deltaCostLog(mod(obj.curIt-1,obj.blockSize)+1) = obj.deltaCost;
    1152
    1153
    1154                 obj.annealObj.anneal(obj.curIt,obj.cost,obj.deltaCost);
    1155
    1156                 % see if stats constraint has been met
    1157                 if mod(obj.curIt,obj.statInterval) == 0
    1158                     allStatsPass = ...
    1159                         obj.doStatTests('reportStyle',obj.statTestReportStyle);
    1160                     verbosePrint(reportHeader,'sos_optimize_reportHeader');
    1161                 end
    1162
    1163                 %see if GUI interrupt has been requested
    1164                 if isGui
    1165                     % check to see if the stop button has been pressed
    1166                     % every so often.  This should not be done too
    1167                     % frequently as the drawnow event could take some time.
    1168                     if mod(obj.curIt,obj.queryStopOptimize) == 0
    1169                         drawnow;
    1170                         if  get(mainWindowData.pushbutton_stopOptimize,'UserData') ~= 0
    1171                             stopOptimize = 1;
    1172                         end
    1173                     end
    1174                 end
    1175
    1176
    1177             end %end iterations
    1178
    1179             %avoid a redundant report
    1180             if mod(obj.curIt,obj.reportInterval) ~= 0 && obj.curIt ~= 1
    1181                 obj.doReport(tStart,startIt);
    1182                 obj.doStatTests('reportStyle','none');
    1183
    1184                 if isempty(obj.histObj) == 0
    1185                     %updatePlots
    1186                     pFlip = obj.nFlip/obj.reportInterval;
    1187                     obj.updateHistory(obj.curIt,obj.cost,...
    1188                           obj.deltaCost,pFlip,obj.annealObj.getTemp());
    1189                     obj.nFlip = 0;
    1190
    1191                     if isempty(obj.plotObj) == 0
    1192                         obj.updatePlots();
    1193                     end
    1194                 end
    1195             end
    1196
    1197             if mod(obj.curIt,obj.statInterval) ~= 0
    1198                     allStatsPass = ...
    1199                         obj.doStatTests('reportStyle',obj.statTestReportStyle);
    1200             end
    1201
    1202             % state the reason why optimization was stopped
    1203            if (allStatsPass == 1)
    1204                 verbosePrint([[char(10), 'Optimization ended after all statistical tests passed defined criteria', char(10)], ...
    1205                         char(10)], 'sos_optimize_endallStatsPass');
    1206                 goodEnding = 1;
    1207            elseif obj.curIt == obj.maxIt
    1208                 verbosePrint([char(10), 'Optimization ended after reaching the maximum number of iterations', ...
    1209                         char(10)], 'sos_optimize_endMaxIt');
    1210            elseif obj.curFreezeIt >= obj.stopFreezeIt
    1211                 verbosePrint([char(10), 'Optimization ended after cost value was frozen for specified number of iterations', ...
    1212                         char(10)], 'sos_optimize_endstopFreezeIt');
    1213            elseif isGui
    1214                if get(mainWindowData.pushbutton_stopOptimize,'UserData') == 1
    1215                verbosePrint([char(10),'Optimization ended after user interrupt (from graphical interface)',...
    1216                         char(10)],'sos_optimize_endUserGuiInterrupt');
    1217                end
    1218            end
    1219
    1220             if isGui == 1
    1221                 mainWindowHandle = sos_gui; %this connects/ launches the gui
    1222                 mainWindowData = guidata(mainWindowHandle);
    1223                 set(mainWindowData.pushbutton_optimize,'Enable','on')
    1224                 set(mainWindowData.pushbutton_stopOptimize,'Enable','off')
    1225             end
    1226
    1227         end
    1228
    1229
    1230         %% doReport (obj,tstart) METHOD
    1231         function doReport(obj,tStart,startIt)
    1232             % displays a progress report from the last iteration in optimization
    1233             %
    1234             %PARAMETERS:
    1235             %   tStart - tic() object indicating start of optimization
    1236
    1237             percentComplete = (obj.curIt/obj.maxIt)*100;
    1238             elapsedTime = toc(tStart);
    1239
    1240             startPercent = (startIt/obj.maxIt)*100;
    1241
    1242             remainingTime = (elapsedTime/ ...
    1243                (percentComplete-startPercent))*(100-startPercent)-elapsedTime;
    1244
    1245             hElapsedTime = seconds2human(elapsedTime,'full');
    1246             tempLen = length(hElapsedTime);
    1247             hElapsedTime = strjust([blanks(8-tempLen) hElapsedTime],'right');
    1248
    1249             hRemainingTime = seconds2human(remainingTime,'full');
    1250             tempLen = length(hRemainingTime);
    1251             hRemainingTime = strjust([blanks(8-tempLen) hRemainingTime],'right');
    1252
    1253
    1254             report = sprintf('%9.0f) \t %15.5f \t %5.2f%% \t %s \t %s', ...
    1255                     obj.curIt,obj.cost,percentComplete, ...
    1256                     hElapsedTime,hRemainingTime);
    1257             verbosePrint(report, 'sos_optimize_report');
    1258
    1259         end
    1260
    1261         %% createPlots() METHOD
    1262         function createPlots(obj,dispIt)
    1263             % creates plots for several optimization parameters, as
    1264             % follows:
    1265             %   - cost
    1266             %   - deltaCost
    1267             %   - sosStatTestpvals
    1268             %   - temperature
    1269             %   - pFlipHistory
    1270             %
    1271             % PARAMETERS:
    1272             %   dispIt - number of iterations to show on the plot screen.
    1273             %       All other datapoints plotted since the creation of the
    1274             %       object will still be accessible by scrolling the x-axis
    1275
    1276
    1277             if isempty(obj.histObj)
    1278                 obj.createHistory();
    1279             end
    1280
    1281             if exist('dispIt','var') == 0
    1282                 dispIt = 100000;
    1283             else
    1284                 validateattributes(dispIt, {'numeric'}, ...
    1285                 {'scalar', 'integer', 'positive', '>', 0});
    1286             end
    1287
    1288
    1289             if isempty(obj.plotObj)
    1290                 obj.plotObj = sosPlots(obj,obj.histObj,dispIt, ...
    1291                                         obj.curIt);
    1292             else
    1293                 verbosePrint('Warning: Plots already exist so cannot be created',...
    1294                     'sos_createPlots_alreadyCreated');
    1295             end
    1296         end
    1297
    1298         %% updatePlots() METHOD
    1299         function updatePlots(obj)
    1300             %updates the contents of the plot
    1301
    1302             obj.plotObj.updatePlots();
    1303
    1304         end
    1305
    1306
    1307         %% createHistory() METHOD
    1308         function createHistory(obj)
    1309             % creates plots for several optimization parameters, as
    1310             % follows:
    1311             %   - cost
    1312             %   - deltaCost
    1313             %   - sosStatTestpvals
    1314             %   - temperature
    1315             %   - pFlipHistory
    1316
    1317             if isempty(obj.histObj)
    1318
    1319                 obj.histObj = sosHistory(obj);
    1320             else
    1321                 verbosePrint('Warning: History already exists so cannot be created',...
    1322                     'sos_createHistory_alreadyCreated');
    1323             end
    1324
    1325         end
    1326
    1327
    1328         %% updateHistory() METHOD
    1329         function updateHistory(obj,curIt,cost,deltaCost,pFlip,temp)
    1330             %updates the contents of the plot
    1331
    1332             % get the information about the p-vals.
    1333             testNames = {};
    1334             testps = [];
    1335
    1336             for i=1:length(obj.sosstattests)
    1337                 testNames = horzcat(testNames,obj.sosstattests{i}.label); %#ok<AGROW>
    1338                 testps = horzcat(testps,obj.sosstattests{i}.lastp); %#ok<AGROW>
    1339             end
    1340
    1341             obj.histObj.updateHistory(curIt,cost,deltaCost,pFlip, ...
    1342                             testNames,testps,temp);
    1343
    1344         end
    1345
    1346         %% function writeHistory(outFile) METHOD
    1347         function writeHistory(obj,outFile)
    1348             %writes all history saved to date to file 'outFile'
    1349
    1350              if exist('outFile','var') == 0
    1351                  error('"Outfile" argument was not supplied to writeHistory()');
    1352              end
    1353
    1354              if(ischar(outFile) == false)
    1355                 error('Outfile has not been set to a string != "null".');
    1356              end
    1357
    1358             if isempty(obj.histObj) == 0
    1359                 obj.histObj.writeHistory(outFile);
    1360             else
    1361                 error('No saved history to write - did you run createHistory() before optimizing?');
    1362             end
    1363         end
    1364
    1365         %% setbufferedHistoryOutfile(outFile) METHOD
    1366         function setBufferedHistoryOutfile(obj,outFile)
    1367             % writes the history on-line, one update at a time, to outfile
    1368             % If outfile exists, it will be overridden.
    1369
    1370             if exist('outFile','var') == 0
    1371                 error('"Outfile" argument was not supplied to writeHistory()');
    1372             end
    1373
    1374             if(ischar(outFile) == false)
    1375                 error('Outfile has not been set to a string != "null".');
    1376             end
    1377
    1378             if ischar(outFile) == false || strcmp(outFile,'null')
    1379                 error('Outfile has not been set to a string != "null".');
    1380             end
    1381
    1382             if isempty(obj.histObj) == 0
    1383                 obj.histObj.setBufferedHistoryOutfile(outFile);
    1384             else
    1385                 error('No saved history to write - did you start recording history with createHistory()?');
    1386             end
    1387         end
    1388
    1389         %% enableBufferedHistoryWrite() METHOD
    1390         function enableBufferedHistoryWrite(obj)
    1391             % enables writing of buffered history.  Enabled automatically
    1392             % when bufferedHistoryWrite is first called; cannot be called
    1393             % until that method has first been called to specify an
    1394             % outfile.  Subsequent enablings continue to write to that
    1395             % file.
    1396
    1397             if isempty(obj.histObj) == 0
    1398                 obj.histObj.enableBufferedHistoryWrite();
    1399             else
    1400                 error('History is not being recorded so buffered writing cannot be enabled - run createHistory() first');
    1401             end
    1402         end
    1403
    1404         %% disableBufferedHistoryWrite() METHOD
    1405         function disableBufferedHistoryWrite(obj)
    1406             % disables writing of buffered history.
    1407
    1408             if isempty(obj.histObj) == 0
    1409                 obj.histObj.disableBufferedHistoryWrite();
    1410             else
    1411                 error('History is not being recorded so buffered writing cannot be disabled - run createHistory() first');
    1412             end
    1413         end
    1414
    1415
    1416         %% writeSamples()  METHOD
    1417         function writeSamples(obj)
    1418            % writes the data from the samples to text files specified in their 'outFile' property
    1419
    1420            verbosePrint('Writing all samples to disk...',...
    1421                             'sos_writeSamples_begin');
    1422
    1423            for i=1:length(obj.samples)
    1424                obj.samples(i).writeData();
    1425            end
    1426         end %writeSamples()
    1427
    1428         %% writePopulations()  METHOD
    1429         function writePopulations(obj)
    1430            % writes the data from the populations to text files specified in their 'outFile' property
    1431
    1432            verbosePrint('Writing all populations to disk...',...
    1433                             'sos_writePopulations_begin');
    1434
    1435            alreadyWritten = {};
    1436            popWritten = 0;
    1437
    1438            for i=1:length(obj.samples)
    1439                if isempty(alreadyWritten)
    1440                    popWritten = 0;
    1441                else
    1442                 for j = 1:length(alreadyWritten)
    1443                     if (alreadyWritten{j} == obj.samples(i).population)
    1444                         popWritten = 1;
    1445                     end
    1446                 end
    1447                end
    1448
    1449                if(popWritten == 0)
    1450                 obj.samples(i).population.writeData();
    1451                 alreadyWritten = [alreadyWritten {obj.samples(i).population}]; %#ok<AGROW>
    1452                end
    1453            end
    1454         end %writeSamples()
    1455
    1456         %% writeAll() METHOD
    1457         function writeAll(obj)
    1458             %write all populations and samples associated with SOS object to disk
    1459             obj.writeSamples();
    1460             obj.writePopulations();
    1461
    1462         end % writeAll()
    1463
    1464         %% addttest(sample1, sample2, s1ColName, s2ColName, type) METHOD
    1465         function addttest(obj, varargin)
    1466                 %adds a t-test to the list of analyses to run
    1467                 newTest = genericStatTest.createStatTest('ttest','sosObj',obj,varargin{:});
    1468                 obj.sosstattests = [obj.sosstattests {newTest}];
    1469
    1470                 % if there is a history object at work, let it know that a
    1471                 % new stat test has been added.
    1472                 if isempty(obj.histObj) == 0
    1473                     obj.histObj.addStatTestName(newTest.name);
    1474                 end
    1475
    1476              verbosePrint('t-test added...',  ...
    1477                     'sos_addttest_end');
    1478         end
    1479
    1480         %% addtzest(sample1, sample2, s1ColName, s2ColName, type, ...) METHOD
    1481         function addztest(obj, varargin)
    1482                 %adds a z-test to the list of analyses to run
    1483
    1484                 % NOTE: If additional, more general types of z-tests are
    1485                 % added, this will need to be conditionalized so that
    1486                 % sosCorrelTest is not chosen by default...
    1487                 newTest = genericStatTest.createStatTest('matchCorrel','sosObj',obj,varargin{:});
    1488                 obj.sosstattests = [obj.sosstattests {newTest}];
    1489
    1490                 % if there is a history object at work, let it know that a
    1491                 % new stat test has been added.
    1492                 if isempty(obj.histObj) == 0
    1493                     obj.histObj.addStatTestName(newTest.name);
    1494                 end
    1495
    1496              verbosePrint('z-test added...',  ...
    1497                     'sos_addztest_end');
    1498         end
    1499
    1500
    1501         %% addtzest(sample1, sample2, s1ColName, s2ColName, type, ...) METHOD
    1502         function addkstest(obj, varargin)
    1503                 %adds a kstest to the list of analyses to run
    1504
    1505                 % NOTE: If additional, more general types of kstests are
    1506                 % added, this will need to be conditionalized so that
    1507                 % sosCorrelTest is not chosen by default...
    1508                 newTest = genericStatTest.createStatTest('matchUniform','sosObj',obj,varargin{:});
    1509                 obj.sosstattests = [obj.sosstattests {newTest}];
    1510
    1511                 % if there is a history object at work, let it know that a
    1512                 % new stat test has been added.
    1513                 if isempty(obj.histObj) == 0
    1514                     obj.histObj.addStatTestName(newTest.name);
    1515                 end
    1516
    1517              verbosePrint('ks-test added...',  ...
    1518                     'sos_addkstest_end');
    1519         end
    1520
    1521
    1522
    1523         function pass = doStatTests(obj,varargin)
    1524             % runs the stat tests and indicates if all passed the user
    1525             % hypotheses.
    1526             %
    1527             %PARAMETERS:
    1528             %   'reportStyle'/'short'|'full' - style of report to be printed.
    1529             %                               Either short or long
    1530             %
    1531             % RETURNS:
    1532             %   NaN if user had no hypotheses about any of the tests that
    1533             %   were run.  1 if there were hypotheses and all hypotheses
    1534             %   passed their tests.  0  otherwise.
    1535
    1536            p = inputParser;
    1537            p.addParamValue('reportStyle','short', ...
    1538                     @(reportStyle)any([strcmp(reportStyle,'short') ...
    1539                                     strcmp(reportStyle,'full') ...
    1540                                     strcmp(reportStyle,'none')]));
    1541            p.parse(varargin{:});
    1542
    1543            if strcmp(p.Results.reportStyle,'none') == 0
    1544                 verbosePrint([char(10),'Running all stat tests:'],...
    1545                             'sos_doStatTests_begin');
    1546            end
    1547             pass = NaN;
    1548
    1549             %
    1550
    1551
    1552             for i=1:length(obj.sosstattests)
    1553                 userHypothesis = obj.sosstattests{i}.runTest(varargin{:});
    1554
    1555                 if userHypothesis == 0
    1556                     pass = 0;
    1557                 % if a hypothesis passes (as opposed to being NaN), set the
    1558                 % condition to pass;  If a hypothesis has already failed,
    1559                 % it cannot pass
    1560                 elseif userHypothesis == 1 && isnan(pass)
    1561                     pass = 1;
    1562                 end
    1563             end
    1564         end % doStatTests
    1565
    1566         %% function deltaCostPercentiles() METHOD
    1567         function deltaCostPercentiles(obj)
    1568             % displays the breakdown of deltaCost values per decile and
    1569             % other important percentiles
    1570
    1571             %one over 100 so that we get the 100th decile
    1572             deciles = 0:10:101;
    1573             scores = prctile(obj.deltaCostLog, deciles);
    1574
    1575             %let the user know how many observations entered into the delta
    1576             %cost report
    1577             verbosePrint(['Deciles for deltaCost in last block:',char(10), ...
    1578                 '(',num2str(min(length(obj.deltaCostLog),obj.curIt)),...
    1579                 ' iterations total; numIt < blockSize in first block)',char(10)], ...
    1580                         'sos_deltaCostPercentiles_Header');
    1581
    1582
    1583            values = '';
    1584            for i=1:length(deciles)
    1585                line=sprintf('\t%1.0f:  \t %+10.8f \n',deciles(i),scores(i));
    1586                values = [values line]; %#ok<AGROW>
    1587            end
    1588
    1589            verbosePrint(values, 'sos_deltaCostPercentiles_Scores');
    1590
    1591
    1592            %print out information that could be helpful for configuring the
    1593            %expAnneal function
    1594
    1595            percentiles = [2.5 97.5];
    1596            scores = prctile(obj.deltaCostLog, percentiles);
    1597
    1598            deltaCost95 = scores(2) - scores(1);
    1599
    1600            msg = sprintf('\n\n 97.5th - 2.5th percentile deltaCost: %10.8f\n\n', ...
    1601                         deltaCost95);
    1602
    1603            verbosePrint(msg, 'sos_deltaCostPercentiles_deltaCost95');
    1604
    1605
    1606         end
    1607
    1608     end %end methods
    1609
    1610     methods (Static)
    1611
    1612         %% p = sosInputParser() STATIC METHOD
    1613         function p = sosInputParser()
    1614             % returns an input parser for the sos constructor args
    1615             %
    1616             %CALL:
    1617             % p = sos.sosInputParser()
    1618             %
    1619             %SYNOPSIS:
    1620             % returns an input parser for the sos constructor args
    1621             %
    1622             %PARAMETERS:
    1623             %   Same as object constructor
    1624             %
    1625             %EXAMPLE:
    1626             % p = sos.sosInputParser()
    1627             %
    1628
    1629              p = inputParser;
    1630
    1631              %use NaN as null, since matlab doesn't support standard
    1632              %NULL
    1633
    1634              p.addParamValue('maxIt',  sos.maxIt_def, ...
    1635                 @(maxIt)validateattributes(maxIt, {'numeric'}, ...
    1636                 {'scalar', 'integer', 'positive', '>', 0}));
    1637             p.addParamValue('pSwapFunction',sos.pSwapFunction_def, ...
    1638                 @(pSwapFunction)ischar(pSwapFunction));
    1639             p.addParamValue('targSampleCandSelectMethod',sos.targSampleCandSelectMethod_def, ...
    1640                 @(targSampleCandSelectMethod)ischar(targSampleCandSelectMethod));
    1641             p.addParamValue('feederdfCandSelectMethod',sos.feederdfCandSelectMethod_def, ...
    1642                 @(feederdfCandSelectMethod)ischar(feederdfCandSelectMethod));
    1643             p.addParamValue('reportInterval',sos.reportInterval_def, ...
    1644                 @(reportInterval)validateattributes(reportInterval, {'numeric'}, ...
    1645                 {'scalar', 'integer', 'positive', '>', 0}));
    1646             p.addParamValue('stopFreezeIt',sos.stopFreezeIt_def, ...
    1647                 @(stopFreezeIt)validateattributes(stopFreezeIt, {'numeric'}, ...
    1648                 {'scalar', 'integer', 'positive', '>', 0}));
    1649             p.addParamValue('statInterval',sos.statInterval_def, ...
    1650                 @(statInterval)validateattributes(statInterval, {'numeric'}, ...
    1651                 {'scalar', 'integer', 'positive', '>', 0}));
    1652             p.addParamValue('statTestReportStyle',sos.statTestReportStyle_def, ...
    1653                 @(statTestReportStyle)any( ...
    1654                     [strcmp(statTestReportStyle,'short'), ...
    1655                      strcmp(statTestReportStyle,'full')]));
    1656             p.addParamValue('blockSize',sos.blockSize_def, ...
    1657                 @(statInterval)validateattributes(statInterval, {'numeric'}, ...
    1658                 {'scalar', 'integer', 'positive', '>', 0}));
    1659
    1660
    1661         end
    1662     end
    1663
    1664     methods (Static, Access = private)
    1665         %% parseConstructorArgs PRIVATE STATIC METHOD
    1666         function p = parseConstructorArgs(varargin)
    1667             %parses the constructor arguments
    1668             %
    1669             % CALL:
    1670             % p = sos.parseConstructorArgs(varargin);
    1671             %
    1672             %parses the arguments from the  constructor.  Default
    1673             %values are substituted where appropriate.  Returns a struct
    1674             %with the parsed args
    1675             %
    1676             %PARAMETERS:
    1677             % SAME as sos CONSTRUCTOR
    1678             %
    1679             %RETURNS:
    1680             %    p - parsed constructor input
    1681
    1682              varargin = varargin{1};
    1683
    1684              p = sos.sosInputParser();
    1685              p.parse(varargin{:});
    1686
    1687              if any(strcmp(p.UsingDefaults,'maxIt'))
    1688                  verbosePrint(['    Defaulting to ',  ...
    1689                      num2str(p.Results.maxIt), ' maximum iterations'], ...
    1690                     'sos_parseConstructor_defaultMaxIt');
    1691              end
    1692
    1693              if any(strcmp(p.UsingDefaults,'pSwapFunction'))
    1694                  verbosePrint(['    Defaulting to ', ...
    1695                      (p.Results.pSwapFunction), ' pSwapFunction'], ...
    1696                     'sos_parseConstructor_pSwapFunction');
    1697              end
    1698
    1699              if any(strcmp(p.UsingDefaults,'targSampleCandSelectMethod'))
    1700                  verbosePrint(['    Defaulting to ', ...
    1701                      (p.Results.targSampleCandSelectMethod), ...
    1702                      ' targSample Candidate Selection Method'], ...
    1703                     'sos_parseConstructor_targSampleCandSelectMethod');
    1704              end
    1705
    1706              if any(strcmp(p.UsingDefaults,'feederdfCandSelectMethod'))
    1707                  verbosePrint(['    Defaulting to ', ...
    1708                      (p.Results.feederdfCandSelectMethod), ...
    1709                      ' feederdf Candidate Selection Method'], ...
    1710                     'sos_parseConstructor_feederdfCandSelectMethod');
    1711              end
    1712
    1713              if any(strcmp(p.UsingDefaults,'reportInterval'))
    1714                  verbosePrint(['    Defaulting to ', ...
    1715                      num2str(p.Results.reportInterval), ...
    1716                      ' iterations between reports'], ...
    1717                     'sos_parseConstructor_reportInterval');
    1718              end
    1719
    1720              if any(strcmp(p.UsingDefaults,'stopFreezeIt'))
    1721                  verbosePrint(['    Defaulting to ', ...
    1722                      num2str(p.Results.stopFreezeIt), ...
    1723                      ' of same frozen cost before stopping'], ...
    1724                     'sos_parseConstructor_stopFreezeIt');
    1725              end
    1726
    1727
    1728              if any(strcmp(p.UsingDefaults,'statInterval'))
    1729                  verbosePrint(['    Defaulting to ', ...
    1730                      num2str(p.Results.statInterval), ...
    1731                      ' intervals between stat reports'], ...
    1732                     'sos_parseConstructor_statReports');
    1733              end
    1734
    1735              if any(strcmp(p.UsingDefaults,'statTestReportStyle'))
    1736                  verbosePrint(['    Defaulting to ', ...
    1737                      p.Results.statTestReportStyle, ...
    1738                      ' style stat reports'], ...
    1739                     'sos_parseConstructor_statReports');
    1740              end
    1741
    1742         end % parseConstructorArgs
    1743     end
    1744
    1745 end