Code covered by the BSD License  

Highlights from
Vector algebra for arrays of any size, with array expansion enabled

image thumbnail
from Vector algebra for arrays of any size, with array expansion enabled by Paolo de Leva
Multiple dot, cross, and outer products, cross divisions, norms, normalizations, projections, etc.

cross2(a, b, idA, idB)
function c = cross2(a, b, idA, idB)
%CROSS2  Vector cross product.
%   This function exploits the BAXFUN engine (MATLAB Central, file #23084),
%   which enables multiple products and array expansion (AX).
%
%   When A and B are 3-element vectors (e.g. 31, 13, or 113 arrays):
%
%       C = CROSS2(A, B) returns their cross product. That is, C = A x B.
%       If NDIMS(A) == 2 and NDIMS(B) == 2, CROSS2(A, B) is equivalent to
%       CROSS(A, B).
%
%   More generally, when A and B are arrays of any size containing one or
%   more 3-element vectors:
%
%       C = CROSS2(A, B) is equivalent to C = CROSS2(A, B, IDA, IDB), where
%       IDA and IDB are the first dimensions of A and B whose length is 3.
%
%       C = CROSS2(A, B, DIM) is equivalent to C = CROSS2(A, B, IDA, IDB),
%       where IDA = IDB = DIM. If A and B have the same size, it is also
%       equivalent to C = CROSS(A, B, DIM).
%
%       C = CROSS2(A, B, IDA, IDB) returns the cross products between the
%       vectors contained in A along dimension IDA and those contained in B
%       along dimension IDB. These vectors must have 3 elements. A and B
%       are viewed as "block arrays". IDA and IDB are referred to as their
%       "internal dimensions" (IDs). For instance, a 362 array may be
%       viewed as an array containing twelve 3-element blocks. In this
%       case, its size is denoted by (3)62, and its ID is 1. Since AX is
%       enabled, A and B may have different size, and IDA may not coincide
%       with IDB (see MULTIPROD).
%
%       Input and output format:
%           Array     Block size     Internal dimension
%           ---------------------------------------------------------------
%           A         3  (1-D)       IDA
%           B         3  (1-D)       IDB
%           C         3  (1-D)       MAX(IDA, IDB)
%           ---------------------------------------------------------------
%           If SIZE(A)==SIZE(B) and IDA==IDB, then SIZE(C)=SIZE(A)=SIZE(B).
%
%   Examples:
%       If A and B are both   (3)62 arrays of vectors,
%       C = CROSS2(A, B) is a (3)62 array  of vectors.
%
%       A single vector B multiplies thirty vectors contained in A: 
%       If  A is ................ a 56(3) array of 30 vectors,
%       and B is ................ a (3)1   vector,
%       C = CROSS2(A, B, 3, 1) is a 56(3) array of 30 vectors.
%
%   See also DOT2, CROSS, CROSSDIV, OUTER, MAGN, UNIT, PROJECTION,
%            REJECTION, TESTCROSS2.

% $ Version: 2.0 $
% CODE      by:                 Paolo de Leva (IUSM, Rome, IT) 2009 Feb 2
%           optimized by:       Code author                    2009 Feb 12
% COMMENTS  by:                 Code author                    2009 Feb 26
% OUTPUT    tested by:          Code author                    2009 Feb 26
% -------------------------------------------------------------------------

% Allow 2 to 4 input arguments
error( nargchk(2, 4, nargin) ); 

% Setting IDA and/or IDB
sizeA = size(a);
sizeB = size(b);
switch nargin
    case 2        
        idA = find(sizeA==3, 1, 'first'); % First dim. of length 3
        idB = find(sizeB==3, 1, 'first');
        if isempty(idA) || isempty(idB)
            error('CROSS2:InvalidSize',...
                  'A and B must have at least one dimension of length 3.');
        end        
    case 3
        idB = idA;
end

% Check block size
if (sizeA(idA)~=3) || (sizeB(idB)~=3),
    error('CROSS2:InvalidBlockSize',...
         ['A and B must be of length 3 in the dimensions\n'...
          'in which the cross product is taken.'])
end

% Dimension shift (first step of array expansion)
%     NOTE: The BAXFUN engine is implemented here without calling
%           BAXFUN, to avoid repeated shift of A and B
diff = idB - idA;
if diff >= 0
    id = idB;
    sizeA = [ones(1, diff) sizeA];
    a = reshape(a, sizeA);
else
    id = idA;
    sizeB = [ones(1,-diff) sizeB];
    b = reshape(b, sizeB);
end

% Vectorized indices to rearrange A and B
idxA = ivector(sizeA);
idxB = ivector(sizeB);

% Calculate cross product
%     c = [a(2,:).*b(3,:) - a(3,:).*b(2,:)
%          a(3,:).*b(1,:) - a(1,:).*b(3,:)
%          a(1,:).*b(2,:) - a(2,:).*b(1,:)];
idxA{id} = [2 3 1]; 
idxB{id} = [3 1 2];
c =     bsxfun( @times, a(idxA{:}), b(idxB{:}) );
idxA{id} = [3 1 2]; 
idxB{id} = [2 3 1];
c = c - bsxfun( @times, a(idxA{:}), b(idxB{:}) );


%--------------------------------------------------------------------------
function indices = ivector(sizeA)
%IVECTOR   Vectorizing the indices of an array. 

Ndims = length(sizeA);
indices = cell(1,Ndims); % preallocating
for d = 1 : Ndims
   indices{d} = 1:sizeA(d);
end    

Contact us