- hard bound constraint 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.
0001 % - hard bound constraint object 0002 % 0003 % copyright 2009-2012 Blair Armstrong, Christine Watson, David Plaut 0004 % 0005 % This file is part of SOS 0006 % 0007 % SOS is free software: you can redistribute it and/or modify 0008 % it for academic and non-commercial purposes 0009 % under the terms of the GNU General Public License as published by 0010 % the Free Software Foundation, either version 3 of the License, or 0011 % (at your option) any later version. For commercial or for-profit 0012 % uses, please contact the authors (sos@cnbc.cmu.edu). 0013 % 0014 % SOS is distributed in the hope that it will be useful, 0015 % but WITHOUT ANY WARRANTY; without even the implied warranty of 0016 % MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 0017 % GNU General Public License for more details. 0018 0019 % You should have received a copy of the GNU General Public License 0020 % along with SOS (see COPYING.txt). 0021 % If not, see <http://www.gnu.org/licenses/>. 0022 0023 0024 0025 classdef hardBoundConstraint < hardConstraint 0026 %% creates and supports hardBoundConstraints 0027 % 0028 % Creates constraint objects that measure the number of items which 0029 % violate a specified hard bound in a sample, and which evaluates 0030 % whether a new item which could be swapped into a sample would also 0031 % violate this same hards bound. 0032 % 0033 % Additional functionality and interface requirements are inherited 0034 % from hardConstraint 0035 % 0036 % PROPERTIES 0037 % comparison - handle to specific comparison method to use 0038 % bound - the bound to evaluate an item against 0039 % s1 - the sample 0040 % s1Col - the column in the sample 0041 % s1ColName - the name of the data stored in the column of the sample 0042 % 0043 % METHODS: 0044 % hardBoundConstraint(varargin) - CONSTRUCTOR 0045 % cost = initCost(obj) Calculates, saves, and returns the cost value for the current items in the sample. 0046 % swCost = swapCost(obj, targSample, targSampleIndex, feederdf, feederdfIndex) Calculates the new cost if items from targSample and feederdf were swapped. 0047 % cost = itemCost(obj, targSample,targSampleIndex,feederdf, feederdfIndex) Calculates the cost of the specified item in df. 0048 % cost = itemCostFilling(obj, targSample,targSampleIndex,feederdf, feederdfIndex) Calculates the cost of the specified item in df to the sample. 0049 % 0050 % METHODS (Static) 0051 % p = hardBoundConstraintInputParser() - generates input parser for constructor args 0052 % 0053 % METHODS (Static, Access = private) 0054 % p = parseConstructorArgs(varargin) - parses the construcvtor args 0055 0056 0057 %% PROPERTIES 0058 properties 0059 comparison % handle to specific comparison method to use 0060 bound % the bound to evaluate an item against 0061 s1 % the sample 0062 s1Col % the column in the sample 0063 s1ColName % the name of the data stored in the column of the sample 0064 end 0065 0066 methods 0067 0068 %% hardBoundConstraint CONSTRUCTOR 0069 function obj = hardBoundConstraint(varargin) 0070 % CONSTRUCTOR - creates a hardBoundConstraint object 0071 % 0072 % CALL: 0073 % hardBoundConstraint(varargin <defined below> ) 0074 % 0075 %PARAMETERS: 0076 % 0077 % 'sosObj'/sos object - the SOS object the constraint will be linked to, and which contains the samples the constraint operates on. 0078 % 'constraintType'/'hard' - the type of contraint - must be 'hard' 0079 % 'fnc'/'floor'|'ceiling' the type of bound to create 0080 % 'sample1'/sample - the sample to apply the constraint to 0081 % 's1ColName'/string - name of column in 1st sample 0082 % 'value'/numeric - value of the bound 0083 % 0084 % EXAMPLE: 0085 % mySOS.addConstraint('constraintType','hard','fnc','ceiling','sample1',s1,'s1ColName','Lg10WF','value',1.5); 0086 0087 p = hardBoundConstraint.parseConstructorArgs(varargin); 0088 0089 0090 %now check additional characteristics of the input parameters. 0091 0092 if(p.Results.sosObj.containsSample(p.Results.sample1) == false) 0093 error('Cannot create hard bound constraint: sos Object does not contain the sample1'); 0094 end 0095 0096 col = p.Results.sample1.colName2colNum(p.Results.s1ColName); 0097 0098 if(col == -1) 0099 error('Specified column name not found in sample1'); 0100 end 0101 0102 if(strcmp(p.Results.sample1.format{col},'%f') == 0) 0103 error('Specified column is not of numeric (%f) format, so cannot use as hard bound'); 0104 end 0105 0106 % properties meet requirements, assign properties to new obj 0107 0108 %give a handle to either hte less than or greater than function 0109 if (strcmp(p.Results.fnc,'floor')) 0110 comp = @ge; 0111 elseif (strcmp(p.Results.fnc,'ceiling')) 0112 comp = @le; 0113 else 0114 error('Specified bound function not suported'); 0115 end 0116 0117 %parent property 0118 obj.sosObj = p.Results.sosObj; 0119 obj.constraintType = p.Results.constraintType; 0120 obj.fnc = p.Results.fnc; 0121 0122 obj.comparison = comp; 0123 obj.bound = p.Results.value; 0124 obj.s1 = p.Results.sample1; 0125 obj.s1Col = col; 0126 obj.s1ColName = p.Results.s1ColName; 0127 0128 0129 obj.cost = NaN; 0130 obj.swCost = NaN; 0131 0132 % add the name and the label 0133 obj.label = [obj.constraintType,'_',obj.fnc,'_',... 0134 obj.s1.name,'_',obj.s1ColName,'_',num2str(obj.bound)]; 0135 if any(strcmp(p.UsingDefaults,'name')) 0136 obj.name = obj.label; 0137 else 0138 obj.name = p.Results.name; 0139 end 0140 0141 0142 verbosePrint('Hard Bound Constraint has been created', ... 0143 'hardBoundConstraint_Constructor_endObjCreation'); 0144 0145 end %constructor 0146 0147 %% cost = initCost() METHOD 0148 function cost = initCost(obj) 0149 % Calculates, saves, and returns the cost value for the current items in the sample. 0150 % 0151 %CALL: 0152 % <hardBoundConstraint>.initCost(); 0153 % 0154 % Calculates the cost of the hard bound for each item in the 0155 % sample. As hard bounds should generally not be violated, a 0156 % warning message will also be displayed if items violating 0157 % a bound are present in the set. This should indicate that 0158 % the user has forced items into the sample (e.g., by putting 0159 % them in a file listing items to be read into the sample 0160 % object when it is created). It should not be displayed 0161 % otherwise if SOS is operating as inteded. 0162 0163 cost = 0; 0164 for i=1:length(obj.s1.data{obj.s1Col}) 0165 if(obj.comparison(obj.s1.data{obj.s1Col}(i),obj.bound) == 0) 0166 0167 %bca: may want to make this print statement more useful... 0168 verbosePrint(['Warning: Item ', num2str(i), ' violated the hard bound constraint!'], ... 0169 'hardBoundConstraint_initCost'); 0170 cost = cost + 1; 0171 end 0172 end 0173 0174 obj.cost=cost; 0175 obj.swCost = NaN; 0176 end 0177 0178 0179 %% swCost(targSample,targSampleIndex, feederdf,feederdfIndex) FUNCTION 0180 function swCost = swapCost(obj, targSample, targSampleIndex, feederdf, feederdfIndex) 0181 % Calculates the new cost if items from targSample and feederdf were swapped. 0182 % 0183 %By definition, if this method is called it means that at least 0184 % one of the two swap objects is implicated in this function 0185 % 0186 %PARAMETERS: 0187 % targSample - the target sample (i.e., the object that will call it's swapSample() method if a swap later occurs). 0188 % targSampleIndex - row index of item to swap 0189 % feederdf - dataframe (sample/pop) containin the other item to swap 0190 % feederdfIndex - row index of item to swap. 0191 0192 curItemCost = obj.itemCost('null','null',targSample, targSampleIndex); 0193 newItemCost = obj.itemCost('null','null',feederdf, feederdfIndex); 0194 0195 0196 %can swap to another item that violates the constraint if you 0197 %currently violate the constraint 0198 if curItemCost == 1 && newItemCost == 1 0199 newSubCost = 0; 0200 elseif curItemCost == 0 && newItemCost == 1 0201 newSubCost = 1; 0202 %must swap if current item violates constraint and new one 0203 %doesn't 0204 elseif curItemCost == 1 && newItemCost == 0 0205 newSubCost = -1; 0206 elseif curItemCost == 0 && newItemCost == 0 0207 newSubCost = 0; 0208 else 0209 error('This condition should not have been met'); 0210 end 0211 0212 swCost = obj.cost + newSubCost; 0213 obj.swCost = swCost; 0214 0215 end 0216 0217 %% itemCost(targSample,targSampleIndex,feederdf, feederdfIndex) METHOD 0218 function cost = itemCost(obj, targSample,targSampleIndex,feederdf, feederdfIndex) 0219 %Calculates the cost of the specified item in df. 0220 %Should usually be invoked once a sample is filled with items. 0221 % 0222 %NOTE: 0223 % Other parameters are provided only for consistency, but are not 0224 % used. 0225 % 0226 %SEE swCost() doc/help for more details 0227 0228 cost = obj.itemCostFilling(targSample,targSampleIndex,feederdf, feederdfIndex); 0229 end 0230 0231 %% cost = itemCostFilling(targSample,targSampleIndex,feederdf, feederdfIndex) METHOD 0232 function cost = itemCostFilling(obj, targSample,targSampleIndex,feederdf, feederdfIndex) %#ok<INUSL> 0233 %Calculates the cost of the specified item in df to the sample. 0234 % Should usually only be invoked when initially filling a 0235 % sample 0236 % 0237 %NOTE: 0238 % Other parameters are provided only for consistency, but are not 0239 % used. 0240 % 0241 %SEE swCost() doc/help for more details 0242 0243 cost = 0; 0244 0245 if(obj.comparison(feederdf.data{obj.s1Col}(feederdfIndex),obj.bound)) 0246 %do nothing 0247 else 0248 cost = 1; 0249 end 0250 end 0251 0252 function cost = acceptSwap(obj) 0253 acceptSwap@genericConstraint(obj); 0254 cost = obj.cost; 0255 end 0256 0257 end 0258 0259 methods(Static) 0260 %% p = hardBoundConstraintInputParser() STATIC METHOD 0261 function p = hardBoundConstraintInputParser() 0262 % generates input parser for constructor args 0263 p = inputParser; 0264 0265 %Note: some of these 'optional' parameters are de facto 0266 %required by making the default value fail validation 0267 p.addParamValue('sosObj','null', ... 0268 @(sosObj)strcmp(class(sosObj),'sos')); 0269 p.addParamValue('constraintType', 'null', ... 0270 @(constraintType)any(strcmp({'hard'},constraintType))); 0271 p.addParamValue('fnc','null', ... 0272 @(fnc)any(strcmp({'floor' 'ceiling'},fnc))); 0273 p.addParamValue('sample1','null', ... 0274 @(sample1)strcmp(class(sample1),'sample')); 0275 p.addParamValue('s1ColName','',@(s1ColName)ischar(s1ColName)); 0276 p.addParamValue('value','null',@(value)isnumeric(value)); 0277 p.addParamValue('name','noname',@(name)ischar(name)); 0278 0279 end % hardBoundConstraintInputParser() 0280 end 0281 0282 methods(Static, Access = private) 0283 0284 %% parseConstructorArgs STATIC PRIVATE FUNCTION 0285 function p = parseConstructorArgs(varargin) 0286 % parses the construcvtor args 0287 % 0288 % see construcor help/doc for more info 0289 0290 varargin = varargin{1}; 0291 p = hardBoundConstraint.hardBoundConstraintInputParser(); 0292 p.parse(varargin{:}); 0293 end 0294 end 0295 0296 end 0297