diff scripts/general/isequal.m @ 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 092078913d54
children 1262d7c4712e
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])