Generate every binary n x m matrix in matlab - matlab

I'd like to generate every boolean matrix in matlab as a 3-dimensional array.
For example:
mat(:,:,1) = [[1 0][0 1]]
mat(:,:,2) = [[1 1][0 1]]
...
My final goal is to generate every trinary matrix of a given size.
Keep in mind that I know that the number of matrices is exponential, but I'll use small numbers.

Not sure that the previous answer actually does what you want... With that method, I get multiple entries in array2D that are the same. Here is a vectorised and (I believe) correct solution:
clear all;
nRows = 2;
nCols = nRows; % Only works for square matrices
% Generate matrix of all binary numbers that fit in nCols
max2Pow = nCols;
maxNum = 2 ^ max2Pow - 1;
allBinCols = bsxfun(#bitand, (0:maxNum)', 2.^((max2Pow-1):-1:0)) > 0;
% Get the indices of the rows in this matrix required for each output
% binary matrix
N = size(allBinCols, 1);
A = repmat({1:N}, nCols, 1);
[B{1:nCols}] = ndgrid(A{:});
rowInds = reshape(cat(3, B{:}), [], nCols)';
% Get the appropriate rows and reshape to a 3D array of right size
nMats = size(rowInds, 2);
binMats = reshape(allBinCols(rowInds(:), :)', nRows, nCols, nMats)
Note that for anything other than small numbers of nRows you will run out of memory pretty quickly, because you're generating 2^(nRows*nRows) matrices of size nRows*nRows. ThatsAlottaNumbers.

Actually the answer is pretty straightforward. Each matrix being boolean, it can be indexed by the binary number obtained when reading all the values in any given order.
For a binary matrix: let n be the number of element in your matrix (n = rows * cols).
for d=0:(2^n-1)
%Convert binary to decimal string
str = dec2bin(d);
%Convert string to array
array1D = str - '0';
array1D = [array1D zeros(1, n-length(array1D))];
%Reshape
array2D(:,:,d+1) = reshape(array1D, rows, cols);
end
This can be very easily generalized to any base by changing dec2bin into dec2base and changing 2^n into (yourbase)^n.

Related

MATLAB: Multiply 2D matrix with 3D matrix within cell arrays

I have a constant 2D double matrix mat1. I also have a 2D cell array mat2 where every cell contains a 2D or 3D double matrix. These double matrices have the same number of rows and columns as mat1. I need to dot multiply (.*) mat1 with every slice of each double matrix within mat2. The result needs to be another cell array results with the same size as mat2, whereby the contatining double matrices must equal the double matrices of mat2 in terms of size.
Here's my code to generate mat1 and mat2 for illustrating purposes. I am struggling at the point where the multiplication should take place.
rowCells = 5;
colCells = 3;
rowTimeSeries = 300;
colTimeSeries = 5;
slices = [1;10];
% Create 2D double matrix
mat1 = rand(rowTimeSeries, colTimeSeries);
% Create 2D cell matrix comprisiong 2D and/or 3D double matrices
mat2 = cell(rowCells,colCells);
for c = 1:colCells
for r = 1:rowCells
slice = randsample(slices, 1, true);
mat2{r,c} = rand(rowTimeSeries, colTimeSeries, slice);
end
end
% Multiply (.*) mat1 with mat2 (every slice)
results = cell(rowCells,colCells);
for c = 1:colCells
for r = 1:rowCells
results{r,c} = ... % I am struggling here!!!
end
end
You could use bsxfun to remove the need for your custom function multiply2D3D, it works in a similar way! Updated code:
results = cell(rowCells,colCells);
for c = 1:colCells
for r = 1:rowCells
results{r,c} = bsxfun(#times, mat1, mat2{r,c});
end
end
This will work for 2D and 3D matrices where the number of rows and cols is the same in each of your "slices", so it should work in your case.
You also don't need to loop over the rows and the columns of your cell array separately. This loop has the same number of iterations, but it is one loop not two, so the code is a little more streamlined:
results = cell(size(mat2));
for n = 1:numel(mat2) % Loop over every element of mat2. numel(mat2) = rowCells*colCells
results{n} = bsxfun(#times, mat1, mat2{n});
end
I had almost the exact same answer as Wolfie but he beat me to it.
Anyway, here is a one liner that I think is slightly nicer:
nR = rowCells; % Number of Rows
nC = colCells; % Number of Cols
results = arrayfun(#(I) bsxfun(#times, mat1, mat2{I}), reshape(1:nR*nC,[],nC), 'un',0);
This uses arrayfun to perform the loop indexing and bsxfun for the multiplications.
A few advantages
1) Specifying 'UniformOutput' ('un') in arrayfun returns a cell array so the results variable is also a cell array and doesn't need to be initialised (in contrast to using loops).
2) The dimensions of the indexes determine the dimensions of results at the output, so they can match what you like.
3) The single line can be used directly as an input argument to a function.
Disadvantage
1) Can run slower than using for loops as Wolfie pointed out in the comments.
One solution I came up with is to outsource the multiplication of a 2D with a 3D matrix into a function. However, I am curious to know whether this is the most efficient way to solve this problem?
rowCells = 5;
colCells = 3;
rowTimeSeries = 300;
colTimeSeries = 5;
slices = [1;10];
% Create 2D double matrix
mat1 = rand(rowTimeSeries, colTimeSeries);
% Create 2D cell matrix comprisiong 2D and/or 3D double matrices
mat2 = cell(rowCells,colCells);
for c = 1:colCells
for r = 1:rowCells
slice = randsample(slices, 1, true);
mat2{r,c} = rand(rowTimeSeries, colTimeSeries, slice);
end
end
% Multiply (.*) mat1 with mat2 (every slice)
results = cell(rowCells,colCells);
for c = 1:colCells
for r = 1:rowCells
results{r,c} = multiply2D3D(mat1, mat2{r,c});
end
end
function vout = multiply2D3D(mat2D, mat3D)
%MULTIPLY2D3D multiplies a 2D double matrix with every slice of a 3D
% double matrix.
%
% INPUTs:
% mat2D:
% 2D double matrix
%
% mat3D:
% 3D double matrix where the third dimension is equal or greater than 1.
%
% OUTPUT:
% vout:
% 3D double matrix with the same size as mat3D. Every slice in vout
% is the result of a multiplication of mat2D with every individual slice
% of mat3D.
[rows, cols, slices] = size(mat3D);
vout = zeros(rows, cols, slices);
for s = 1 : slices
vout(:,:,s) = mat2D .* mat3D(:,:,s);
end
end

Matlab: store array in matrix?

I have many array (n*1 dimension), how can I do something like
matrix = [];
for i = 1:5
for j =1:5
matrix (i,j) = zeros(n,1); % store a given array to a cell of a matrix
end
end
I find Array of Matrices in MATLAB
But this is store matrices into array, not the otherwise.
Ying Xiong's suggestion is what you want if the vectors are of different lengths. But assuming the number of elements is constant (which they seem to be) you may also use a 3-dimensional array, where each (i,j) element contains a vector in the third dimension, like this:
rows = 5; cols = 5; n = 10; %// Dimensions
matrix = zeros(rows, cols, n); %// Initialize matrix
vector = 1:n; %// Just an example
for ii = 1:rows %// Bad practice to use i as a variable name
for jj = 1:cols %// Bad practice to use j as a variable name
matrix(ii,jj,:) = vector; %// Assignment
end
end
Now each index (i,j) contains the vectors you want, for instance:
squeeze(matrix(1,1,:))
ans =
1
2
3
4
5
6
7
8
9
10
Having all values in a single matrix can be a good thing if you want to do similar operations on all elements, as vectorized approaches are usually very fast in MATLAB. You might want to check out permute, reshape and functions like bsxfun.
Note that you might be able to vectorize the loops, but without knowing the specifics, that's impossible to know.
You need to use cell array.
n = 10;
matrix = cell(5,5);
for i = 1:5
for j = 1:5
matrix{i,j} = zeros(n,1);
end
end

Linear index of the maximum of a multi-dimensional matrix - MATLAB

Let's say I have a 3-dimensional matrix and have computed the max along the second dimension, and want to get the linear indices of the max values. However, the max-function only returns the subscripts along one dimension.
A = randn([5,5,5]); % Generate random matrix
[M, Ind] = max(A,[],2); % Take the max along dimension 2
How do I transfer the index to linear indexing, such that
M == A(Ind)
becomes true?
My intention for this problem is that I have two multi-dimensional matrices and need to compute the max in the first one. Then, I want to access the values in the second matrix at exactly those positions where I found a max in the first one.
One way is to use sub2ind:
A = randn([5,5,5]);
[M, col] = max(A,[],2);
[m,n,o] = size(A);
dim1 = mod((0:m*o-1)', m)+1;
dim2 = col(:);
dim3 = ceil((1:m*o)/m)';
ind = sub2ind(size(A), dim1, dim2, dim3)
verify it works with
isequal(M(:), A(ind))
to get them to have the same shape as M:
reshape(ind, m, 1, o)
Create the indices for the other dimensions.
In dim 1 the index needs to change fastest: [1,2,...,size(A,1)] and this size(A,3) times:
idx1 = repmat((1:size(A,1))',size(A,3),1);
In dim 2 the index is given by Ind.
In dim 3 the index need to change slowest: [1,1,...,1] for size(A,1) times and then [2,2,...,2] and so on until size(A,3).
idx3 = ones(size(A,1),1)*(1:size(A,3));
Access single values:
M_ = A(sub2ind(size(A),idx1(:),Ind(:),idx3(:)));
Compare:
M(:) == M_
3-dimensional case:
[m, n, p] = size(A);
[M, Ind] = max(A,[],2);
LinInd = bsxfun(#plus, (1:m).', (0:p-1)*m*n); %'//
LinInd = LinInd(:) + (Ind(:)-1)*m;
The desired linear index is LinInd. This produces
A(LinInd) == M(:)
with all true entries (note you need (:) on the right-hand side so that the comparison makes sense).
General multi-dimensonal case:
d = 3; %// dimension along which max will be computed
s = size(A);
sLow = prod(s(1:d-1));
sHigh = prod(s(d+1:end));
[M, Ind] = max(A,[],d);
LinInd = bsxfun(#plus, (1:sLow).', (0:sHigh-1)*sLow*s(d)); %'//
LinInd = LinInd(:) + (Ind(:)-1)*sLow;
Let's suppose A and B are the two matrices you have and you need to get max indices from A and use those indices to index into B for the desired output. One approach to achieve the same could be like this -
%// Your code to get Ind
A = randn([5,5,5]); % Generate random matrix
[M, Ind] = max(A,[],2); % Take the max along dimension 2
%// ------- Solution code -------------
%// Get the size of A
[n1,n2,n3] = size(A)
%// Linear indices corresponding to column and third dimension indices
col_dim3_lin_idx = bsxfun(#plus,(Ind-1)*n1,permute([0:n3-1]*n1*n2,[1 3 2]))
%// Finally get the overall linear indices
linear_index = bsxfun(#plus,col_dim3_lin_idx,[1:n1]') %//'
%// Get the corresponding elements from B
out = B(linear_index)
Slightly different way to have the desired linear indices as a 2D array would be like this -
[n1,n2,n3] = size(A) %// Get the size of A
idx = bsxfun(#plus,bsxfun(#plus,squeeze((Ind-1)*n1),[0:n3-1]*n1*n2),[1:n1]')
idx(:) would be the column vector of linear indices with this new approach, which you can index into B i.e. B(idx(:)) to have the desired output as a column vector.

Matlab - Generating random coordinates for a matrix

I need to create a list (of size n) of random, non-repeating set of coordinates on a matrix of predefined size.
Is there a fast way to generate this in Matlab?
My initial idea was to create a list of size n with permutations the size of (width x length) and to translate them back to Row and Col values, but it seems to me too much.
Thanks,
Guy
You can use randperm to generate a linear index, and convert it to [row,col] if needed using ind2sub.
x = rand(7,9);
n = 20;
ndx = randperm(numel(x), n);
[row,col] = ind2sub(size(x), ndx);
As long as n is less than the number of elements in the matrix this is simple:
% A is the matrix to be sampled
% N is the number of coordinate pairs you want
numInMat = numel(A);
% sample from 1:N without replacement
ind = randperm(numInMat, N);
% convert ind to Row,Col pairs
[r, c] = ind2sub( size(A), ind )
Your idea is a good one, although you don't even have to convert your linear indices back to row and col indices, you can do linear indexing directly into a 2D array.
idx = randperm(prod(size(data)))
where data is your matrix. This will generate a vector of random integers between 1 and prod(size(data)), i.e. one index for each element.
e.g.
n = 3;
data = magic(n);
idx = randperm(prod(size(data)));
reshape(data(idx), size(data)) %this gives you your randomly indexed data matrix back

Indexing Matrices with two other matrices

I have two large matrices of row numbers and column numbers and a matrix of data. I want to create a matrix where:
output(i,j) = data(row(i,j),col(i,j))
How can I do this quickly?
Let [T, N] = size(Row), and let [DataT, DataN] = size(Data), then a one-line solution is:
Soln = reshape(Data(sub2ind([DataT DataN], Row(:), Col(:))), T, N);
This one-liner looks a bit complicated, so let's break it down step by step in an example case. I've included comments to indicate what is happening with each section:
%# Set fixed parameters for example matrices
T = 3; N = 2;
DataT = 5; DataN = 4;
%# Generate random Data matrix
Data = rand(DataT, DataN);
%# Generate some random subscript index matrices for indexing Data
Row = randi(DataT, T, N);
Col = randi(DataN, T, N);
%# Obtain the linear indices implied by treating Row and Col as subscript matrices
L = sub2ind([DataT DataN], Row(:), Col(:));
%# Use the linear indices to get the data we want
Soln = Data(L);
%# Reshape the data from a vector into matrix of size T by N
Soln = reshape(Soln, T, N);
The standard reference for solving these types of problems is Matrix-Indexing-in-MATLAB