Variable determines matrix dimension - matlab

Assume that I wish to define a matrix but the number of dimension of the matrix is a variable (v) in Matlab.
If v=1, then
M(1:10) = 0;
if v=2, then
M(1:10, 1:10) = 0;
...
I thought about how to use "reshape" to do this but I am scratching my head on how to do this exactly.
Any help would be appreciated.

For arbitrary v, you can use the vector-input form of zeros. Because of how this function works, the input v=1 needs special treatment if you want it to give a row vector (as seems to be the case from your code):
N = 10;
v = 3;
if v==1
sz = [1 N]; % or [N 1] for column vector
else
sz = repmat(N, 1, v);
end
M = zeros(sz);
Equivalently, if you prefer it in a single line:
M = zeros([repmat(1, 1, v==1) repmat(N, 1, v)]); % v=1 gives a row vector
or
M = zeros([repmat(N, 1, v) 1]); % v=1 gives a column vector
The latter works because Matlab arrays have an infinite number of trailing singleton dimensions.

you can do
switch v
case 1
M=zeros(1,10);%matrix of size 1,10
case 2
M=zeros(10,10);%matrix of size 10,10
end

Related

Matlab - Applying a function in a neighborhood

Lets say that I have a 250*250 matrix. What I want to do is select a [3 3] neighborhood around every pixel and apply a function to it. Now the problem is that the function will output a 2*2 matrix for every pixel in the neighborhood and then I have to add the result of every pixel and finally get a 2*2 matrix for the selected pixel. So in the end I will get 62500 2*2 matrices. Also, I have to save the 2*2 matrix for every pixel in a 250*250 cell. Because these matrices will be used for further calculations. So any idea how I go about doing this because I cannot use nfilter or colfilt because in those the function must return a scalar. Any advice or suggestions are highly welcome.
You can use nlfilter with a function that returns a cell so the result will be a cell matrix.:
a = rand(10);
result = nlfilter(a,[3 3],#(x){x(1:2,1:2)});
Here's one pattern of how to do this:
% define matrix
N = 250; % dimensionality
M = rand(N); % random square N-by-N matrix
% initialize output cell array
C = cell(N);
% apply the function (assume the function is called your_function)
for row = 1 : N
for col = 1 : N
% determine a 3x3 neighborhood (if on edge of matrix, 2x2)
row_index = max(1, row - 1) : min(N, row + 1);
col_index = max(1, col - 1) : min(N, col + 1);
neighborhood = mat(row_index, col_index);
% apply the function and save to cell
C{row, col} = your_function(neighborhood);
end
end
And here is a simple example of your_function so you can test the above code:
function mat = your_function(mat)
S = size(mat);
if S(1) < 2 || S(2) < 2, error('Bad input'); end
mat = mat(1:2, 1:2);

Replacing elements in a base matrix by squared permutation submatrices

I have a sparse parity check matrix (consisting of ones and zeros) and I would need to replace each nonzero element (ones) from it by PM: a squared permutation matrix of dimension N (being N generally a large integer). In the case of the zero elements, these would be replaced by squared null matrices of the same dimension.
Let me share with you which the current state of my code is:
This is the base matrix in which I would like to replace its ones by permutation matrices:
B = zeros((L + ms) * dc, L * dv);
for i = 1 : 1 : L
for j = 1 : 1 : dv
B(dc*(i-1)+1 : dc*(ms+i), j+dv*(i-1)) = ones(dc*(ms+1), 1);
end
end
I have been told a way for doing so by using 'cell' objects, this is, initializing H as an array of empty cells that would contain the corresponding submatrices:
H=repmat({{}},size(B));
Mc = 500 % Dimension of the permutation matrix
MP=randi([1,5],Mc,Mc); % Definition of one permutation matrix
% It would be desirable that the permutation matrix is different for each replacement
[H{B==0}]=deal(zeros(Mp));
[H{B==1}]=deal(MP);
But there's one problem coming up -that I would need this matrix to be used as a parameter of a following function and it would be very much desirable that it were a simple matrix of ones and zeros (as I am not very familiar with 'cell' structures... however, as you can see, Mc is such a big integer that I don't know if that would be possible to be handled.
Do you have any other way of doing so to have a raw matrix of dimensions (L*ms)dcMc, LdvMc as output?
These are some parameters that could be used to have a try:
ms = 2;
Mc = 600; % any number (specially big ones) could serve for this purpose
dc = 3;
dv = 4;
L = 15;
Many thanks in advance for your attention, and may you have a nice day.
This is how it can be done with cells:
B = Randi([0,1], m, n); % m*n array of 1s and 0s
H = cell(size(B)); % Define cell array
Mc = 500; % Size of replacement matrices
MP = randi([1,5], Mc, Mc); % Permutation matrix
H(B==0) = {zeros(Mc, Mc)}; % Set elements of H where B==0 to matrix of zeros
H(B==1) = {MP}; % Set elements of H where B==1 to permutation matrix
% Convert to matrix
Hmat = cell2mat(H); % Hmat = Mc*m row by Mc*n column matrix
Each cell element holds a matrix of size Mc*Mc, at the end this can be converted to one large matrix. Take care which sorts of brackets you use with cells, the parentheses () are for logical indexing, whilst the curly braces {} are for assigning the sub-matrixes as cell elements.
Example:
B = [1 0; 1 1];
MP = [1 2; 3 4];
H(B==0) = {zeros(2, 2)};
H(B==1) = {MP};
Hmat = cell2mat(H);
% >> Hmat = [1 2 0 0
% 3 4 0 0
% 1 2 1 2
% 3 4 3 4];
If you want the replacement matrix MP to change, you will have to do this in a loop, changing MP on each iteration and using it to replace one element of H.

How can all dimensions left after the specified one be preserved, without explicitly listing them?

Or equivalently, "what is the equivalent of NumPy's ellipsis indexing in Matlab"
Say I have some high-dimensional array:
x = zeros(3, 4, 5, 6);
I want to write a function that takes an array of size (3, ...), and does some computation. In NumPy, I could write this:
def fun(x):
return x[0]*x[1] + x[2]
However, the equivalent in MATLAB doesn't work, because indexing with one integer flattens the array to 1d
function y = fun_bad(x)
y = x(1)*x(2) + x(3)
I can make this work for up to 3-dimensional arrays with
function y = fun_ok3d(x)
y = x(1,:,:)*x(2,:,:) + x(3,:,:)
If I want this to work for up to 10-dimensional arrays, I can write
function y = fun_ok10d(x)
y = x(1,:,:,:,:,:,:,:,:,:)*x(2,:,:,:,:,:,:,:,:,:) + x(3,:,:,:,:,:,:,:,:,:)
How can I avoid writing stupid numbers of colons here, and just make this work for any dimension? Is there some x(1,...) syntax that implies this?
NumPy can use the ... (Ellipsis) literal in an indexing expression to mean ": as many times as needed", which would solve this problem.
Approach 1: using a comma-separated list with ':'
I don't know a way to specify
: as many times as needed
while preserving shape. But you can specify
: an arbitrary number of times
where that number of times is defined at run-time. With this method you can preserve shape, provided that the number of indices coincides with the number of dimensions.
This is done using a comma-separated list generated from a cell array, and exploiting the fact that the string ':' can be used as an index instead of ::
function y = fun(x)
colons = repmat({':'}, 1, ndims(x)-1); % row cell array containing the string ':'
% repeated the required number of times
y = x(1,colons{:}).*x(2,colons{:}) + x(3,colons{:});
This approach can be easily generalized to indexing along any dimension, not just the first:
function y = fun(x, dim)
% Input argument dim is the dimension along which to index
colons_pre = repmat({':'}, 1, dim-1);
colons_post = repmat({':'}, 1, ndims(x)-dim);
y = x(colons_pre{:}, 1, colons_post{:}) ...
.*x(colons_pre{:}, 2, colons_post{:}) ...
+ x(colons_pre{:}, 3, colons_post{:});
Approach 2: splitting the array
You can split the array along the first dimension using num2cell, and then apply the operation to the resulting subarrays. Of course this uses more memory; and as noted by #Adriaan it is slower.
function y = fun(x)
xs = num2cell(x, [2:ndims(x)]); % x split along the first dimension
y = xs{1}.*xs{2} + xs{3};
Or, for indexing along any dimension:
function y = fun(x, dim)
xs = num2cell(x, [1:dim-1 dim+1:ndims(x)]); % x split along dimension dim
y = xs{1}.*xs{2} + xs{3};
MATLAB flattens all trailing dimensions when using a single colon, so you can use that to get from your N-D array to a 2D array, which you can reshape back into the original N dimensions after the calculation.
Along the first dimension
If you want to use the first dimension you can use a relatively simple and short piece of code:
function y = MyMultiDimensional(x)
x_size = size(x); % Get input size
yflat = x(1,:) .* x(2,:) + x(3,:); % Calculate "flattened" 2D function
y = reshape(yflat, [1 x_size(2:end)]); % Reshape output back to original size
end
Along an arbitrary dimension, now featuring N-D permute.
When you want your function to act along the n-th dimension out of a total of N, you can permute that dimension to the front first:
function y = MyMultiDimensional(x,n)
x_size = size(x); % Get input size
Order = 1:numel(x_size);
Order(n)=[]; % Remove n-th dimension
Order2 = [n, Order]; % Prepend n-th dimension
xPermuted = permute(x,Order2); % permute the n-th dimension to the front
yTmp = xPermuted (1,:) .* xPermuted (2,:) + xPermuted (3,:); % Calculate "flattened" 2D function
y = reshape(yTmp, x_size(Order)); % Reshape output back to original size
end
I timed the results of the two methods of Luis' and my methods:
function timeMultiDim()
x = rand(1e1,1e1,1e1,1e1,1e1,1e1,1e1,1e1);
function y = Luis1(x)
colons = repmat({':'}, 1, ndims(x)-1); % row cell array containing the string ':'
% repeated the required number of times
y = x(1,colons{:}).*x(2,colons{:}) + x(3,colons{:});
end
function y = Luis2(x)
xs = num2cell(x, [2:ndims(x)]); % x split along the first dimension
y = xs{1}.*xs{2} + xs{3};
end
function y = Adriaan(x)
x_size = size(x); % Get input size
yflat = x(1,:) .* x(2,:) + x(3,:); % Calculate "flattened" 2D function
y = reshape(yflat, [1 x_size(2:end)]); % Reshape output back to original size
end
n=1;
function y = Adriaan2(x,n)
x_size = size(x); % Get input size
Order = 1:numel(x_size);
Order(n)=[]; % Remove n-th dimension
Order2 = [n, Order]; % Prepend n-th dimension
xPermuted = permute(x,Order2); % permute the n-th dimension to the front
yTmp = xPermuted (1,:) .* xPermuted (2,:) + xPermuted (3,:); % Calculate "flattened" 2D function
y = reshape(yTmp, x_size(Order)); % Reshape output back to original size
end
t1 = timeit(#() Luis1(x));
t2 = timeit(#() Luis2(x));
t3 = timeit(#() Adriaan(x));
t4 = timeit(#() Adriaan2(x,n));
format long g;
fprintf('Luis 1: %f seconds\n', t1);
fprintf('Luis 2: %f seconds\n', t2);
fprintf('Adriaan 1: %f seconds\n', t3);
fprintf('Adriaan 2: %f seconds\n', t4);
end
Luis 1: 0.698139 seconds
Luis 2: 4.082378 seconds
Adriaan 1: 0.696034 seconds
Adriaan 2: 0.691597 seconds
So, going to a cell is bad, it takes more than 5 times as long, reshape and ':' are barely apart, so that'd come down to preference.

Filling in a Cell of Matrices in MATLAB

In Matlab I am trying to create a cell of size 16 x1 where each entry of this cell is a matrix. I have the following equation
$$W_g = exp^{\frac{j{2\pi m}{N}(n+\frac{g}{G}))} \,\,\,\,\,\,\, m,n=0,1,.....(N-1)$$
for this work assume $N=4$ and the index $g$ is the index that refers to the cell element i.e g=0:1:15
W=cell(16,1);
for g=1:16
for m=1:3
for n=1:3
W{g,m,n}= exp((2*pi*j*m/4)* n+(g-1)/16));
end
end
end
How can I make this work? I have two problems with this, you see g starts from 0 and MATLAB doesnt accept index of zero and how to actually define the matrices within the cell.
Thanks
So if I understand you have this equation:
And you just want the following code:
W=cell(16,1);
n = 1:3;
m = 1:3;
N = 4;
for g=1:16
W{g}= exp((2*pi*j.*m/4*N).*n+(g-1)/16);
end
%or the 1 line version:
W = cellfun(#(g) exp((2*pi*j.*m/4*N).*n+(g-1)/16),num2cell([1:16]),'UniformOutput',0);
With matlab you can use the Element-wise multiplication symbol .*
For example:
%A matrix multiplication
A = [2,3]
B = [1,3]';
result = A * B %result = 11
%An element wise multiplication
A = [2,3]
B = [1,3];
result = A .* B %result = [2,9]
First of all, i is the complex number in matlab (sqrt(-1)) not j, and you are correct, matlab is indexed in 1, so simply start counting g at 1, until 16.
Next, create a zero matrix, and calculate all indices accordingly. Something like this should work just fine :
clc
clear all
W=cell(16,1);
for g=1:16;
temp = zeros(3,3);
for m=1:3
for n=1:3
temp (m,n) = exp((2*pi*1i*m/4)* n+g/16);
end
end
W{g} = temp;
end
if you are considering doing much larger operations, consider using linspace to create your m and n indices and using matrix operations

Getting the N-dimensional product of vectors

I am trying to write code to get the 'N-dimensional product' of vectors. So for example, if I have 2 vectors of length L, x & y, then the '2-dimensional product' is simply the regular vector product, R=x*y', so that each entry of R, R(i,j) is the product of the i'th element of x and the j'th element of y, aka R(i,j)=x(i)*y(j).
The problem is how to elegantly generalize this in matlab for arbitrary dimensions. This is I had 3 vectors, x,y,z, I want the 3 dimensional array, R, such that R(i,j,k)=x(i)*y(j)*z(k).
Same thing for 4 vectors, x1,x2,x3,x4: R(i1,i2,i3,i4)=x1(i1)*x2(i2)*x3(i3)*x4(i4), etc...
Also, I do NOT know the number of dimensions beforehand. The code must be able to handle an arbitrary number of input vectors, and the number of input vectors corresponds to the dimensionality of the final answer.
Is there any easy matlab trick to do this and avoid going through each element of R specifically?
Thanks!
I think by "regular vector product" you mean outer product.
In any case, you can use the ndgrid function. I like this more than using bsxfun as it's a little more straightforward.
% make some vectors
w = 1:10;
x = w+1;
y = x+1;
z = y+1;
vecs = {w,x,y,z};
nvecs = length(vecs);
[grids{1:nvecs}] = ndgrid(vecs{:});
R = grids{1};
for i=2:nvecs
R = R .* grids{i};
end;
% Check results
for i=1:10
for j=1:10
for k=1:10
for l=1:10
V(i,j,k,l) = R(i,j,k,l) == w(i)*x(j)*y(k)*z(l);
end;
end;
end;
end;
all(V(:))
ans = 1
The built-in function bsxfun is a fast utility that should be able to help. It is designed to perform 2 input functions on a per-element basis for two inputs with mismatching dimensions. Singletons dimensions are expanded, and non-singleton dimensions need to match. (It sounds confusing, but once grok'd it useful in many ways.)
As I understand your problem, you can adjust the dimension shape of each vector to define the dimension that it should be defined across. Then use nested bsxfun calls to perform the multiplication.
Example code follows:
%Some inputs, N-by-1 vectors
x = [1; 3; 9];
y = [1; 2; 4];
z = [1; 5];
%The computation you describe, using nested BSXFUN calls
bsxfun(#times, bsxfun(#times, ... %Nested BSX fun calls, 1 per dimension
x, ... % First argument, in dimension 1
permute(y,2:-1:1) ) , ... % Second argument, permuited to dimension 2
permute(z,3:-1:1) ) % Third argument, permuted to dimension 3
%Result
% ans(:,:,1) =
% 1 2 4
% 3 6 12
% 9 18 36
% ans(:,:,2) =
% 5 10 20
% 15 30 60
% 45 90 180
To handle an arbitrary number of dimensions, this can be expanded using a recursive or loop construct. The loop would look something like this:
allInputs = {[1; 3; 9], [1; 2; 4], [1; 5]};
accumulatedResult = allInputs {1};
for ix = 2:length(allInputs)
accumulatedResult = bsxfun(#times, ...
accumulatedResult, ...
permute(allInputs{ix},ix:-1:1));
end