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