Professional Documents
Culture Documents
M Array Manipulation Tips and Tricks: Atlab
M Array Manipulation Tips and Tricks: Atlab
Peter J. Acklam Statistics Division Department of Mathematics University of Oslo Norway E-mail: jacklam@math.uio.no WWW URL: http://www.math.uio.no/~jacklam/ 5 May 2000
Abstract This document is intended to be a compilation tips and tricks mainly related to efcient ways of performing low-level array manipulation in M ATLAB. Here, manipulate means replicating and rotating arrays or parts of arrays, inserting, extracting, permuting and shifting elements, generating combinations and permutations of elements, runlength encoding and decoding, multiplying and dividing arrays and calculating distance matrics and so forth. A few other issues regarding how to write fast M ATLAB code is also covered.
A This document was produced with -LTEX. The PS (PostScript) version was created with dvips by Tomas Rokicki. The PDF (Portable Document Format) version was created with ps2pdf, a part of Aladdin Ghostscript by Aladdin Enterprises.
The PS and PDF version may be viewed with software available at the Ghostscript, Ghostview and GSview Home Page at http://www.cs.wisc.edu/~ghost/index.html. The PDF version may also be viewed with Adobe Acrobat Reader available at http://www.adobe.com/products/acrobat/readstep.html. Copyright 2000 Peter J. Acklam. All rights reserved. Any material in this document may be reproduced or duplicated for personal or educational use. M ATLAB is a trademark of The MathWorks, Inc. (http://www.mathworks.com) TEX is a trademark of the American Mathematical Society (http://www.ams.org)
CONTENTS
Contents
1 Introduction 1.1 Background . . . . . . . 1.2 Vectorization . . . . . . 1.3 About the examples . . . 1.4 Credit where credit is due 1.5 Errors/Feedback . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3 3 4 4 4 4 4 5 5 5 5 5 5 6 6 6 6 6 7 7
2 Operators, functions and special characters 2.1 Operators . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2.2 Built-in functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2.3 M-le functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3 Creating vectors, matrices and arrays 3.1 Special vectors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3.1.1 Uniformly spaced elements . . . . . . . . . . . . . . . . . . . . . . . . . . . 4 Shifting 4.1 Vectors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4.2 Arrays . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5 Replicating elements and arrays 5.1 Constant array . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5.2 Replicating elements in vectors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5.2.1 Replicate each element a constant number of times . . . . . . . . . . . . . . 6 Reshaping arrays 6.1 Subdividing 2D matrix . . . . . . . . . . . . . . . . . . 6.1.1 Create 4D array . . . . . . . . . . . . . . . . . . 6.1.2 Create 3D array (columns rst) . . . . . . . . . . 6.1.3 Create 3D array (rows rst) . . . . . . . . . . . 6.1.4 Create 2D matrix (columns rst, column output) 6.1.5 Create 2D matrix (columns rst, row output) . . 6.1.6 Create 2D matrix (rows rst, column output) . . 6.1.7 Create 2D matrix (rows rst, row output) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
7 . 7 . 7 . 8 . 8 . 9 . 9 . 10 . 10 . . . . . . . . . . . . . 11 11 11 11 12 12 14 15 16 17 18 19 19 19
7 Rotating matrices and arrays 7.1 Rotating 2D matrices . . . . . . . . . . . . . . . . . . . . . 7.2 Rotating ND arrays . . . . . . . . . . . . . . . . . . . . . . 7.3 Rotating ND arrays around an arbitrary axis . . . . . . . . . 7.4 Block-rotating 2D matrices . . . . . . . . . . . . . . . . . . 7.4.1 Inner vs outer block rotation . . . . . . . . . . . 7.4.2 Inner block rotation 90 degrees counterclockwise . 7.4.3 Inner block rotation 180 degrees . . . . . . . . . . 7.4.4 Inner block rotation 90 degrees clockwise . . . . . 7.4.5 Outer block rotation 90 degrees counterclockwise 7.4.6 Outer block rotation 180 degrees . . . . . . . . . 7.4.7 Outer block rotation 90 degrees clockwise . . . . 7.5 Blocktransposing a 2D matrix . . . . . . . . . . . . . . . . 7.5.1 Inner blocktransposing . . . . . . . . . . . . . . .
1 INTRODUCTION
7.5.2
Outer blocktransposing . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20 20 20 20 20 21 21 21 22
8 Multiply arrays 8.1 Multiply each 2D slice with the same matrix (element-by-element) 8.2 Multiply each 2D slice with the same matrix (left) . . . . . . . . . 8.3 Multiply each 2D slice with the same matrix (right) . . . . . . . . 8.4 Multiply matrix with every element of a vector . . . . . . . . . . 8.5 Multiply each 2D slice with corresponding element of a vector . . 8.6 Outer product of all rows in a matrix . . . . . . . . . . . . . . . . 8.7 Keeping only diagonal elements of multiplication . . . . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
9 Divide arrays 22 9.1 Divide each 2D slice with the same matrix (element-by-element) . . . . . . . . . . . 22 9.2 Divide each 2D slice with the same matrix (left) . . . . . . . . . . . . . . . . . . . . 22 9.3 Divide each 2D slice with the same matrix (right) . . . . . . . . . . . . . . . . . . . 22 10 Calculating distances 10.1 Euclidean distance . . . . . . . . . . . . . . 10.2 Distance between two points . . . . . . . . . 10.3 Euclidean distance vector . . . . . . . . . . . 10.4 Euclidean distance matrix . . . . . . . . . . . 10.5 Special case when both matrices are identical 10.6 Mahalanobis distance . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23 23 23 23 24 24 24 25 25 26 26 26 26 27 27 27 27 27 27 28 29 30 30 30
11 Statistics, probability and combinatorics 11.1 Discrete uniform sampling with replacement . . 11.2 Discrete weighted sampling with replacement . 11.3 Discrete uniform sampling without replacement 11.4 Combinations . . . . . . . . . . . . . . . . . . 11.4.1 Counting combinations . . . . . . . . . 11.4.2 Generating combinations . . . . . . . . 11.5 Permutations . . . . . . . . . . . . . . . . . . 11.5.1 Counting permutations . . . . . . . . . 11.5.2 Generating permutations . . . . . . . . 12 Miscellaneous 12.1 Creating index vector from index limits 12.2 Matrix with different incremental runs . 12.3 Finding indexes . . . . . . . . . . . . . 12.4 Run-length encoding and decoding . . . 12.4.1 Run-length encoding . . . . . . 12.4.2 Run-length decoding . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . .
. . . . . . . . . . . . . . .
. . . . . . . . . . . . . . .
. . . . . . . . . . . . . . .
. . . . . . . . . . . . . . .
. . . . . . . . . . . . . . .
. . . . . . . . . . . . . . .
. . . . . . . . . . . . . . .
. . . . . . . . . . . . . . .
. . . . . . . . . . . . . . .
. . . . . . . . . . . . . . .
. . . . . . . . . . . . . . .
. . . . . . . . . . . . . . .
. . . . . . . . . . . . . . .
. . . . . . . . . . . . . . .
. . . . . . . . . . . . . . .
. . . . . . . . . . . . . . .
. . . . . . . . . . . . . . .
. . . . . . . . . . . . . . .
. . . . . . . . . . . . . . .
1 Introduction
1.1 Background
Since the early 1990s I have been following the discussions in the main M ATLAB newsgroup on Usenet, comp.soft-sys.matlab. I realized that many postings there were about how to ma-
nipulate arrays efciently. I decided to start collecting what I thought was the most interestings solutions and see if I could compile them into one document. Well, this is it.
1.2 Vectorization
The term vectorization is frequently associated with M ATLAB. Strictly speaking, it means to rewrite code so that, in stead of using a for-loop iterating over each scalar in an array, one takes advantage of M ATLABs vectorization capabilities and does everything in one go. For instance, the 5 lines
x = [ 1 2 3 4 5 ]; y = zeros(size(x)); for i = 1:5 y(i) = x(i)^2; end
which is faster, most compact, and easier to read. With this rather strict denition of vectorization, vectorized code is always faster than non-vectorized code. Some people use the term vectorization in the sense removing any for-loop, but I will stick to the former, more strict denition.
1.5 Errors/Feedback
If you nd errors or have suggestions for improvements or if there is anything you think should be here but is not, please mail me and I will see what I can do. My address is on the front page of this document.
at the command prompt and take a look at the list of operators, functions and special characters, and look at the associated help pages. When manipulating arrays in M ATLAB there are some operators and functions that are particularely useful.
2.1 Operators
: . The colon operator. Type help colon for more information. Non-conjugate transpose. Type help transpose for more information. Complex conjugate transpose. Type help ctranspose for more information.
4 SHIFTING
If step is not a multiple of the difference upper-lower, the last element of X, X(end), will be less than upper. So the condition A(end) <= upper is always satised.
4 Shifting
4.1 Vectors
To shift and rotate the elements of a vector, use
X([ X([ X([ X([ end 1:end-1 ]); end-k+1:end 1:end-k ]); 2:end 1 ]); k+1:end 1:k ]); % % % % shift shift shift shift right/down 1 element right/down k elements left/up 1 element left/up k elements
Note that these only work if k is non-negative. If k is an arbitrary integer one may use something like
X( mod((1:end)-k-1, end)+1 ); X( mod((1:end)+k-1, end)+1 ); % shift right/down k elements % shift left/up k element
4.2 Arrays
To shift and rotate the elements of an array X along dimension dim, rst initialize a subscript cell array with
idx = repmat({:}, ndims(X), 1); % initialize subscripts n = size(X, dim); % length along dimension dim
6 RESHAPING ARRAYS
The repmat solution might in some cases be slighly slower, but it has several advantages. Firstly, it uses less memory. Seconly, it also works if val is a function returning a scalar value, e.g., if val is Inf or NaN:
X = NaN(ones(siz)); X = repmat(NaN, siz); % wont work unless NaN is a variable % this works
Avoid using
X = val * ones(siz);
since it does unnecessary multiplications and only works if val is of class double.
If A is a column-vector, use
B = A(:,ones(1,N)).; B = B(:);
but this requires unnecessary arithmetic. The only advantage is that it works regardless of whether A is a row or column vector.
6 Reshaping arrays
6.1 Subdividing 2D matrix
Assume X is an m-by-n matrix. 6.1.1 Create 4D array To create a p-by-q-by-m/p-by-n/q array Y where the i,j submatrix of X is Y(:,:,i,j), use
Y = reshape( X, [ p m/p q n/q ] ); Y = permute( Y, [ 1 3 2 4 ] );
Now,
6 RESHAPING ARRAYS
X = [
6.1.2 Create 3D array (columns rst) Assume you want to create a p-by-q-by-m*n/(p*q) array Y where the i,j submatrix of X is Y(:,:,i+(j-1)*m/p). E.g., if A, B, C and D are p-by-q matrices, convert
X = [ A B C D ];
into
Y = cat( 3, A, C, B, D );
use
Y = reshape( X, [ p m/p q n/q ] ); Y = permute( Y, [ 1 3 2 4 ] ); Y = reshape( Y, [ p q m*n/(p*q) ] )
Now,
X = [ Y(:,:,1) Y(:,:,m/p+1) ... Y(:,:,(n/q-1)*m/p+1) Y(:,:,2) Y(:,:,m/p+2) ... Y(:,:,(n/q-1)*m/p+2) ... ... ... ... Y(:,:,m/p) Y(:,:,2*m/p) ... Y(:,:,n/q*m/p) ];
6.1.3 Create 3D array (rows rst) Assume you want to create a p-by-q-by-m*n/(p*q) array Y where the i,j submatrix of X is Y(:,:,j+(i-1)*n/q). E.g., if A, B, C and D are p-by-q matrices, convert
X = [ A B C D ];
into
Y = cat( 3, A, B, C, D );
use
Y = reshape( X, [ p m/p n ] ); Y = permute( Y, [ 1 3 2 ] ); Y = reshape( Y, [ p q m*n/(p*q) ] );
6 RESHAPING ARRAYS
Now,
X = [ Y(:,:,1) Y(:,:,2) Y(:,:,n/q+1) Y(:,:,n/q+2) ... ... Y(:,:,(m/p-1)*n/q+1) Y(:,:,(m/p-1)*n/q+2) ... Y(:,:,n/q) ... Y(:,:,2*n/q) ... ... ... Y(:,:,m/p*n/q) ];
6.1.4 Create 2D matrix (columns rst, column output) Assume you want to create a m*n/q-by-q matrix Y where the submatrices of X are concatenated (columns rst) vertically. E.g., if A, B, C and D are p-by-q matrices, convert
X = [ A B C D ];
into
Y = [ A C B D ];
use
Y = reshape( X, [ m q n/q ] ); Y = permute( Y, [ 1 3 2 ] ); Y = reshape( Y, [ m*n/q q ] );
6.1.5 Create 2D matrix (columns rst, row output) Assume you want to create a p-by-m*n/p matrix Y where the submatrices of X are concatenated (columns rst) horizontally. E.g., if A, B, C and D are p-by-q matrices, convert
X = [ A B C D ];
into
Y = [ A C B D ];
use
Y = reshape( X, [ p m/p q n/q ] ) Y = permute( Y, [ 1 3 2 4 ] ); Y = reshape( Y, [ p m*n/p ] );
6 RESHAPING ARRAYS
10
6.1.6 Create 2D matrix (rows rst, column output) Assume you want to create a m*n/q-by-q matrix Y where the submatrices of X are concatenated (rows rst) vertically. E.g., if A, B, C and D are p-by-q matrices, convert
X = [ A B C D ];
into
Y = [ A B C D ];
use
Y = reshape( X, [ p m/p q n/q ] ); Y = permute( Y, [ 1 4 2 3 ] ); Y = reshape( Y, [ m*n/q q ] );
6.1.7 Create 2D matrix (rows rst, row output) Assume you want to create a p-by-m*n/p matrix Y where the submatrices of X are concatenated (rows rst) horizontally. E.g., if A, B, C and D are p-by-q matrices, convert
X = [ A B C D ];
into
Y = [ A B C D ];
use
Y = reshape( X, [ p m/p n ] ); Y = permute( Y, [ 1 3 2 ] ); Y = reshape( Y, [ p m*n/p ] );
11
Rotating 90 clockwise
s v Y Y = = = = size(X); % size vector [ 2 1 3:ndims(X) ]; % dimension permutation vector reshape( X(s(1):-1:1,:), s ); permute( Y, v );
12
If we want to rotate n*90 degrees counterclockwise, we may merge the three cases above into
% Largest dimension number we have to deal with. nd = max( [ ndims(A) dim1 dim2 ] ); % Initialize subscript cell array. v = {:}; v = v(ones(nd,1)); % Flip along appropriate dimensions. if n == 1 | n == 2 v{dim2} = size(A,dim2):-1:1; end if n == 2 | n == 3 v{dim1} = size(A,dim1):-1:1; end B = A(v{:}); % Permute dimensions if appropriate. if n == 1 | n == 3 d = 1:nd; d([ dim1 dim2 ]) = [ dim2 dim1 ]; B = permute( A, d ); end
13
Inner block rotation is a rotation of the elements within each block, preserving the position of each block within the array. Outer block rotation rotates the blocks but does not change the position of the elements within each block. An example will illustrate: An inner block rotation 90 degrees counterclockwise will have the following effect
[ A B C D E F G H I ] => [ rot90(A) rot90(B) rot90(C) rot90(D) rot90(E) rot90(F) rot90(G) rot90(H) rot90(I) ]
However, an outer block rotation 90 degrees counterclockwise will have the following effect
[ A B C D E F G H I ] => [ C F I B E H A D G ]
In all the examples below, it is assumed that X is an m-by-n matrix of p-by-q blocks.
14
7.4.2 Inner block rotation 90 degrees counterclockwise General case To perform the rotation
X = [ A B ... C D ... ... ... ] => [ rot90(A) rot90(B) ... rot90(C) rot90(D) ... ... ... ... ]
use
Y Y Y Y = = = = reshape( X, [ p m/p q n/q ] ); Y(:,:,q:-1:1,:); permute( Y, [ 3 2 1 4 ] ); reshape( Y, [ q*m/p p*n/q ] ); % or Y = Y(:,:,end:-1:1,:);
use
Y Y Y Y = = = = reshape( X, [ p q n/q ] ); Y(:,q:-1:1,:); permute( Y, [ 2 1 3 ] ); reshape( Y, [ q m*n/q ] ); % or Y = Y(:,end:-1:1,:); % or Y = Y(:,:);
use
Y Y Y Y = = = = X(:,q:-1:1); reshape( Y, [ p m/p q ] ); permute( Y, [ 3 2 1 ] ); reshape( Y, [ q*m/p p ] ); % or Y = X(:,end:-1:1);
15
7.4.3 Inner block rotation 180 degrees General case To perform the rotation
X = [ A B ... C D ... ... ... ] => [ rot90(A,2) rot90(B,2) ... rot90(C,2) rot90(D,2) ... ... ... ... ]
use
Y = reshape( X, [ p m/p q n/q ] ); Y = Y(p:-1:1,:,q:-1:1,:); Y = reshape( Y, [ m n ] ); % or Y = Y(end:-1:1,:,end:-1:1,:);
use
Y = reshape( X, [ p q n/q ] ); Y = Y(p:-1:1,q:-1:1,:); Y = reshape( Y, [ m n ] ); % or Y = Y(end:-1:1,end:-1:1,:); % or Y = Y(:,:);
use
Y = reshape( X, [ p m/p q ] ); Y = Y(p:-1:1,:,q:-1:1); Y = reshape( Y, [ m n ] ); % or Y = Y(end:-1:1,:,end:-1:1);
16
7.4.4 Inner block rotation 90 degrees clockwise General case To perform the rotation
X = [ A B ... C D ... ... ... ] => [ rot90(A,3) rot90(B,3) ... rot90(C,3) rot90(D,3) ... ... ... ... ]
use
Y Y Y Y = = = = reshape( X, [ p m/p q n/q ] ); Y(p:-1:1,:,:,:); permute( Y, [ 3 2 1 4 ] ); reshape( Y, [ q*m/p p*n/q ] ); % or Y = Y(end:-1:1,:,:,:);
use
Y Y Y Y = = = = X(p:-1:1,:); reshape( Y, [ p q n/q ] ); permute( Y, [ 2 1 3 ] ); reshape( Y, [ q m*n/q ] ); % or Y = X(end:-1:1,:);
% or Y = Y(:,:);
use
Y Y Y Y = = = = reshape( X, [ p m/p q ] ); Y(p:-1:1,:,:); permute( Y, [ 3 2 1 ] ); reshape( Y, [ q*m/p p ] ); % or Y = Y(end:-1:1,:,:);
17
7.4.5 Outer block rotation 90 degrees counterclockwise General case To perform the rotation
X = [ A B ... C D ... ... ... ] => [ ... ... B D ... A C ... ]
use
Y Y Y Y = = = = reshape( X, [ p m/p q n/q ] ); Y(:,:,:,n/q:-1:1); permute( Y, [ 1 4 3 2 ] ); reshape( Y, [ p*n/q q*m/p ] ); % or Y = Y(:,:,:,end:-1:1);
use
Y Y Y Y = = = = reshape( X, [ p q n/q ] ); Y(:,:,n/q:-1:1); permute( Y, [ 1 3 2 ] ); reshape( Y, [ m*n/q q ] ); % or Y = Y(:,:,end:-1:1);
use
Y = reshape( X, [ p m/p q ] ); Y = permute( Y, [ 1 3 2 ] ); Y = reshape( Y, [ p n*m/p ] );
% or Y(:,:);
18
7.4.6 Outer block rotation 180 degrees General case To perform the rotation
X = [ A B ... C D ... ... ... ] [ => ... ... ... D C ... B A ]
use
Y = reshape( X, [ p m/p q n/q ] ); Y = Y(:,m/p:-1:1,:,n/q:-1:1); % or Y = Y(:,end:-1:1,:,end:-1:1); Y = reshape( Y, [ m n ] );
use
Y = reshape( X, [ p q n/q ] ); Y = Y(:,:,n/q:-1:1); Y = reshape( Y, [ m n ] ); % or Y = Y(:,:,end:-1:1); % or Y = Y(:,:);
use
Y = reshape( X, [ p m/p q ] ); Y = Y(:,m/p:-1:1,:); Y = reshape( Y, [ m n ] ); % or Y = Y(:,end:-1:1,:);
19
7.4.7 Outer block rotation 90 degrees clockwise General case To perform the rotation
X = [ A B ... C D ... ... ... ] => [ ... C A ... D B ... ... ]
use
Y Y Y Y = = = = reshape( X, [ p m/p q n/q ] ); Y(:,m/p:-1:1,:,:); permute( Y, [ 1 4 3 2 ] ); reshape( Y, [ p*n/q q*m/p ] ); % or Y = Y(:,end:-1:1,:,:);
use
Y = reshape( X, [ p q n/q ] ); Y = permute( Y, [ 1 3 2 ] ); Y = reshape( Y, [ m*n/q q ] );
use
Y Y Y Y = = = = reshape( X, [ p m/p q ] ); Y(:,m/p:-1:1,:); permute( Y, [ 1 3 2 ] ); reshape( Y, [ p n*m/p ] ); % or Y = Y(:,end:-1:1,:);
use
Y = reshape( X, [ p m/p q n/q ] ); Y = permute( Y, [ 3 2 1 4 ] ); Y = reshape( Y, [ q*m/p p*n/q ] );
8 MULTIPLY ARRAYS
20
7.5.2 Outer blocktransposing Assume X is an m-by-n matrix and you want to subdivide it into p-by-q submatrices and transpose as if each block was an element. E.g., if A, B, C and D are p-by-q matrices, convert
X = [ A B ... C D ... ... ... ] => [ A C ... B D ... ... ... ]
use
Y = reshape( X, [ p m/p q n/q ] ); Y = permute( Y, [ 1 4 3 2 ] ); Y = reshape( Y, [ p*n/q q*m/p] );
8 Multiply arrays
8.1 Multiply each 2D slice with the same matrix (element-by-element)
Assume X is an m-by-n-by-p-by-q-by-. . . array and Y is an m-by-n matrix and you want to construct a new m-by-n-by-p-by-q-by-. . . array Z, where
Z(:,:,i,j,...) = X(:,:,i,j,...) .* Y;
for all i=1,...,p, j=1,...,q, etc. This can be done with nested for-loops, or by the following vectorized code
sx = size(X); Z = X .* repmat(Y, [1 1 sx(3:end)]);
for all i=1,...,p, j=1,...,q, etc. This can be done with nested for-loops, or by the following vectorized code
sx = size(X); sy = size(Y); Z = reshape(Y * X(:,:), [sy(1) sx(2:end)]);
for all i=1,...,p, j=1,...,q, etc. This can be done with nested for-loops, or by the following vectorized code
8 MULTIPLY ARRAYS
21
sx sy dx Xt Z2 Z2
= = = = = =
size(X); size(Y); ndims(X); reshape(permute(X, [1 3:dx 2]), [prod(sx)/sx(2) sx(2)]); Xt * Y; permute(reshape(Z2, [sx([1 3:dx]) sy(2)]), [1 dx 2:dx-1]);
The third line above builds a 2D matrix which is a vertical concatenation (stacking) of all 2D slices X(:,:,i,j,...). The fourth line does the actual multiplication. The fth line does the opposite of the third line.
a non-for-loop solution is
j = 1:n; Y = reshape(repmat(X, n, 1) .* X(:,j(ones(n, 1),:))., [n n m]);
Note the use of the non-conjugate transpose in the second factor to ensure that it works correctly also for complex matrices.
9 DIVIDE ARRAYS
22
Solution (1) does a lot of unnecessary work, since we only keep the n diagonal elements of the n2 computed elements. Solution (2) only computes the elements of interest and is signicantly faster if n is large.
9 Divide arrays
9.1 Divide each 2D slice with the same matrix (element-by-element)
Assume X is an m-by-n-by-p-by-q-by-. . . array and Y is an m-by-n matrix and you want to construct a new m-by-n-by-p-by-q-by-. . . array Z, where
Z(:,:,i,j,...) = X(:,:,i,j,...) ./ Y;
for all i=1,...,p, j=1,...,q, etc. This can be done with nested for-loops, or by the following vectorized code
sx = size(X); Z = X./repmat(Y, [1 1 sx(3:end)]);
for all i=1,...,p, j=1,...,q, etc. This can be done with nested for-loops, or by the following vectorized code
Z = reshape(Y\X(:,:), size(X));
for all i=1,...,p, j=1,...,q, etc. This can be done with nested for-loops, or by the following vectorized code
10 CALCULATING DISTANCES
23
sx = size(X); dx = ndims(X); Xt = reshape(permute(X, [1 3:dx 2]), [prod(sx)/sx(2) sx(2)]); Z = Xt/Y; Z = permute(reshape(Z, sx([1 3:dx 2])), [1 dx 2:dx-1]);
The third line above builds a 2D matrix which is a vertical concatenation (stacking) of all 2D slices X(:,:,i,j,...). The fourth line does the actual division. The fth line does the opposite of the third line. The ve lines above might be simplied a little by introducing a dimension permutation vector
sx = size(X); dx = ndims(X); v = [1 3:dx 2]; Xt = reshape(permute(X, v), [prod(sx)/sx(2) sx(2)]); Z = Xt/Y; Z = ipermute(reshape(Z, sx(v)), v);
If you dont care about readability, this code may also be written as
sx = size(X); dx = ndims(X); v = [1 3:dx 2]; Z = ipermute(reshape(reshape(permute(X, v), ... [prod(sx)/sx(2) sx(2)])/Y, sx(v)), v);
10 Calculating distances
10.1 Euclidean distance
The Euclidean distance from xi to y j is
di j
xi
yj
xi
yj
x1i
y1 j
x pi
yp j
10 CALCULATING DISTANCES
24
The following code inlines the call to repmat, but requires to temporary variables unless one doesnt mind changing X and Y
Xt = permute(X, [1 3 2]); Yt = permute(Y, [3 1 2]); D = sqrt(sum(abs( Xt( :, ones(1, n), : ) ... - Yt( ones(1, m), :, : ) ).^2, 3));
One might want to take advantage of the fact that D will be symmetric. The following code rst creates the indexes for the upper triangular part of D. Then it computes the upper triangular part of D and nally lets the lower triangular part of D be a mirror image of the upper triangular part.
[ i j ] = find(triu(ones(m), 1)); % Trick to get indices. D = zeros(m, m); % Initialise output matrix. D( i + m*(j-1) ) = sqrt(sum(abs( X(i,:) - X(j,:) ).^2, 2)); D( j + m*(i-1) ) = D( i + m*(j-1) );
where nx
Assume Y is an ny-by-p matrix containing a set of vectors and X is an nx-by-p matrix containing another set of vectors, then the Mahalanobis distance from each vector Y(j,:) (for j=1,...,ny) to the set of vectors in X can be calculated with
nx = size(X, 1); % size of set in X ny = size(Y, 1); % size of set in Y m = mean(X); C = cov(X); d = zeros(ny, 1); for j = 1:ny d(j) = (Y(j,:) - m) / C * (Y(j,:) - m); end
1 n xi nx i 1
and
d2 j
yj
x Cx
yj
x
nx
Cx
1 i 1
xi
x xi
25
which is computed more efciently with the following code which does some inlining of functions (mean and cov) and vectorization
nx = size(X, 1); ny = size(Y, 1); m Xc C Yc d = = = = = sum(X, 1)/nx; X - m(ones(nx,1),:); (Xc * Xc)/(nx - 1); Y - m(ones(ny,1),:); sum(Yc/C.*Yc, 2)); % size of set in X % size of set in Y % % % % % centroid (mean) distance to centroid of X variance matrix distance to centroid of X Mahalanobis distances
The call to conj is to make sure it also works for the complex case. The call to real is to remove numerical noise. The Statistics Toolbox contains the function mahal for calculating the Mahalanobis distances, but mahal computes the distances by doing an orthogonal-triangular (QR) decomposition of the matrix C. The code above returns the same as d = mahal(Y, X). Special case when both matrices are identical If Y and X are identical in the code above, the code may be simplied somewhat. The for-loop solution becomes
n = m = C = d = for end size(X, 1); % size of set in X mean(X); cov(X); zeros(n, 1); j = 1:n d(j) = (Y(j,:) - m) / C * (Y(j,:) - m);
again, to make it work in the complex case, the last line must be written as
d = real(sum(c/C.*conj(c), 2)); % Mahalanobis distances
26
Note that the number of times through the loop depends on the number of probabilities and not the sample size, so it should be quite fast even for large samples.
11.4 Combinations
Combinations is what you get when you pick k elements, without replacement, from a sample of size n, and consider the order of the elements to be irrelevant. 11.4.1 Counting combinations
The number of ways to pick k elements, without replacement, from a sample of size n is is calculate with
c = nchoosek(n, k);
n k
which
which may overow. Unfortunately, both n and k have to be scalars. If n and/or k are vectors, one may use the fact that
where the round is just to remove any numerical noise that might have been introduced by gammaln and exp.
n k
n! k! n k !
n 1 1n k
12 MISCELLANEOUS
27
11.4.2 Generating combinations To generate a matrix with all possible combinations of n elements taken k at a time, one may use the M ATLAB function nchoosek. That function is rather slow compared to the choosenk function which is a part of Mike Brookes Voicebox (Speech recognition toolbox) whose homepage is at http://www.ee.ic.ac.uk/hp/staff/dmb/voicebox/voicebox.html For the special case of generating all combinations of n elements taken 2 at a time, there is a neat trick
[ x(:,2) x(:,1) ] = find(tril(ones(n), -1));
11.5 Permutations
11.5.1 Counting permutations
p = prod(n-k+1:n);
11.5.2 Generating permutations To generate a matrix with all possible permutations of n elements, one may use the function perms. That function is rather slow compared to the permutes function which is a part of Mike Brookes Voicebox (Speech recognition toolbox) whose homepage is at http://www.ee.ic.ac.uk/hp/staff/dmb/voicebox/voicebox.html
12 Miscellaneous
This section contains things that dont t anywhere else.
which unfortunately requires a lot of memory copying since a new x has to be allocated each time through the loop. A better for-loop solution is one that allocates the required space and then lls in the elements afterwards. This for-loop solution above may be several times faster than the rst one
m d n c = = = = length(lo); hi - lo + 1; sum(d); cumsum(d); % % % % length of input vectors length of each "run" length of output vector last index in each run
x = zeros(1, n);
12 MISCELLANEOUS
28
Neither of the for-loop solutions above can compete with the the solution below which has no forloops. It uses cumsum rather than the : to do the incrementing in each run and may be many times faster than the for-loop solutions above.
m = length(lo); d = hi - lo + 1; n = sum(d); % length of input vectors % length of each "run" % length of output vector
If fails, however, if lo(i)>hi(i) for any i. Such a case will create an empty vector anyway, so the problem can be solved by a simple pre-processing step which removing the elements for which lo(i)>hi(i)
i = lo <= hi; lo = lo(i); hi = hi(i);
There also exists a one-line solution which is clearly compact, but not as fast as the no-for-loop solution above
x = eval([[ sprintf(%d:%d,, [lo ; hi]) ]]);
How does one create the matrix where the ith column contains the vector 1:a(i) possibly padded with zeros:
b = [ 1 2 3 0 1 2 0 0 1 2 3 4 ];
12 MISCELLANEOUS
29
or
m = max(a); aa = a(:); aa = aa(:,ones(m, 1)); bb = 1:m; bb = bb(ones(length(a), 1),:); b = bb .* (bb <= aa);
or
m = size(x, 1); j = zeros(m, 1); for i = 1:m k = [ 0 find(x(i,:) ~= 0) ]; j(i) = k(end); end
12 MISCELLANEOUS
30
12.4.2 Run-length decoding Given the run-length vector l and the value vector v, one may create the full vector x by using
i = cumsum([ 1 l ]); j = zeros(1, i(end)-1); j(i(1:end-1)) = 1; x = v(cumsum(j));