Mercurial > octave
changeset 24308:606f3866cdb7
__isequal__.m: Rewrite function for performance.
* isequal.m: Add many more BIST tests. Most are to verify the same thing
through the two different internal code paths (2 args vs. multiple args) in
__isequal__.m
* __isequal__.m: Add Rik Wehbring to Copyright. Rewrite docstring and comments
describing algorithm. Add special fast path for only two arguments (most
common case). Use size_equal() rather than hand-rolled code to check ndims() and
size() along each dimension. Use strcmp without reshaping for better performance.
Add special fast conversion for cellstr type by converting to char arrays and using
strcmp. Put if/elseif branches in rough order of probability so common cases are
hit first. Only run isnan tests on floating point objects which can actually
have NaN values. Rename variables for clarity.
author | Rik <rik@octave.org> |
---|---|
date | Sat, 25 Nov 2017 21:56:15 -0800 |
parents | ddaee520d342 |
children | 1262d7c4712e |
files | scripts/general/isequal.m scripts/general/private/__isequal__.m |
diffstat | 2 files changed, 308 insertions(+), 161 deletions(-) [+] |
line wrap: on
line diff
--- a/scripts/general/isequal.m Fri Nov 24 17:29:00 2017 -0800 +++ b/scripts/general/isequal.m Sat Nov 25 21:56:15 2017 -0800 @@ -35,10 +35,10 @@ ## test empty input %!assert (isequal ([], []), true) +%!assert (isequal ([], 1), false) %!assert (isequal ([], [], 1), false) %!assert (isequal ([], 1, []), false) %!assert (isequal (1, [], []), false) -%!assert (isequal (1, [], []), false) ## test size and shape %!assert (isequal ([1,2,3,4], [1,2,3,4]), true) @@ -46,87 +46,145 @@ %!assert (isequal ([1,2,3,4], [1;2;3;4]), false) %!assert (isequal ([1,2,3,4], [1,2;3,4]), false) %!assert (isequal ([1,2,3,4], [1,3;2,4]), false) +%!assert (isequal ([1,2,3,4], [1,2,3,4], [1,2,3,4]), true) +%!assert (isequal ([1;2;3;4], [1;2;3;4], [1;2;3;4]), true) +%!assert (isequal ([1,2,3,4], [1,2,3,4], [1;2;3;4]), false) +%!assert (isequal ([1,2,3,4], [1,2,3,4], [1,2;3,4]), false) +%!assert (isequal ([1,2,3,4], [1,2,3,4], [1,3;2,4]), false) +## General tests %!test %! A = 1:8; %! B = reshape (A, 2, 2, 2); %! assert (isequal (A, B), false); +%! assert (isequal (A, A, B), false); %!test %! A = reshape (1:8, 2, 2, 2); %! B = A; %! assert (isequal (A, B), true); +%! assert (isequal (A, A, B), true); %!test %! A = reshape (1:8, 2, 4); %! B = reshape (A, 2, 2, 2); %! assert (isequal (A, B), false); +%! assert (isequal (A, A, B), false); + +## test characters and strings +%!assert (isequal ('a', "a"), true) +%!assert (isequal ('a', 'a', "a"), true) +%!assert (isequal ("abab", ["a", "b", "a", "b"]), true) +%!assert (isequal ("abab", "abab", ["a", "b", "a", "b"]), true) +%!assert (isequal (["a","b","c","d"], ["a","b","c","d"]), true) +%!assert (isequal (["a","b","c","d"], ["a","b","c","d"], ["a","b","c","d"]), +%! true) +%!assert (isequal (["test ";"strings"], ["test ";"strings"]), true) +%!assert (isequal (["test ";"strings"], ["test ";"strings"], +%! ["test ";"strings"]), true) +%!assert (isequal (["a","b","c","d"], ["a";"b";"c";"d"]), false) +%!assert (isequal (["a","b","c","d"], ["a","b","c","d"], ["a";"b";"c";"d"]), +%! false) ## test all numeric built-in primitives +%!assert (isequal (false, 0)) +%!assert (isequal (char (0), 0)) %!assert (isequal (false, logical (0), char (0), %! int8 (0), int16 (0), int32 (0), int64 (0), %! uint8 (0), uint16 (0), uint32 (0), uint64 (0), %! double (0), single (0), -%! double (complex (0,0)), single (complex (0,0))), +%! double (complex (0,0)), single (complex (0,0)), +%! sparse (false), sparse (logical (0)), +%! sparse (double (0)), sparse (single (0)), +%! sparse (double (complex (0,0))), +%! sparse (single (complex (0,0)))), %! true) %!assert (isequal (true, logical (1), char (1), %! int8 (1), int16 (1), int32 (1), int64 (1), %! uint8 (1), uint16 (1), uint32 (1), uint64 (1), %! double (1), single (1), -%! double (complex (1,0)), single (complex (1,0))), +%! double (complex (1,0)), single (complex (1,0)), +%! sparse (true), sparse (logical (1)), +%! sparse (double (1)), sparse (single (1)), +%! sparse (double (complex (1,0))), +%! sparse (single (complex (1,0)))), %! true) -## test characters and strings -%!assert (isequal ('a', "a"), true) -%!assert (isequal ("abab", ["a", "b", "a", "b"]), true) -%!assert (isequal (["a","b","c","d"], ["a","b","c","d"]), true) -%!assert (isequal (["test ";"strings"], ["test ";"strings"], -%! ["test ";"strings"]), true) -%!assert (isequal (["a","b","c","d"], ["a";"b";"c";"d"]), false) - -## test function_handle -%!test -%! fcn = @(x) x.^2; -%! assert (isequal (fcn, fcn), true); -%! assert (isequal (fcn, @(x) x.^2), false); -%! assert (isequal (@(x) x.^2, fcn), false); - ## test structures -%!assert (isequal (struct ([]),struct ([])), true) +%!assert (isequal (struct ([]), struct ([])), true) +%!assert (isequal (struct ([]), struct ([]), struct ([])), true) %!assert (isequal (struct ("a",1), struct ("a",1)), true) +%!assert (isequal (struct ("a",1), struct ("a",1), struct ("a",1)), true) %!assert (isequal (struct ("a",1), struct ("a",2)), false) +%!assert (isequal (struct ("a",1), struct ("a",1), struct ("a",2)), false) +%!assert (isequal (struct ("a",1), struct ("a",1,"b",2)), false) +%!assert (isequal (struct ("a",1), struct ("a",1),struct ("a",1,"b",2)), false) %!assert (isequal (struct ("a",1), struct ("b",1)), false) +%!assert (isequal (struct ("a",1), struct ("a",1), struct ("b",1)), false) %!assert (isequal (struct ("a",1,"b",2), struct ("a",1,"b",2)), true) +%!assert (isequal (struct ("a",1,"b",2), struct ("a",1,"b",2), +%! struct ("a",1,"b",2)), true) %!assert (isequal (struct ("a",1,"b",2), struct ("b",2,"a",1)), true) %!assert (isequal (struct ("a",1,"b",2), struct ("a",1,"b",2), -%! struct ("a",1,"b",2)), true) +%! struct ("b",2,"a",1)), true) %!assert (isequal (struct ("a","abc","b",2), struct ("a","abc","b",2)), true) +%!assert (isequal (struct ("a","abc","b",2), struct ("a","abc","b",2), +%! struct ("a","abc","b",2)), true) ## recursive structure %!test %! x.a = "a1"; %! x.b.a = "ba1"; %! x.b.b = "bb1"; +%! assert (isequal (x, x), true); %! assert (isequal (x, x, x), true); %! y = x; %! y.b.b = "bb2"; %! assert (isequal (x, y), false); +%! assert (isequal (x, x, y), false); %! y = x; %! y.b = rmfield (y.b, "b"); %! y.b.b.a = "bba1"; %! assert (isequal (x, y), false); +%! assert (isequal (x, x, y), false); + +## test cellstr +%!assert (isequal (cell (1,1), cell (1,1)), true) +%!assert (isequal (cell (1,1), cell (1,2)), false) +%!assert (isequal ({"a","b";"c","d"}, {"a","b";"c","d"}), true) +%!assert (isequal ({"a","b";"c","d"}, {"a","b";"c","d"}, {"a","b";"c","d"}), +%! true) +%!assert (isequal ({"a","b","c","d"}, {"a";"b";"c";"d"}), false) +%!assert (isequal ({"a","b","c","d"}, {"a","b","c","d"}, {"a";"b";"c";"d"}), +%! false) +%!assert (isequal (["a","b","c","d"], {"a","b","c","d"}), false) +%!assert (isequal (["a","b","c","d"], ["a","b","c","d"], {"a","b","c","d"}), +%! false) +%!test +%! x = { ["ab"; "cd"] ; ["ef"; "gh"] }; +%! assert (isequal (x, x), true); +%! assert (isequal (x, x, x), true); +%! y = x; +%! y(2) = ["ef"; "gH"]; +%! assert (isequal (x, y), false); +%! assert (isequal (x, x, y), false); ## test cells %!assert (isequal (cell (1,1), cell (1,1)), true) +%!assert (isequal (cell (1,1), cell (1,1), cell (1,1)), true) %!assert (isequal (cell (1,1), cell (1,2)), false) +%!assert (isequal (cell (1,1), cell (1,1), cell (1,2)), false) %!assert (isequal ({"a",1}, {"a",1}), true) +%!assert (isequal ({"a",1}, {"a",1}, {"a",1}), true) %!assert (isequal ({"a",1}, {"a",2}), false) +%!assert (isequal ({"a",1}, {"a",1}, {"a",2}), false) %!assert (isequal ({"a",1}, {"b",1}), false) +%!assert (isequal ({"a",1}, {"a",1}, {"b",1}), false) %!assert (isequal ({"a",1,"b",2}, {"a",1,"b",2}), true) +%!assert (isequal ({"a",1,"b",2}, {"a",1,"b",2}, {"a",1,"b",2}), true) %!assert (isequal ({"a",1,"b",2}, {"b",2,"a",1}), false) -%!assert (isequal ({"a",1,"b",2}, {"a",1,"b",2}, {"a",1,"b",2}), true) +%!assert (isequal ({"a",1,"b",2}, {"a",1,"b",2}, {"b",2,"a",1}), false) %!assert (isequal ({"a","abc","b",2}, {"a","abc","b",2}), true) -%!assert (isequal ({"a","b","c","d"}, {"a","b","c","d"}), true) -%!assert (isequal ({"a","b","c","d"}, {"a";"b";"c";"d"}), false) -%!assert (isequal (["a","b","c","d"], {"a","b","c","d"}), false) +%!assert (isequal ({"a","abc","b",2}, {"a","abc","b",2}, {"a","abc","b",2}), +%! true) ## recursive cell %!test @@ -139,26 +197,49 @@ %! y{3}{1}{1} = "goodbye"; %! assert (isequal (x, y), false); +## test function_handle +%!test +%! fcn = @(x) x.^2; +%! assert (isequal (fcn, fcn), true); +%! assert (isequal (fcn, fcn, fcn), true); +%! assert (isequal (fcn, @(x) x.^2), false); +%! assert (isequal (fcn, fcn, @(x) x.^2), false); +%! assert (isequal (@(x) x.^2, fcn), false); +%! assert (isequal (@(x) x.^2, @(x) x.^2, fcn), false); + ## test for sparse matrices %!assert (isequal (sparse ([]), []), true) +%!assert (isequal (sparse ([]), sparse ([]), []), true) %!assert (isequal ([], sparse ([])), true) +%!assert (isequal ([], [], sparse ([])), true) %!assert (isequal (sparse (0,1), sparse (0,1)), true) +%!assert (isequal (sparse (0,1), sparse (0,1), sparse (0,1)), true) %!assert (isequal (sparse (0,1), zeros (0,1)), true) +%!assert (isequal (sparse (0,1), sparse (0,1), zeros (0,1)), true) %!assert (isequal (sparse (2,2), sparse (2,2)), true) +%!assert (isequal (sparse (2,2), sparse (2,2), sparse (2,2)), true) %!assert (isequal (zeros (2,2), sparse (2,2)), true) +%!assert (isequal (zeros (2,2), zeros (2,2), sparse (2,2)), true) %!assert (isequal (speye (1), eye (1)), true) +%!assert (isequal (speye (1), speye (1), eye (1)), true) %!assert (isequal (eye (300), speye (300)), true) +%!assert (isequal (eye (300), eye (300), speye (300)), true) %!assert (isequal (sparse (0,1), sparse (1,0)), false) +%!assert (isequal (sparse (0,1), sparse (0,1), sparse (1,0)), false) ## test NaN %!assert (isequal (NaN, NaN), false) +%!assert (isequal (NaN, NaN, NaN), false) %!assert (isequal (NaN, Inf), false) +%!assert (isequal (NaN, Inf, Inf), false) %!assert (isequal (NaN, 1.0), false) +%!assert (isequal (NaN, 1.0, 1.0), false) %!assert (isequal ([1,2,NaN,4], [1,2,NaN,4]), false) +%!assert (isequal ([1,2,NaN,4], [1,2,NaN,4], [1,2,NaN,4]), false) +%!assert (isequal (struct ("a",NaN,"b",2), struct ("a",NaN,"b",2)), false) %!assert (isequal (struct ("a",NaN,"b",2), struct ("a",NaN,"b",2), %! struct ("a",NaN,"b",2)), false) ## test input validation %!error isequal () %!error isequal (1) -%!error isequal ([1,1])
--- a/scripts/general/private/__isequal__.m Fri Nov 24 17:29:00 2017 -0800 +++ b/scripts/general/private/__isequal__.m Sat Nov 25 21:56:15 2017 -0800 @@ -1,3 +1,4 @@ +## Copyright (C) 2017 Rik Wehbring ## Copyright (C) 2000-2017 Paul Kienzle ## ## This file is part of Octave. @@ -16,173 +17,238 @@ ## along with Octave; see the file COPYING. If not, see ## <http://www.gnu.org/licenses/>. -## Undocumented internal function. - ## -*- texinfo -*- -## @deftypefn {} {} __isequal__ (@var{nans_compare_equal}, @var{x1}, @var{x2}, @dots{}) -## Undocumented internal function. -## @end deftypefn - -## Return true if @var{x1}, @var{x2}, @dots{} are all equal and +## @deftypefn {} {} __isequal__ (@var{nans_compare_equal}, @var{x}, @var{y}, @dots{}) +## Internal function. +## +## Return true if @var{x}, @var{y}, @dots{} are all equal and ## @var{nans_compare_equal} evaluates to false. ## ## If @var{nans_compare_equal} evaluates to true, then assume NaN == NaN. - -## Modified by: William Poetra Yoga Hadisoeseno +## @end deftypefn ## Algorithm: ## -## 1. Determine the class of x -## 2. If x and all other arguments have the same class, then check that the -## number of dimensions and then the size of each dimension match. -## If not all arguments share the same class, then verify that all of the -## arguments belong to a comparable "numeric" class which includes -## numeric, logical, and character arrays. Check that number of dimensions -## and size of each dimension match. -## 3. For each argument after x, compare it for equality with x: -## a. struct compare each member by name, not by order (recursive) -## b. object convert to struct, and then compare as stated above -## c. cell compare each member by order (recursive) -## d. char compare each member with strcmp -## e fcn_handle compare using overloaded 'eq' operator -## f. <other> compare each nonzero member, and assume NaN == NaN +## 1. Verify the class of x. +## a. All objects are of the same class +## b. All objects are of a generic "numeric" class which includes +## numeric, logical, and character arrays +## 2. Verify size of all objects match. +## 3. Convert objects to struct, and then compare as stated below. +## 4. For each argument after x, compare it for equality with x: +## a. char compare each member with strcmp +## b. numeric compare each member with '==', and assume NaN == NaN ## if nans_compare_equal is nonzero. +## c. struct compare number of fieldnames, value of fieldnames, +## and then each field with __isequal__ (recursive) +## d. cellstr compare each cellstr member with strcmp +## e. cell compare each member with __isequal__ (recursive) +## f. fcn_handle compare using overloaded "eq" operator function t = __isequal__ (nans_compare_equal, x, varargin) - l_v = nargin - 2; - - ## Generic tests. + nvarargin = nargin - 2; + two_args = (nvarargin == 1); # Optimization for base case of just 2 args - ## All arguments must either be of the same class or they must be - ## "numeric" values. - t = (all (strcmp (class (x), - cellfun ("class", varargin, "uniformoutput", false))) - || ((isreal (x) || isnumeric (x)) - && all (cellfun ("isreal", varargin) - | cellfun ("isnumeric", varargin)))); - - if (t) - ## Test that everything has the same number of dimensions. - t = all (builtin ("ndims", x) == cellfun ("ndims", varargin)); + if (two_args) + y = varargin{1}; # alias y to second input for comparison endif - if (t) - ## Test that everything is the same size since the dimensionality matches. - nd = ndims (x); - k = 1; - do - t = all (builtin ("size", x, k) == cellfun ("size", varargin, k)); - until (! t || k++ == nd); + ############################################################ + ## Generic tests for equality + + ## All arguments must either be of the same class, + ## or they must be "numeric" values. + if (two_args) + t = (strcmp (class (x), class (y)) + || ((isreal (x) || iscomplex (x)) && (isreal (y) || iscomplex (y)))); + else + t = (all (cellfun ("isclass", varargin, class (x))) + || ((isreal (x) || iscomplex (x)) + && all (cellfun ("isreal", varargin) + | cellfun ("isnumeric", varargin)))); endif - ## From here on, compare objects as if they were structures. + ## Test that everything is the same size (which also tests dimensions) + if (t) + t = size_equal (x, varargin{:}); + endif + + ## From here on, compare any objects as if they were structures. if (t && isobject (x)) ## Locally suppress class-to-struct warning. We know what we are doing. warning ("off", "Octave:classdef-to-struct", "local"); x = builtin ("struct", x); - for i = 1:numel (varargin) - varargin{i} = builtin ("struct", varargin{i}); + for i = 1:nvarargin + varargin(i) = builtin ("struct", varargin{i}); endfor endif - if (t) - ## Check individual classes. - if (isstruct (x)) - ## Test the number of fields. - fn_x = fieldnames (x); - l_fn_x = numfields (x); - fn_v = cellfun ("fieldnames", varargin, "uniformoutput", false); - t = all (l_fn_x == cellfun ("numel", fn_v)); - - ## Test that all the names are equal. - idx = 0; - s_fn_x = sort (fn_x); - while (t && idx < l_v) - idx += 1; - ## We'll allow the fieldnames to be in a different order. - t = all (strcmp (s_fn_x, sort (fn_v{idx}))); - endwhile + ############################################################ + ## Check individual classes. - idx = 0; - while (t && idx < l_fn_x) - ## Test that all field values are equal. - idx += 1; - args = cell (1, 2+l_v); - args(1:2) = {nans_compare_equal, {x.(fn_x{idx})}}; - for argn = 1:l_v - args{argn+2} = {varargin{argn}.(fn_x{idx})}; - endfor - ## Minimize function calls by calling for all the arguments at once. - t = __isequal__ (args{:}); - endwhile - - elseif (iscellstr (x) && all (cellfun (@iscellstr, varargin))) - ## Check that each element of a cellstr is equal. - l_x = numel (x); - idx = 0; - ## FIXME: It would be faster to use strcmp on whole cellstr arrays, - ## rather than element-by-element, but bug #51412 needs to be fixed. - while (t && idx < l_x) - idx += 1; - t = all (strcmp (x{idx}, [cellindexmat(varargin, idx){:}])); - endwhile + if (t) + if (two_args) - elseif (iscell (x)) - ## Check that each element of a cell is equal. - l_x = numel (x); - idx = 0; - args = cell (1, 2+l_v); - args{1} = nans_compare_equal; - while (t && idx < l_x) - idx += 1; - args{2} = x{idx}; - args(3:end) = [cellindexmat(varargin, idx){:}]; - - t = __isequal__ (args{:}); - endwhile - - elseif (ischar (x) && all (cellfun ("isclass", varargin, "char"))) - ## Sizes are equal already, so we can just make everything into a - ## row and test the rows. - n_x = numel (x); - strings = cell (1, l_v); - for i = 1:l_v - strings{i} = reshape (varargin{i}, 1, n_x); - endfor - t = all (strcmp (reshape (x, 1, n_x), strings)); + if (ischar (x) && ischar (y)) + ## char type. Optimization, strcmp is ~35% faster than '==' operator. + t = strcmp (x, y); - elseif (isa (x, "function_handle")) - ## The == operator is overloaded for handles. - t = all (cellfun ("eq", {x}, varargin)); - - else - ## Check the numeric types. + elseif (isreal (x) || iscomplex (x)) + ## general "numeric" type. Use '==' operator. + m = (x == y); + t = all (m(:)); - f_x = find (x); - l_f_x = length (f_x); - x = x(f_x); - for argn = 1:l_v - y = varargin{argn}; - f_y = find (y); - - t = (l_f_x == length (f_y)) && all (f_x == f_y); - if (! t) - break; - endif - - y = y(f_y); - m = (x == y); - t = all (m); - - if (! t && nans_compare_equal) + if (! t && nans_compare_equal && isfloat (x) && isfloat (y)) t = isnan (x(! m)) && isnan (y(! m)); endif - if (! t) - break; + elseif (isstruct (x)) + ## struct type. Compare # of fields, fieldnames, then field values. + + ## Test number of fields are equal. + t = (numfields (x) == numfields (y)); + + ## Test that all the field names are equal. + if (t) + s_fnm_x = sort (fieldnames (x)); + t = all (strcmp (s_fnm_x, sort (fieldnames (y)))); + endif + + ## Test that all field values are equal. Slow because of recursion. + if (t) + for fldnm = s_fnm_x.' + t = __isequal__ (nans_compare_equal, x.(fldnm{1}), y.(fldnm{1})); + if (! t) + break; + endif + endfor endif - endfor + + elseif (iscellstr (x) && iscellstr (y)) + ## cellstr type. Optimization over cell type by using strcmp. + ## FIXME: It would be faster to use strcmp on whole cellstr arrays, + ## but bug #51412 needs to be fixed. Instead, time/space trade-off. + ## Convert to char (space) for faster processing with strcmp (time). + t = strcmp (char (x), char (y)); + + elseif (iscell (x)) + ## cell type. Check that each element of a cell is equal. Slow. + n = numel (x); + idx = 1; + while (t && idx <= n) + t = __isequal__ (nans_compare_equal, x{idx}, y{idx}); + idx += 1; + endwhile + + elseif (isa (x, "function_handle")) + ## function type. Use '==' operator which is overloaded. + t = (x == y); + + else + error ("__isequal__: Impossible to reach code. File a bug report."); + + endif + + else ## More than two args. This is going to be slower in general. + + if (ischar (x) && all (cellfun ("isclass", varargin, "char"))) + ## char type. Optimization, strcmp is ~35% faster than '==' operator. + idx = 1; + while (t && idx <= nvarargin) + t = strcmp (x, varargin{idx}); + idx += 1; + endwhile + + elseif (isreal (x) || iscomplex (x)) + ## general "numeric" type. Use '==' operator. + + idx = 1; + while (t && idx <= nvarargin) + y = varargin{idx}; + m = (x == y); + t = all (m(:)); + + if (! t && nans_compare_equal && isfloat (x) && isfloat (y)) + t = isnan (x(! m)) && isnan (y(! m)); + endif + + idx += 1; + endwhile + + elseif (isstruct (x)) + ## struct type. Compare # of fields, fieldnames, then field values. + + ## Test number of fields are equal. + fnm_x = fieldnames (x); + n = numel (fnm_x); + fnm_v = cellfun ("fieldnames", varargin, "uniformoutput", false); + t = all (n == cellfun ("numel", fnm_v)); + + ## Test that all the field names are equal. + if (t) + fnm_x = sort (fnm_x); + idx = 1; + while (t && idx <= nvarargin) + ## Allow the fieldnames to be in a different order. + t = all (strcmp (fnm_x, sort (fnm_v{idx}))); + idx += 1; + endwhile + endif + + ## Test that all field values are equal. Slow because of recursion. + if (t) + args = cell (1, 2 + nvarargin); + args(1) = nans_compare_equal; + for fldnm = fnm_x.' + args(2) = x.(fldnm{1}); + for argn = 1:nvarargin + args(argn+2) = varargin{argn}.(fldnm{1}); + endfor + + t = __isequal__ (args{:}); + + if (! t) + break; + endif + endfor + endif + + elseif (iscellstr (x) && all (cellfun (@iscellstr, varargin))) + ## cellstr type. Optimization over cell type by using strcmp. + ## FIXME: It would be faster to use strcmp on whole cellstr arrays, + ## but bug #51412 needs to be fixed. Instead, time/space trade-off. + ## Convert to char (space) for faster processing with strcmp (time). + idx = 1; + x = char (x); + while (t && idx <= nvarargin) + t = strcmp (x, char (varargin{idx})); + idx += 1; + endwhile + + elseif (iscell (x)) + ## cell type. Check that each element of a cell is equal. Slow. + n = numel (x); + args = cell (1, 2 + nvarargin); + args(1) = nans_compare_equal; + idx = 1; + while (t && idx <= n) + args(2) = x{idx}; + args(3:end) = [cellindexmat(varargin, idx){:}]; + + t = __isequal__ (args{:}); + + idx += 1; + endwhile + + elseif (isa (x, "function_handle")) + ## function type. Use '==' operator which is overloaded. + t = all (cellfun ("eq", {x}, varargin)); + + else + error ("__isequal__: Impossible to reach code. File a bug report."); + + endif endif endif