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