Mercurial > octave
changeset 27229:255f2681d224
intersect.m: Accept a "legacy" flag for Matlab compatibility.
* NEWS: Announce change.
* intersect.m: Add new calling form and explanation of "legacy" option to
docstring. Allow up to 4 inputs in input validation. Check for "legacy"
in input options and set variable optlegacy. Only use two-input form
of sort or sortrows when number of outputs of intersect function is greater
than 1. After calculation, change orientation of outputs as required based
on optlegacy. Add BIST tests to test output orientation and values.
* validsetargs.m: Modify to accept a variable number of option arguments as
last input (varargin). Use switch statement to validate possible options
including accepting "legacy".
author | Rik <rik@octave.org> |
---|---|
date | Wed, 10 Jul 2019 17:32:52 -0700 |
parents | c80681b4948d |
children | 9f44123dc25b |
files | NEWS scripts/set/intersect.m scripts/set/private/validsetargs.m |
diffstat | 3 files changed, 87 insertions(+), 29 deletions(-) [+] |
line wrap: on
line diff
--- a/NEWS Wed Jul 10 17:25:39 2019 -0700 +++ b/NEWS Wed Jul 10 17:32:52 2019 -0700 @@ -53,6 +53,10 @@ behavior, or Matlab behavior from releases prior to R2012b, can be obtained by using the `"legacy"` flag. +- The function `intersect` now accepts a `"legacy"` flag which changes + the index values (second and third outputs) as well as the orientation + of the outputs to match Matlab releases prior to R2012b. + - Complex RESTful web services can now be accessed by the `webread` and `webwrite` functions alongside with the `weboptions` structure. One major feature is the support for cookies to enable RESTful
--- a/scripts/set/intersect.m Wed Jul 10 17:25:39 2019 -0700 +++ b/scripts/set/intersect.m Wed Jul 10 17:32:52 2019 -0700 @@ -20,6 +20,7 @@ ## -*- texinfo -*- ## @deftypefn {} {@var{c} =} intersect (@var{a}, @var{b}) ## @deftypefnx {} {@var{c} =} intersect (@var{a}, @var{b}, "rows") +## @deftypefnx {} {@var{c} =} intersect (@dots{}, "legacy") ## @deftypefnx {} {[@var{c}, @var{ia}, @var{ib}] =} intersect (@dots{}) ## ## Return the unique elements common to both @var{a} and @var{b} sorted in @@ -32,15 +33,19 @@ ## If the optional input @qcode{"rows"} is given then return the common rows of ## @var{a} and @var{b}. The inputs must be 2-D matrices to use this option. ## -## If requested, return index vectors @var{ia} and @var{ib} such that +## If requested, return column index vectors @var{ia} and @var{ib} such that ## @code{@var{c} = @var{a}(@var{ia})} and @code{@var{c} = @var{b}(@var{ib})}. ## +## Programming Note: The input flag @qcode{"legacy"} changes the shape of the +## outputs (@var{c}, @var{i}, @var{j} to row vectors whenever at least one of +## the inputs is a row vector. +## ## @seealso{unique, union, setdiff, setxor, ismember} ## @end deftypefn function [c, ia, ib] = intersect (a, b, varargin) - if (nargin < 2 || nargin > 3) + if (nargin < 2 || nargin > 4) print_usage (); endif @@ -58,13 +63,21 @@ endif ia = ib = []; else - by_rows = nargin == 3; - isrowvec = isrow (a) && isrow (b); + by_rows = any (strcmp ("rows", varargin)); + optlegacy = any (strcmp ("legacy", varargin)); + + if (optlegacy) + isrowvec = ! iscolumn (a) || ! iscolumn (b); + else + isrowvec = isrow (a) && isrow (b); + endif ## Form A and B into sets if (nargout > 1) [a, ja] = unique (a, varargin{:}); + ja = ja(:); [b, jb] = unique (b, varargin{:}); + jb = jb(:); else a = unique (a, varargin{:}); b = unique (b, varargin{:}); @@ -72,13 +85,21 @@ if (by_rows) c = [a; b]; - [c, ic] = sortrows (c); + if (nargout > 1) + [c, ic] = sortrows (c); + else + c = sortrows (c); + endif ii = find (all (c(1:end-1,:) == c(2:end,:), 2)); c = c(ii,:); len_a = rows (a); else c = [a(:); b(:)]; - [c, ic] = sort (c); # [a(:);b(:)](ic) == c + if (nargout > 1) + [c, ic] = sort (c); # [a(:);b(:)](ic) == c + else + c = sort (c); + endif if (iscellstr (c)) ii = find (strcmp (c(1:end-1), c(2:end))); else @@ -88,15 +109,20 @@ len_a = length (a); endif + ## Adjust output orientation for Matlab compatibility + if (isrowvec) + c = c.'; + endif + if (nargout > 1) ia = ja(ic(ii)); # a(ia) == c ib = jb(ic(ii+1) - len_a); # b(ib) == c + if (optlegacy && isrowvec) + ia = ia.'; + ib = ib.'; + endif endif - ## Adjust output orientation for Matlab compatibility - if (! by_rows && isrowvec) - c = c.'; - endif endif endfunction @@ -107,10 +133,17 @@ %! a = 1:4; %! b = 2:5; -%!assert (size (intersect (a, b)), [1 3]) -%!assert (size (intersect (a', b)), [3 1]) -%!assert (size (intersect (a, b')), [3 1]) -%!assert (size (intersect (a', b')), [3 1]) +%!assert (size (intersect (a, b)), [1, 3]) +%!assert (size (intersect (a', b)), [3, 1]) +%!assert (size (intersect (a, b')), [3, 1]) +%!assert (size (intersect (a', b')), [3, 1]) +%!assert (size (intersect (a, b, "legacy")), [1, 3]) +%!assert (size (intersect (a', b, "legacy")), [1, 3]) +%!assert (size (intersect (a, b', "legacy")), [1, 3]) +%!assert (size (intersect (a', b', "legacy")), [3, 1]) + +## Clear shared variables +%!shared ## Test multi-dimensional arrays %!test @@ -150,6 +183,19 @@ %! assert (ia, [1:3]'); %! assert (ib, [1:3]'); +## Test "legacy" argument +%!test +%! a = [7 1 7 7 4]; +%! b = [7 0 4 4 0]; +%! [c, ia, ib] = intersect (a, b); +%! assert (c, [4, 7]); +%! assert (ia, [5; 1]); +%! assert (ib, [3; 1]); +%! [c, ia, ib] = intersect (a, b, "legacy"); +%! assert (c, [4, 7]); +%! assert (ia, [5, 4]); +%! assert (ib, [4, 1]); + ## Test return type of empty intersections %!assert (intersect (['a', 'b'], {}), {}) %!assert (intersect ([], {'a', 'b'}), {})
--- a/scripts/set/private/validsetargs.m Wed Jul 10 17:25:39 2019 -0700 +++ b/scripts/set/private/validsetargs.m Wed Jul 10 17:32:52 2019 -0700 @@ -19,7 +19,7 @@ ## Validate arguments for binary set operation. -function [x, y] = validsetargs (caller, x, y, byrows_arg) +function [x, y] = validsetargs (caller, x, y, varargin) isallowedarraytype = @(x) isnumeric (x) || ischar (x) || islogical (x); @@ -42,21 +42,29 @@ error ("%s: A and B must be arrays or cell arrays of strings", caller); endif elseif (nargin == 4) - if (! strcmpi (byrows_arg, "rows")) - error ("%s: invalid option: %s", caller, byrows_arg); - endif + for arg = varargin + switch (arg{1}) + case "legacy" + ## Accepted option, do nothing. - if (iscell (x) || iscell (y)) - error ('%s: cells not supported with "rows"', caller); - elseif (! (isallowedarraytype (x) && isallowedarraytype (y))) - error ("%s: A and B must be arrays or cell arrays of strings", caller); - else - if (ndims (x) > 2 || ndims (y) > 2) - error ('%s: A and B must be 2-dimensional matrices for "rows"', caller); - elseif (columns (x) != columns (y) && ! (isempty (x) || isempty (y))) - error ("%s: number of columns in A and B must match", caller); - endif - endif + case "rows" + if (iscell (x) || iscell (y)) + error ('%s: cells not supported with "rows"', caller); + elseif (! (isallowedarraytype (x) && isallowedarraytype (y))) + error ("%s: A and B must be arrays or cell arrays of strings", caller); + else + if (ndims (x) > 2 || ndims (y) > 2) + error ('%s: A and B must be 2-dimensional matrices for "rows"', caller); + elseif (columns (x) != columns (y) && ! (isempty (x) || isempty (y))) + error ("%s: number of columns in A and B must match", caller); + endif + endif + + otherwise + error ("%s: invalid option: %s", caller, byrows_arg); + + endswitch + endfor endif endfunction