Mercurial > octave
view scripts/linear-algebra/cross.m @ 33279:308060bc6b27 stable
cross: Improve input validation and expand BISTs. (bug #65544)
* cross.m: Add input validation check for input dim to ensure it's a real
integer valued numeric scalar. Change vector check from columns and rows
count to iscolumn and isrow check to avoid passing 1-by-n-by-m and n-by-1-by-m
arrays through to transpose operator. Move size and ndims check earlier
to reduce repeated function calls. Reduce large BISTs tolerances on simple
tests from 2e-8 to eps. Change docstring mention of matrices to arrays, add
note about error if sz(dim) != 3, and add additional example. Add BISTs
to verify dim input validation and to catch vector transpose check. Add
BISTs for all error messages and warnings and remove FIXME note requesting
the same.
* NEWS.9.md: Note change to dim input validation.
author | Nicholas R. Jankowski <jankowski.nicholas@gmail.com> |
---|---|
date | Sun, 31 Mar 2024 22:48:01 -0400 |
parents | 2e484f9f1f18 |
children | 2aea823a9973 |
line wrap: on
line source
######################################################################## ## ## Copyright (C) 1995-2024 The Octave Project Developers ## ## See the file COPYRIGHT.md in the top-level directory of this ## distribution or <https://octave.org/copyright/>. ## ## This file is part of Octave. ## ## Octave is free software: you can redistribute it and/or modify it ## under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## Octave is distributed in the hope that it will be useful, but ## WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with Octave; see the file COPYING. If not, see ## <https://www.gnu.org/licenses/>. ## ######################################################################## ## -*- texinfo -*- ## @deftypefn {} {@var{z} =} cross (@var{x}, @var{y}) ## @deftypefnx {} {@var{z} =} cross (@var{x}, @var{y}, @var{dim}) ## Compute the vector cross product of two 3-dimensional vectors @var{x} and ## @var{y}. ## ## If @var{x} and @var{y} are arrays, the cross product is applied along the ## first dimension with three elements. ## ## The optional argument @var{dim} forces the cross product to be calculated ## along the specified dimension. An error will be produced if the specified ## dimension is not three elements in size. ## ## Example Code: ## ## @example ## @group ## cross ([1, 1, 0], [0, 1, 1]) ## @result{} ## 1 -1 1 ## @end group ## @end example ## ## @example ## @group ## cross (magic (3), eye (3), 2) ## @result{} ## 0 6 -1 ## -7 0 3 ## 9 -4 0 ## @end group ## @end example ## ## @seealso{dot, curl, divergence} ## @end deftypefn function z = cross (x, y, dim) if (nargin < 2) print_usage (); endif nd = ndims (x); if (nd < 3 && ndims (y) < 3 && nargin < 3) ## COMPATIBILITY -- opposite behavior for cross(row,col) ## Swap x and y in the assignments below to get the matlab behavior. ## Better yet, fix the calling code so that it uses conformant vectors. if (iscolumn (x) && isrow (y)) warning ("cross: taking cross product of column by row"); y = y.'; elseif (isrow (x) && iscolumn (y)) warning ("cross: taking cross product of row by column"); x = x.'; endif endif sz = size (x); if (nargin == 2) dim = find (sz == 3, 1); if (isempty (dim)) error ("cross: must have at least one dimension with 3 elements"); endif else if (! (isnumeric (dim) && dim > 0 && isreal (dim) && ... isscalar (dim) && dim == fix (dim))) error ("cross: DIM must be a positive scalar whole number"); endif if (dim > nd || sz(dim) != 3) error ("cross: must have three elements in dimension DIM"); endif endif idx2 = idx3 = idx1 = {':'}(ones (1, nd)); idx1(dim) = 1; idx2(dim) = 2; idx3(dim) = 3; if (size_equal (x, y)) x1 = x(idx1{:}); x2 = x(idx2{:}); x3 = x(idx3{:}); y1 = y(idx1{:}); y2 = y(idx2{:}); y3 = y(idx3{:}); z = cat (dim, (x2.*y3 - x3.*y2), (x3.*y1 - x1.*y3), (x1.*y2 - x2.*y1)); else error ("cross: X and Y must have the same dimensions"); endif endfunction %!test %! x = [1, 0, 0]; %! y = [0, 1, 0]; %! r = [0, 0, 1]; %! assert (cross (x, y), r, eps); %!test %! x = [1, 2, 3]; %! y = [4, 5, 6]; %! r = [(2*6-3*5), (3*4-1*6), (1*5-2*4)]; %! assert (cross (x, y), r, eps); %!test %! x = [1, 0, 0; 0, 1, 0; 0, 0, 1]; %! y = [0, 1, 0; 0, 0, 1; 1, 0, 0]; %! r = [0, 0, 1; 1, 0, 0; 0, 1, 0]; %! assert (cross (x, y, 2), r, eps); %! assert (cross (x, y, 1), -r, eps); %!test <*65527> %! x = cat (3, [1, 1, 1]', [1, 1, 1]'); %! y = cat (3, [1, 0, 0], [1, 0, 0]); %! fail ("cross (x, y)", "X and Y must have the same dimensions"); %! fail ("cross (y, x)", "X and Y must have the same dimensions"); ## Test input validation %!error <Invalid call> cross () %!error <Invalid call> cross (1) %!error <must have at least one dimension with 3 elements> cross (0, 0) %!error <must have at least one dimension with 3 elements> cross ([1, 2], [3, 4]) %!error <must have at least one dimension with 3 elements> cross ([1, 2], [3, 4, 5]) %!error <must have three elements in dimension DIM> cross (0, 0, 1) %!error <must have three elements in dimension DIM> cross ([1, 2, 3], [1, 2, 3], 1) %!error <must have three elements in dimension DIM> cross ([1, 2, 3], [1, 2, 3], 9) %!error <must have three elements in dimension DIM> cross (magic (3), magic (3), 4) %!error <DIM must be a positive scalar whole number> cross ([1, 2, 3], [4, 5, 6], {1}) %!error <DIM must be a positive scalar whole number> cross ([1, 2, 3], [4, 5, 6], "a") %!error <DIM must be a positive scalar whole number> cross ([1, 2, 3], [4, 5, 6], true) %!error <DIM must be a positive scalar whole number> cross ([1, 2, 3], [4, 5, 6], [1, 2]) %!error <DIM must be a positive scalar whole number> cross ([1, 2, 3], [4, 5, 6], 0) %!error <DIM must be a positive scalar whole number> cross ([1, 2, 3], [4, 5, 6], -1) %!error <DIM must be a positive scalar whole number> cross ([1, 2, 3], [4, 5, 6], 1.5) %!error <DIM must be a positive scalar whole number> cross ([1, 2, 3], [4, 5, 6], 2i) %!error <X and Y must have the same dimensions> cross ([1, 2, 3], [3, 4]) %!warning <taking cross product of column by row> cross ([1, 2, 3]', [4, 5, 6]); %!warning <taking cross product of row by column> cross ([1, 2, 3], [4, 5, 6]');