1%% Copyright (C) 2000, 2005, 2006, 2007 Paul Kienzle
2%%
3%% This file is part of Octave.
4%%
5%% Octave is free software; you can redistribute it and/or modify it
6%% under the terms of the GNU General Public License as published by
7%% the Free Software Foundation; either version 3 of the License, or (at
8%% your option) any later version.
9%%
10%% Octave is distributed in the hope that it will be useful, but
11%% WITHOUT ANY WARRANTY; without even the implied warranty of
12%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13%% General Public License for more details.
14%%
15%% You should have received a copy of the GNU General Public License
16%% along with Octave; see the file COPYING.  If not, see
17%% <http://www.gnu.org/licenses/>.
18
19%% Undocumented internal function.
20
21%% -*- texinfo -*-
22%% @deftypefn {Function File} {} isequal3 (@var{nans_compare_equal}, @var{x1}, @var{x2}, @dots{})
23%% Return true if @var{x1}, @var{x2}, @dots{} are all equal and
24%% @var{nans_compare_equal} evaluates to false.
25%%
26%% If @var{nans_compare_equal} evaluates to true, then assume NaN == NaN.
27%% @seealso{isequal, isequalwithequalnans}
28%% @end deftypefn
29
30%% Modified by: William Poetra Yoga Hadisoeseno
31%% modified by Alois Schloegl for the use with Matlab
32
33%% Algorithm:
34%%
35%% 1. Determine the class of x
36%% 2. If x is of the struct, cell, list or char class, for each
37%%    argument after x, determine whether it has the same class
38%%    and size as x.
39%%    Otherwise, for each argument after x, verify that it is not
40%%    of the struct, cell, list or char class, and that it has
41%%    the same size as x.
42%% 3. For each argument after x, compare it for equality with x:
43%%    a. struct     compare each member by name, not by order (recursive)
44%%    b. cell/list  compare each member by order (recursive)
45%%    c. char       compare each member with strcmp
46%%    d. <other>    compare each nonzero member, and assume NaN == NaN
47%%                  if nans_compare_equal is nonzero.
48
49function t = isequal3(nans_compare_equal, x, varargin)
50
51  if (nargin < 2)
52    print_usage ();
53  end
54
55  l_v = nargin - 2;
56
57  %% Generic tests.
58
59  %% All arguments must either be of the same class or they must be
60  %% numeric values.
61  t = (all (strcmp (class(x), cellfun (@class, varargin, 'UniformOutput', false))) || (isnumeric (x) && all (cellfun (@isnumeric, varargin, 'UniformOutput', true))));
62
63  if (t)
64    %% Test that everything has the same number of dimensions.
65    s_x = size (x);
66    s_v = cellfun (@size, varargin, 'UniformOutput', false);
67    t = all (length (s_x) == cellfun (@length, s_v));
68  end
69
70  if (t)
71    %% Test that everything is the same size since it has the same
72    %% dimensionality.
73    l_x = length (s_x);
74    s_v = reshape ([s_v{:}], length (s_x), []);
75    idx = 0;
76    while (t && idx < l_x)
77      idx=idx+1;
78      t = all (s_x(idx) == s_v(idx, :));
79    end
80  end
81
82  if (t)
83    %% Check individual classes.
84    if (isstruct (x))
85      %% Test the number of fields.
86      fn_x = fieldnames (x);
87      l_fn_x = length (fn_x);
88      fn_v = cellfun (@fieldnames, varargin, 'UniformOutput', false);
89      t = all (l_fn_x == cellfun (@length, fn_v));
90
91      %% Test that all the names are equal.
92      idx = 0;
93      s_fn_x = sort (fn_x);
94      while (t && idx < l_v)
95      	idx=idx+1;
96	%% We'll allow the fieldnames to be in a different order.
97	t = all (strcmp (s_fn_x, sort (fn_v{idx})));
98      end
99
100      idx = 0;
101      while (t && idx < l_fn_x)
102	%% Test that all field values are equal.
103      	idx=idx+1;
104	args = {nans_compare_equal, {x.(fn_x{idx})}};
105	for argn = 1:l_v
106	  args{argn+2} = {varargin{argn}.(fn_x{idx})};
107	end
108	%% Minimize function calls by calling for all the arguments at
109	%% once.
110        t = isequal3(args{:});
111      end
112
113    elseif (iscell (x))
114      %% Check that each element of a cell is equal.
115      l_x = numel (x);
116      idx = 0;
117      while (t && idx < l_x)
118	idx=idx+1;
119	args = {nans_compare_equal, x{idx}};
120	for p = 1:l_v
121	  args{p+2} = varargin{p}{idx};
122	end
123        t = isequal3 (args{:});
124      end
125
126    elseif (ischar (x))
127
128      %% Sizes are equal already, so we can just make everything into a
129      %% row and test the rows.
130      for i = 1:l_v
131	strings{i} = reshape (varargin{i}, 1, []);
132      end
133      t = all (strcmp (reshape (x, 1, []), strings));
134
135    else
136      %% Check the numeric types.
137
138      if (issparse (x))
139	f_x = spfind (x);
140      else
141	f_x = find (x);
142      end
143      l_f_x = length (f_x);
144      x = x(f_x);
145      for argn = 1:l_v
146	y = varargin{argn};
147	if (issparse (y))
148          f_y = spfind (y);
149	else
150          f_y = find (y);
151	end
152
153	t = (l_f_x == length (f_y)) && all (f_x == f_y);
154	if (~t)
155          return;
156	end
157
158	y = y(f_y);
159	m = (x == y);
160	t = all (m);
161
162	if (~t)
163          if (nans_compare_equal)
164            t = isnan (x(~m)) && isnan (y(~m));
165          else
166            return;
167          end
168	end
169      end
170
171    end
172  end
173
174end
175
176%% test size and shape
177%!assert(isequal3(0,[1,2,3,4],[1,2,3,4]), true)
178%!assert(isequal3(0,[1;2;3;4],[1;2;3;4]), true)
179%!assert(isequal3(0,[1,2,3,4],[1;2;3;4]), false)
180%!assert(isequal3(0,[1,2,3,4],[1,2;3,4]), false)
181%!assert(isequal3(0,[1,2,3,4],[1,3;2,4]), false)
182
183%!test
184%! A = 1:8;
185%! B = reshape (A, 2, 2, 2);
186%! assert (isequal3 (0, A, B), false);
187
188%!test
189%! A = reshape (1:8, 2, 2, 2);
190%! B = A;
191%! assert (isequal3 (0, A, B), true);
192
193%!test
194%! A = reshape (1:8, 2, 4);
195%! B = reshape (A, 2, 2, 2);
196%! assert (isequal3 (0, A, B), false);
197
198%% test for equality
199%!assert(isequal3(0,[1,2,3,4],[1,2,3,4]), true)
200%!assert(isequal3(1,{1,2,NaN,4},{1,2,NaN,4}), true)
201%!assert(isequal3(1,[1,2,NaN,4],[1,2,NaN,4]), true)
202%!assert(isequal3(0,['a','b','c','d'],['a','b','c','d']), true)
203%% Test multi-line strings
204%!assert(isequal3(0,["test";"strings"],["test";"strings"],["test";"strings"]), true)
205%% test for inequality
206%!assert(isequal3(0,[1,2,3,4],[1;2;3;4]),false)
207%!assert(isequal3(0,{1,2,3,4},[1,2,3,4]),false)
208%!assert(isequal3(0,[1,2,3,4],{1,2,3,4}),false)
209%!assert(isequal3(0,[1,2,NaN,4],[1,2,NaN,4]),false)
210%!assert(isequal3(1,[1,2,NaN,4],[1,NaN,3,4]),false)
211%!assert(isequal3(1,[1,2,NaN,4],[1,2,3,4]),false)
212%!assert(isequal3(0,['a','b','c','d'],['a';'b';'c';'d']),false)
213%!assert(isequal3(0,{'a','b','c','d'},{'a';'b';'c';'d'}),false)
214%% test for equality (struct)
215%!assert(isequal3(0,struct('a',1,'b',2),struct('a',1,'b',2)),true)
216%!assert(isequal3(0,struct('a',1,'b',2),struct('a',1,'b',2),struct('a',1,'b',2)),true)
217%!assert(isequal3(0,struct('a','abc','b',2),struct('a','abc','b',2)),true)
218%!assert(isequal3(1,struct('a',NaN,'b',2),struct('a',NaN,'b',2),struct('a',NaN,'b',2)),true)
219%% test for inequality (struct)
220%!assert(isequal3(0,struct('a',NaN,'b',2),struct('a',NaN,'b',2),struct('a',NaN,'b',2)),false)
221
222