0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023 classdef sos < genericStatTest
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037
0038
0039
0040
0041
0042
0043
0044
0045
0046
0047
0048
0049
0050
0051
0052
0053
0054
0055
0056
0057
0058
0059
0060
0061
0062
0063
0064
0065
0066
0067
0068
0069
0070
0071
0072
0073
0074
0075
0076
0077
0078
0079
0080
0081
0082
0083
0084
0085
0086
0087
0088
0089
0090
0091
0092
0093
0094
0095
0096
0097
0098
0099 properties
0100 samples
0101 hardConstraints
0102 softConstraints
0103 metaConstraints
0104 cost
0105 sCandObj
0106 feederCandObj
0107 pSwapObj
0108 annealObj
0109 maxIt
0110 allData
0111 allDataColName
0112 allDataColMean
0113 allDataColStd
0114 reportInterval
0115 curIt
0116 curFreezeIt
0117 stopFreezeIt
0118 sosstattests
0119 statInterval
0120 statTestReportStyle
0121 deltaCost
0122 blockSize
0123 nFlip
0124 deltaCostLog
0125 oldNumIt
0126 plotObj
0127 histObj
0128 targSampleCandSelectMethod
0129 feederdfCandSelectMethod
0130 queryStopOptimize
0131 end
0132
0133
0134 properties (Constant)
0135 maxIt_def = 10000;
0136 pSwapFunction_def = 'logistic';
0137 targSampleCandSelectMethod_def = 'random';
0138 feederdfCandSelectMethod_def = 'randomPopulationAndSample';
0139 reportInterval_def = 1000;
0140 stopFreezeIt_def = 10000;
0141 statInterval_def = 10000;
0142 statTestReportStyle_def = 'short';
0143 blockSize_def = 1000;
0144 queryStopOptimize_def = 100;
0145 end
0146
0147 methods
0148
0149
0150 function obj = sos(varargin)
0151
0152
0153
0154
0155
0156
0157
0158
0159
0160
0161
0162
0163
0164
0165
0166
0167
0168 verbosePrint([char(10) 'Creating sos Object'], ...
0169 'sos_constructor_startObjCreation');
0170
0171 p = sos.parseConstructorArgs(varargin);
0172
0173
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
0206 obj.setAnnealSchedule();
0207
0208 verbosePrint(['Creation of sos object complete' char(10)], ...
0209 'sos_constructor_endObjCreation');
0210 end
0211
0212
0213
0214 function obj = addSample(obj, sample)
0215
0216
0217
0218
0219
0220
0221
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
0246
0247
0248
0249 function present = containsSample(obj, sample)
0250
0251
0252
0253
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
0264
0265
0266
0267 function constraint = addConstraint(obj, varargin)
0268
0269
0270
0271
0272
0273
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
0290 function present = containsConstraint(obj, constraint)
0291
0292
0293
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
0321 function obj = initFillSamples(obj)
0322
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
0332
0333 totalAdd = [];
0334 for i=1:length(obj.samples)
0335
0336
0337
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];
0349
0350 end
0351
0352
0353
0354
0355 while(isempty(totalAdd) ==0)
0356
0357 toAddIndex=floor((length(totalAdd)*rand)+1);
0358 sIndex= totalAdd(toAddIndex);
0359
0360
0361
0362
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
0384
0385 validItem = obj.checkHardConstraintsFilling( ...
0386 obj.samples(sIndex),sItemIndex, ...
0387 obj.samples(sIndex).population,pItemIndex);
0388
0389 if(validItem == 1)
0390
0391
0392 totalAdd(toAddIndex)=[];
0393 pItem = obj.samples(sIndex).population.popItem(pItemIndex);
0394 obj.samples(sIndex).appendItem(pItem);
0395 end
0396 end
0397 end
0398
0399
0400
0401 function validItem = checkHardConstraintsFilling(obj,sample,sItemIndex,newItemDataFrame,newItemIndex)
0402
0403
0404
0405
0406
0407
0408
0409
0410
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
0424
0425
0426
0427 function swCost = checkHardConstraintsSwapping(obj,sample,sItemIndex,newItemDataFrame,newItemIndex)
0428
0429
0430
0431
0432
0433
0434
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
0456 function swCost = checkSoftConstraintsSwapping(obj,targSample,targSampleIndex,feederdf, feederdfIndex)
0457
0458
0459
0460
0461
0462
0463
0464
0465
0466
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
0485 function swCost = checkMetaConstraintsSwapping(obj,~,~,~,~)
0486
0487
0488
0489
0490
0491
0492
0493
0494
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
0505 function [colName,colMean,colStd,allData] = normalizeData(obj)
0506
0507
0508 verbosePrint('Normalizing Population and Sample Data', ...
0509 'sos_normalizeData_start');
0510
0511
0512 allData = dataFrame();
0513
0514 alreadyMerged = {};
0515
0516
0517 for i=1:length(obj.samples)
0518
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
0532 if(popPresent == 0)
0533
0534
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}];
0539 end
0540 end
0541
0542
0543 allData = dataFrame.aContainsb(allData,obj.samples(i));
0544 allData = dataFrame.aContainsbData(allData,obj.samples(i));
0545
0546
0547
0548
0549 alreadyMerged = [alreadyMerged {obj.samples(i)}];
0550
0551
0552 end
0553
0554
0555
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
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
0573
0574
0575 for i=1:length(alreadyMerged)
0576
0577 alreadyMerged{i}.sosObj = obj;
0578 alreadyMerged{i}.zdata = {};
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
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
0596 if(isnan(m) || isnan(std))
0597 error('Normalization failed because either the mean or stdeviation was NaN');
0598 end
0599
0600
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;
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
0624
0625
0626
0627 function cost = initCost(obj)
0628
0629
0630 verbosePrint([char(10),'Initializing Constraints',char(10)],...
0631 'sos_initCost_startInit');
0632
0633
0634
0635
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
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
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
0722 function cost = dispCost(obj)
0723
0724
0725 verbosePrint([char(10),'Displaying Constraint Costs',char(10)],...
0726 'sos_dispCost_start');
0727
0728
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
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
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
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
0790
0791
0792 function setAnnealSchedule(obj,varargin)
0793
0794
0795
0796
0797
0798
0799
0800
0801
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
0810
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
0835 function setSampleCandidateSelectionMethod(obj,methodName)
0836
0837
0838
0839
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
0854 function setFeederdfCandidateSelectionMethod(obj,methodName)
0855
0856
0857
0858
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
0877 function setpSwapFunction(obj,swFunctionName)
0878
0879
0880
0881
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
0893
0894
0895
0896 function goodEnding = optimize(obj,varargin)
0897
0898
0899
0900
0901
0902
0903
0904
0905
0906
0907
0908
0909
0910
0911
0912
0913
0914
0915
0916
0917
0918
0919 verbosePrint(['Setting up optimization procedure...', ...
0920 char(10)], 'sos_optimize_begin');
0921
0922
0923
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
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
0942 isGui = 0;
0943 else
0944 isGui = p.Results.isGui;
0945
0946 if isGui == 1
0947 mainWindowHandle = sos_gui;
0948 mainWindowData = guidata(mainWindowHandle);
0949 set(mainWindowData.pushbutton_stopOptimize,'UserData',0)
0950 elseif isGui == 0
0951
0952 else
0953 error('isGui should be a flag with value 1 or 0).');
0954 end
0955 end
0956
0957
0958
0959
0960 stopOptimize = 0;
0961
0962 goodEnding = 0;
0963
0964
0965
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
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
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
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
1045 [targSample,targSampleIndex] = obj.sCandObj.getCandidateIndex();
1046 [feederdf, feederdfIndex] = obj.feederCandObj.getCandidateIndex(targSample);
1047
1048
1049
1050
1051
1052 sumHardswCost = obj.checkHardConstraintsSwapping(...
1053 targSample,targSampleIndex,feederdf, feederdfIndex);
1054
1055
1056
1057
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
1069
1070
1071
1072 deltaCost = -1*(curCost - swCost);
1073
1074
1075
1076
1077 if sumHardswCost == 0
1078 shouldSwap = obj.pSwapObj.shouldSwap(...
1079 deltaCost,obj.annealObj.getTemp());
1080
1081 obj.deltaCost = deltaCost;
1082
1083
1084
1085 else
1086 shouldSwap = 1;
1087
1088 end
1089
1090 if shouldSwap == 1
1091
1092 obj.nFlip = obj.nFlip + 1;
1093
1094
1095
1096 targSample.swapItems(...
1097 targSampleIndex,feederdf, feederdfIndex,obj);
1098
1099
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
1113 if sumHardswCost < 0
1114 obj.curFreezeIt = 0;
1115 elseif obj.cost ~= swCost
1116 obj.curFreezeIt = 0;
1117 else
1118 obj.curFreezeIt = obj.curFreezeIt +1;
1119 end
1120
1121 obj.cost = swCost;
1122 else
1123
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
1147
1148
1149
1150
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
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
1164 if isGui
1165
1166
1167
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
1178
1179
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
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
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;
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
1231 function doReport(obj,tStart,startIt)
1232
1233
1234
1235
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
1262 function createPlots(obj,dispIt)
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
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
1299 function updatePlots(obj)
1300
1301
1302 obj.plotObj.updatePlots();
1303
1304 end
1305
1306
1307
1308 function createHistory(obj)
1309
1310
1311
1312
1313
1314
1315
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
1329 function updateHistory(obj,curIt,cost,deltaCost,pFlip,temp)
1330
1331
1332
1333 testNames = {};
1334 testps = [];
1335
1336 for i=1:length(obj.sosstattests)
1337 testNames = horzcat(testNames,obj.sosstattests{i}.label);
1338 testps = horzcat(testps,obj.sosstattests{i}.lastp);
1339 end
1340
1341 obj.histObj.updateHistory(curIt,cost,deltaCost,pFlip, ...
1342 testNames,testps,temp);
1343
1344 end
1345
1346
1347 function writeHistory(obj,outFile)
1348
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
1366 function setBufferedHistoryOutfile(obj,outFile)
1367
1368
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
1390 function enableBufferedHistoryWrite(obj)
1391
1392
1393
1394
1395
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
1405 function disableBufferedHistoryWrite(obj)
1406
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
1417 function writeSamples(obj)
1418
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
1427
1428
1429 function writePopulations(obj)
1430
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}];
1452 end
1453 end
1454 end
1455
1456
1457 function writeAll(obj)
1458
1459 obj.writeSamples();
1460 obj.writePopulations();
1461
1462 end
1463
1464
1465 function addttest(obj, varargin)
1466
1467 newTest = genericStatTest.createStatTest('ttest','sosObj',obj,varargin{:});
1468 obj.sosstattests = [obj.sosstattests {newTest}];
1469
1470
1471
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
1481 function addztest(obj, varargin)
1482
1483
1484
1485
1486
1487 newTest = genericStatTest.createStatTest('matchCorrel','sosObj',obj,varargin{:});
1488 obj.sosstattests = [obj.sosstattests {newTest}];
1489
1490
1491
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
1502 function addkstest(obj, varargin)
1503
1504
1505
1506
1507
1508 newTest = genericStatTest.createStatTest('matchUniform','sosObj',obj,varargin{:});
1509 obj.sosstattests = [obj.sosstattests {newTest}];
1510
1511
1512
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
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
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
1558
1559
1560 elseif userHypothesis == 1 && isnan(pass)
1561 pass = 1;
1562 end
1563 end
1564 end
1565
1566
1567 function deltaCostPercentiles(obj)
1568
1569
1570
1571
1572 deciles = 0:10:101;
1573 scores = prctile(obj.deltaCostLog, deciles);
1574
1575
1576
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];
1587 end
1588
1589 verbosePrint(values, 'sos_deltaCostPercentiles_Scores');
1590
1591
1592
1593
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
1609
1610 methods (Static)
1611
1612
1613 function p = sosInputParser()
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629 p = inputParser;
1630
1631
1632
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
1666 function p = parseConstructorArgs(varargin)
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
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
1743 end
1744
1745 end