Mercurial > hg > ltpda
comparison m-toolbox/classes/@plist/eq.m @ 0:f0afece42f48
Import.
author | Daniele Nicolodi <nicolodi@science.unitn.it> |
---|---|
date | Wed, 23 Nov 2011 19:22:13 +0100 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:f0afece42f48 |
---|---|
1 % EQ overloads the == operator for ltpda plist objects. | |
2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | |
3 % | |
4 % DESCRIPTION: EQ overloads the == operator for ltpda plist objects. | |
5 % | |
6 % Two plists are considered equal if each has the same name, | |
7 % created time, version, creator and parameter objects. The | |
8 % order of the param-objects doesn't matter. | |
9 % | |
10 % CALL: result = eq(u1,u2) | |
11 % | |
12 % With a PLIST | |
13 % | |
14 % r = eq(obj1, obj2, plist('Exceptions', {'prop1', 'prop2'})) | |
15 % r = eq(obj1, obj2, plist('Tol', eps(1))) | |
16 % r = eq(obj1, obj2, plist('Exceptions', 'prop', 'Tol', 1e-14)) | |
17 % | |
18 % INPUTS: pl1, pl2 - Input objects | |
19 % | |
20 % OUTPUTS: If the two objects are considered equal, result == true, | |
21 % otherwise, result == false. | |
22 % | |
23 % <a href="matlab:utils.helper.displayMethodInfo('plist', 'eq')">Parameters Description</a> | |
24 % | |
25 % VERSION: $Id: eq.m,v 1.27 2011/04/08 08:56:21 hewitson Exp $ | |
26 % | |
27 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | |
28 | |
29 function result = eq(obj1, obj2, varargin) | |
30 | |
31 % Check if this is a call for parameters | |
32 hh = [{obj1}, {obj2}, varargin]; | |
33 if utils.helper.isinfocall(hh{:}) | |
34 result = getInfo(varargin{1}); | |
35 return | |
36 end | |
37 | |
38 import utils.const.* | |
39 | |
40 %%%%% Check class | |
41 if ~strcmp(class(obj1), class(obj2)) | |
42 utils.helper.msg(msg.PROC1, 'NOT EQUAL: The objects are not from the same class. [%s] <-> [%s]', class(obj1), class(obj2)); | |
43 result = false; | |
44 return | |
45 end | |
46 | |
47 %%%%% Check length of obj1 and obj2 | |
48 if numel(obj1) ~= numel(obj2) | |
49 utils.helper.msg(msg.PROC1, 'NOT EQUAL: The size of the %s-object''s. [%d] <-> [%d]', class(obj1), numel(obj1), numel(obj2)); | |
50 result = false; | |
51 return | |
52 end | |
53 | |
54 plin = []; | |
55 exception_list = varargin; | |
56 if ~isempty(varargin) && isa(varargin{1}, 'plist') | |
57 plin = varargin{1}; | |
58 end | |
59 | |
60 %%%%% Get the tolerance from a potential existing plist | |
61 if ~isempty(plin) && plin.isparam('tol') | |
62 tol = plin.find('tol'); | |
63 else | |
64 dpl = getDefaultPlist(); | |
65 tol = dpl.find('tol'); | |
66 end | |
67 | |
68 %%%%% Convert a potential existing plist into a exception | |
69 if ~isempty(plin) && plin.isparam('exceptions') | |
70 exception_list = find(plin, 'Exceptions'); | |
71 if isempty(exception_list) | |
72 exception_list = cell(0); | |
73 elseif ~iscell(exception_list) | |
74 exception_list = cellstr(exception_list); | |
75 end | |
76 end | |
77 | |
78 result = true; | |
79 | |
80 %%%%% for each element in obj1 and obj2 | |
81 for jj = 1:numel(obj1) | |
82 | |
83 if isa(obj1, 'ltpda_uoh') | |
84 utils.helper.msg(msg.PROC1, 'testing %s against %s', obj1.name, obj2.name); | |
85 end | |
86 | |
87 fields = fieldnames(obj1(jj)); | |
88 | |
89 for ii = 1:length(fields) | |
90 field = fields{ii}; | |
91 | |
92 %%%%% Creates the exception list for the current field. | |
93 %%%%% For example: {'name', 'ao/name'} | |
94 ck_field = {field, sprintf('%s/%s', class(obj1), field)}; | |
95 | |
96 % Special case (for the ao- and history-class): | |
97 % Is the field = 'hist', 'inhists' then add 'history' to the exception list. | |
98 %%%%% For example: {'history', 'ao/history'} | |
99 if utils.helper.ismember(field, {'hist', 'inhists'}) | |
100 ck_field{end+1} = 'history'; | |
101 ck_field{end+1} = sprintf('%s/history', class(obj1)); | |
102 elseif strcmp(field, 'val') | |
103 ck_field{end+1} = 'value'; | |
104 ck_field{end+1} = sprintf('%s/value', class(obj1)); | |
105 end | |
106 | |
107 %%%%% Check field if it is not in the exception list | |
108 if ~(any(utils.helper.ismember(ck_field, exception_list))) | |
109 | |
110 if isa(obj1(jj).(field), 'sym') | |
111 %%%%%%%%%% The property is a sym-object %%%%%%%%%% | |
112 if ~eq(obj1(jj).(field), obj2(jj).(field)) | |
113 result = false; | |
114 disaply_msg(obj1, jj, field) | |
115 return | |
116 end | |
117 | |
118 elseif isa(obj1(jj).(field), 'ltpda_obj') | |
119 %%%%%%%%%% The property is a ltpda-object %%%%%%%%%% | |
120 | |
121 %%%%% Check the length of the property | |
122 if length(obj1(jj).(field)) ~= length(obj2(jj).(field)) | |
123 utils.helper.msg(msg.PROC1, 'NOT EQUAL: The property [%s] of the object [%s] have not the same size %d <-> %d.', field, class(obj1), length(obj1(jj).(field)), length(obj2(jj).(field))); | |
124 result = false; | |
125 return | |
126 end | |
127 | |
128 %%%%% Special case for param-objects because the order shouldn't matter | |
129 if isa(obj1(jj).(field), 'param') | |
130 | |
131 if ~eqparam(obj1(jj).(field), obj2(jj).(field), exception_list, tol) | |
132 result = false; | |
133 disaply_msg(obj1, jj, field) | |
134 return | |
135 end | |
136 | |
137 else | |
138 %%%%% For each element of the property | |
139 for kk = 1:numel(obj1(jj).(field)) | |
140 if isempty(plin) | |
141 % Command with a list of exceptions | |
142 res = eq(obj1(jj).(field)(kk), obj2(jj).(field)(kk), exception_list{:}); | |
143 else | |
144 % Command with a PLIST | |
145 res = eq(obj1(jj).(field)(kk), obj2(jj).(field)(kk), plin); | |
146 end | |
147 if ~res | |
148 result = false; | |
149 disaply_msg(obj1, jj, field) | |
150 return | |
151 end | |
152 end | |
153 end | |
154 | |
155 elseif isstruct(obj1(jj).(field)) | |
156 %%%%%%%%%% The property is a structure %%%%%%%%%% | |
157 | |
158 if ~eqstruct(obj1(jj).(field), obj2(jj).(field), exception_list, tol) | |
159 result = false; | |
160 disaply_msg(obj1, jj, field) | |
161 return | |
162 end | |
163 | |
164 elseif iscell(obj1(jj).(field)) | |
165 %%%%%%%%%% The property is a cell array %%%%%%%%%% | |
166 | |
167 if ~eqcell(obj1(jj).(field), obj2(jj).(field), exception_list, tol) | |
168 result = false; | |
169 disaply_msg(obj1, jj, field) | |
170 return | |
171 end | |
172 | |
173 elseif isnumeric(obj1(jj).(field)) | |
174 %%%%%%%%%% The property is an elemental MATLAB datatype %%%%%%%%%% | |
175 if ~utils.math.isequal(obj1(jj).(field), obj2(jj).(field), tol) | |
176 result = false; | |
177 disaply_msg(obj1, jj, field) | |
178 return | |
179 end | |
180 else | |
181 %%%%%%%%%% The property is an elemental MATLAB datatype %%%%%%%%%% | |
182 if ~isequal(obj1(jj).(field), obj2(jj).(field)) | |
183 result = false; | |
184 disaply_msg(obj1, jj, field) | |
185 return | |
186 end | |
187 end | |
188 | |
189 end | |
190 end | |
191 | |
192 end | |
193 end | |
194 | |
195 | |
196 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | |
197 % Local Functions % | |
198 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | |
199 | |
200 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | |
201 % | |
202 % FUNCTION: disaply_msg | |
203 % | |
204 % DESCRIPTION: Diesplay a message if the objects are not equal | |
205 % | |
206 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | |
207 | |
208 function disaply_msg(obj, obj_no, field) | |
209 import utils.const.* | |
210 if numel(obj) > 1 | |
211 utils.helper.msg(msg.PROC1, 'NOT EQUAL: %s.%s (%d. object)', class(obj(obj_no)), field, obj_no); | |
212 else | |
213 utils.helper.msg(msg.PROC1, 'NOT EQUAL: %s.%s', class(obj(obj_no)), field); | |
214 end | |
215 end | |
216 | |
217 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | |
218 % | |
219 % FUNCTION: eqstruct | |
220 % | |
221 % DESCRIPTION: Equal method to compare structures | |
222 % | |
223 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | |
224 | |
225 function result = eqstruct(obj1, obj2, exception_list, tol) | |
226 | |
227 import utils.const.* | |
228 | |
229 %%%%% Check class | |
230 if ~strcmp(class(obj1), class(obj2)) | |
231 utils.helper.msg(msg.PROC1, 'NOT EQUAL: The objects are not from the same class. [%s] <-> [%s]', class(obj1), class(obj2)); | |
232 result = false; | |
233 return | |
234 end | |
235 | |
236 %%%%% Check length of obj1 and obj2 | |
237 fieldsA = fieldnames(obj1); | |
238 fieldsB = fieldnames(obj2); | |
239 if numel(fieldsA) ~= numel(fieldsB) | |
240 utils.helper.msg(msg.PROC1, 'NOT EQUAL: The size of the %s-object''s. [%d] <-> [%d]', class(obj1), numel(obj1), numel(obj2)); | |
241 result = false; | |
242 return | |
243 end | |
244 | |
245 result = true; | |
246 | |
247 for oo = 1:numel(obj1) | |
248 for ii = 1:numel(fieldsA) | |
249 | |
250 if isa(obj1(oo).(fieldsA{ii}), 'ltpda_obj') | |
251 %%%%%%%%%%%%% LTPDA objects | |
252 if ~eq(obj1(oo).(fieldsA{ii}), obj2(oo).(fieldsA{ii}), plist('exceptions', exception_list, 'tol', tol)) | |
253 result = false; | |
254 disaply_msg(obj1, oo, fieldsA{ii}) | |
255 return | |
256 end | |
257 | |
258 elseif isstruct(obj1(oo).(fieldsA{ii})) | |
259 %%%%%%%%%%%%% STRUCTURE | |
260 if ~eqstruct(obj1(oo).(fieldsA{ii}), obj2(oo).(fieldsA{ii}), exception_list, tol) | |
261 result = false; | |
262 disaply_msg(obj1, oo, fieldsA{ii}) | |
263 return | |
264 end | |
265 | |
266 elseif iscell(obj1(oo).(fieldsA{ii})) | |
267 %%%%%%%%%%%%% STRUCTURE | |
268 if ~eqcell(obj1(oo).(fieldsA{ii}), obj2(oo).(fieldsA{ii}), exception_list, tol) | |
269 result = false; | |
270 disaply_msg(obj1, oo, fieldsA{ii}) | |
271 return | |
272 end | |
273 elseif isnumeric(obj1(oo).(fieldsA{ii})) | |
274 if ~utils.math.isequal(obj1(oo).(fieldsA{ii}), obj2(oo).(fieldsA{ii}), tol) | |
275 result = false; | |
276 disaply_msg(obj1, oo, fieldsA{ii}) | |
277 return | |
278 end | |
279 | |
280 else | |
281 if ~isequal(obj1(oo).(fieldsA{ii}), obj2(oo).(fieldsA{ii})) | |
282 result = false; | |
283 disaply_msg(obj1, oo, fieldsA{ii}) | |
284 return | |
285 end | |
286 end | |
287 | |
288 end % over all fields | |
289 end % over all objects | |
290 | |
291 end | |
292 | |
293 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | |
294 % | |
295 % FUNCTION: eqcell | |
296 % | |
297 % DESCRIPTION: Equal method to compare structures | |
298 % | |
299 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | |
300 | |
301 function result = eqcell(obj1, obj2, exception_list, tol) | |
302 | |
303 import utils.const.* | |
304 | |
305 %%%%% Check class | |
306 if ~strcmp(class(obj1), class(obj2)) | |
307 utils.helper.msg(msg.PROC1, 'NOT EQUAL: The objects are not from the same class. [%s] <-> [%s]', class(obj1), class(obj2)); | |
308 result = false; | |
309 return | |
310 end | |
311 | |
312 %%%%% Check length of obj1 and obj2 | |
313 if numel(obj1) ~= numel(obj2) | |
314 utils.helper.msg(msg.PROC1, 'NOT EQUAL: The size of the %s-object''s. [%d] <-> [%d]', class(obj1), numel(obj1), numel(obj2)); | |
315 result = false; | |
316 return | |
317 end | |
318 | |
319 result = true; | |
320 | |
321 for ii = 1:numel(obj1) | |
322 | |
323 if isa(obj1{ii}, 'ltpda_obj') | |
324 %%%%%%%%%%%%% LTPDA objects | |
325 if ~eq(obj1{ii}, obj2{ii}, plist('exceptions', exception_list, 'tol', tol)) | |
326 result = false; | |
327 disaply_msg(obj1, ii, 'cell-object') | |
328 return | |
329 end | |
330 | |
331 elseif isstruct(obj1{ii}) | |
332 %%%%%%%%%%%%% STRUCTURE | |
333 if ~eqstruct(obj1{ii}, obj2{ii}, exception_list, tol) | |
334 result = false; | |
335 disaply_msg(obj1, ii, 'cell-object') | |
336 return | |
337 end | |
338 | |
339 elseif iscell(obj1{ii}) | |
340 %%%%%%%%%%%%% CELL | |
341 if ~eqcell(obj1{ii}, obj2{ii}, exception_list, tol) | |
342 result = false; | |
343 disaply_msg(obj1, ii, 'cell-object') | |
344 return | |
345 end | |
346 | |
347 elseif isnumeric(obj1{ii}) | |
348 %%%%%%%%%%%%% Numberic | |
349 if ~utils.math.isequal(obj1{ii}, obj2{ii}, tol) | |
350 result = false; | |
351 disaply_msg(obj1, ii, 'cell-object') | |
352 return | |
353 end | |
354 | |
355 else | |
356 if ~isequal(obj1{ii}, obj2{ii}) | |
357 result = false; | |
358 disaply_msg(obj1, ii, 'cell-object') | |
359 return | |
360 end | |
361 end | |
362 end | |
363 end | |
364 | |
365 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | |
366 % | |
367 % FUNCTION: eqparam | |
368 % | |
369 % DESCRIPTION: Equal method to compare param-objects. The order of the | |
370 % param-objects doesn't matter. | |
371 % | |
372 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | |
373 | |
374 function result = eqparam(obj1, obj2, exception_list, tol) | |
375 | |
376 import utils.const.* | |
377 | |
378 %%%%% Check class | |
379 if ~strcmp(class(obj1), class(obj2)) | |
380 utils.helper.msg(msg.PROC1, 'NOT EQUAL: The objects are not from the same class. [%s] <-> [%s]', class(obj1), class(obj2)); | |
381 result = false; | |
382 return | |
383 end | |
384 | |
385 %%%%% Check length of obj1 and obj2 | |
386 if numel(obj1) ~= numel(obj2) | |
387 utils.helper.msg(msg.PROC1, 'NOT EQUAL: The size of the %s-object''s. [%d] <-> [%d]', class(obj1), numel(obj1), numel(obj2)); | |
388 result = false; | |
389 return | |
390 end | |
391 | |
392 result = true; | |
393 | |
394 for oo = 1:numel(obj1) | |
395 | |
396 found = false; | |
397 for ii = 1:numel(obj2) | |
398 | |
399 if strcmp(obj1(oo).key, obj2(ii).key) | |
400 allparts = true; | |
401 fields = fieldnames(obj1(oo)); | |
402 for ff = 1:numel(fields) | |
403 field = fields{ff}; | |
404 | |
405 ck_field = {field, sprintf('%s/%s', class(obj1), field)}; | |
406 if ~(any(utils.helper.ismember(ck_field, exception_list))) | |
407 | |
408 if strcmp(field, 'val') | |
409 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | |
410 %%% Compare only the current value | |
411 val1 = obj1(oo).getVal(); | |
412 val2 = obj2(ii).getVal(); | |
413 if isa(val1, 'ltpda_obj') | |
414 %%%%%%%%%%%%% LTPDA objects | |
415 allparts = allparts && eq(val1, val2, plist('exceptions', exception_list, 'tol', tol)); | |
416 | |
417 elseif isstruct(val1) | |
418 %%%%%%%%%%%%% STRUCTURE | |
419 allparts = allparts && eqstruct(val1, val2, exception_list, tol); | |
420 | |
421 elseif iscell(val1) | |
422 %%%%%%%%%%%%% CELL | |
423 allparts = allparts && eqcell(val1, val2, exception_list, tol); | |
424 elseif isnumeric(val1) | |
425 %%%%%%%%%%%%% Numeric | |
426 allparts = allparts && utils.math.isequal(val1, val2, tol); | |
427 else | |
428 allparts = allparts && isequal(val1, val2); | |
429 end | |
430 | |
431 %%%%% Check the properties of the paramValue Object | |
432 if isa(obj1(oo).val, 'paramValue') | |
433 allparts = allparts && eqstruct(obj1(oo).val.property, obj2(ii).val.property, exception_list, tol); | |
434 end | |
435 | |
436 continue; | |
437 end | |
438 | |
439 if isa(obj1(oo).(field), 'ltpda_obj') | |
440 %%%%%%%%%%%%% LTPDA objects | |
441 allparts = allparts && eq(obj1(oo).(field), obj2(ii).(field), plist('exceptions', exception_list, 'tol', tol)); | |
442 | |
443 elseif isstruct(obj1(oo).(field)) | |
444 %%%%%%%%%%%%% STRUCTURE | |
445 allparts = allparts && eqstruct(obj1(oo).(field), obj2(ii).(field), exception_list, tol); | |
446 | |
447 elseif iscell(obj1(oo).(field)) | |
448 %%%%%%%%%%%%% CELL | |
449 allparts = allparts && eqcell(obj1(oo).(field), obj2(ii).(field), exception_list, tol); | |
450 | |
451 elseif isnumeric(obj1(oo).(field)) | |
452 %%%%%%%%%%%%% Numeric | |
453 allparts = allparts && utils.math.isequal(obj1(oo).(field), obj2(ii).(field), tol); | |
454 else | |
455 allparts = allparts && isequal(obj1(oo).(field), obj2(ii).(field)); | |
456 end | |
457 | |
458 end | |
459 | |
460 end | |
461 if allparts | |
462 found = true; | |
463 end | |
464 end | |
465 | |
466 end % inner-loop | |
467 | |
468 if ~found | |
469 result = false; | |
470 disaply_msg(obj1, oo, ['key: ''' obj1(oo).key '''']) | |
471 return | |
472 end | |
473 | |
474 end % outer-loop | |
475 | |
476 end | |
477 | |
478 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | |
479 % | |
480 % FUNCTION: getInfo | |
481 % | |
482 % DESCRIPTION: Get Info Object | |
483 % | |
484 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | |
485 | |
486 function ii = getInfo(varargin) | |
487 if nargin == 1 && strcmpi(varargin{1}, 'None') | |
488 sets = {}; | |
489 pl = []; | |
490 else | |
491 sets = {'Default'}; | |
492 pl = getDefaultPlist; | |
493 end | |
494 % Build info object | |
495 ii = minfo(mfilename, 'plist', 'ltpda', utils.const.categories.relop, '$Id: eq.m,v 1.27 2011/04/08 08:56:21 hewitson Exp $', sets, pl); | |
496 ii.setModifier(false); | |
497 end | |
498 | |
499 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | |
500 % | |
501 % FUNCTION: getDefaultPlist | |
502 % | |
503 % DESCRIPTION: Get Default Plist | |
504 % | |
505 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | |
506 | |
507 function plo = getDefaultPlist() | |
508 plo = plist(); | |
509 | |
510 % Exceptions | |
511 p = param({'Exceptions', 'Test the objects without the given property names'}, paramValue.EMPTY_CELL); | |
512 plo.append(p); | |
513 | |
514 % Tolerance | |
515 p = param({'Tol', 'Test double values with the given tolerance'}, paramValue.DOUBLE_VALUE(eps(1))); | |
516 plo.append(p); | |
517 | |
518 end | |
519 |