Replacing elements in a base matrix by squared permutation submatrices - matlab

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.

Related

Generalise indexing of a multi-dimensional array in Matlab

I want to generalise to any n the Matlab code below.
Let A be an n-dimensional array:
clear
rng default
n=4;
A=randn(n,n,n,n);
n=5;
A=randn(n,n,n,n,n);
Note that A is composed of n^(n-2) 2-dimensional matrices, each of size nxn.
For example, when n=4 these matrices are A(:,:,1,1),...,A(:,:,4,1),A(:,:,1,2),...,A(:,:,4,4).
Suppose I'm interested in a code which:
1) deletes the last column and row in each of the n^(n-2) 2-dimensional matrices
%when n=4
A(n,:,:,:)=[];
A(:,n,:,:)=[];
%when n=5
A(n,:,:,:,:)=[];
A(:,n,:,:,:)=[];
2) deletes the 2-dimensional matrices with the 3-th,4-th,5-th,n-th index equal to n.
%when n=4
A(:,:,n,:)=[];
A(:,:,:,n)=[];
%when n=5
A(:,:,n,:,:)=[];
A(:,:,:,n,:)=[];
A(:,:,:,:,n)=[];
Question: could you help me to generalise the code above to any n? I cannot see how to proceed.
You can index your matrix with a cell containing multiple elements. Each element will be interpreted as a new index (more information here):
%Example 1: A(:,:,1:3,1:3,1:3}
%elements per dimension
n = 4;
%number of dimension
d = 5;
%random matrix
repdim = repmat({n},d,1)
A = rand(repdim{:});
%We want A(:,:,1:3,1:3,1:3}, so we create c = {1:3,1:3,1:3}
c = repmat({1:n-1},d-2,1);
%Get the new matrix
A = A(:,:,c{:});
%Example 2: A(1:3,1:3,:,:,:}
%elements per dimension
n = 4;
%number of dimension
d = 5;
%random matrix
repdim = repmat({n},d,1)
A = rand(repdim{:});
%We want A(1:3,1:3,:,:,:}, so we create c1 = {1:3,1:3} and c2 = {':',':',':'}
c1 = repmat({1:n-1},2,1);
c2 = repmat({':'},d-2,1); %thanks to #LuisMendo for the suggestion.
%Get the new matrix
A = A(c1{:},c2{:});

Add a diagonal of zeros to a matrix in MATLAB

Suppose I have a matrix A of dimension Nx(N-1) in MATLAB, e.g.
N=5;
A=[1 2 3 4;
5 6 7 8;
9 10 11 12;
13 14 15 16;
17 18 19 20 ];
I want to transform A into an NxN matrix B, just by adding a zero diagonal, i.e.,
B=[ 0 1 2 3 4;
5 0 6 7 8;
9 10 0 11 12;
13 14 15 0 16;
17 18 19 20 0];
This code does what I want:
B_temp = zeros(N,N);
B_temp(1,:) = [0 A(1,:)];
B_temp(N,:) = [A(N,:) 0];
for j=2:N-1
B_temp(j,:)= [A(j,1:j-1) 0 A(j,j:end)];
end
B = B_temp;
Could you suggest an efficient way to vectorise it?
You can do this with upper and lower triangular parts of the matrix (triu and tril).
Then it's a 1 line solution:
B = [tril(A,-1) zeros(N, 1)] + [zeros(N,1) triu(A)];
Edit: benchmark
This is a comparison of the loop method, the 2 methods in Sardar's answer, and my method above.
Benchmark code, using timeit for timing and directly lifting code from question and answers:
function benchie()
N = 1e4; A = rand(N,N-1); % Initialise large matrix
% Set up anonymous functions for input to timeit
s1 = #() sardar1(A,N); s2 = #() sardar2(A,N);
w = #() wolfie(A,N); u = #() user3285148(A,N);
% timings
timeit(s1), timeit(s2), timeit(w), timeit(u)
end
function sardar1(A, N) % using eye as an indexing matrix
B=double(~eye(N)); B(find(B))=A.'; B=B.';
end
function sardar2(A,N) % similar to sardar1, but avoiding slow operations
B=1-eye(N); B(logical(B))=A.'; B=B.';
end
function wolfie(A,N) % using triangular parts of the matrix
B = [tril(A,-1) zeros(N, 1)] + [zeros(N,1) triu(A)];
end
function user3285148(A, N) % original looping method
B = zeros(N,N); B(1,:) = [0 A(1,:)]; B(N,:) = [A(N,:) 0];
for j=2:N-1; B(j,:)= [A(j,1:j-1) 0 A(j,j:end)]; end
end
Results:
Sardar method 1: 2.83 secs
Sardar method 2: 1.82 secs
My method: 1.45 secs
Looping method: 3.80 secs (!)
Conclusions:
Your desire to vectorise this was well founded, looping is way slower than other methods.
Avoiding data conversions and find for large matrices is important, saving ~35% processing time between Sardar's methods.
By avoiding indexing all together you can save a further 20% processing time.
Generate a matrix with zeros at diagonal and ones at non-diagonal indices. Replace the non-diagonal elements with the transpose of A (since MATLAB is column major). Transpose again to get the correct order.
B = double(~eye(N)); %Converting to double since we want to replace with double entries
B(find(B)) = A.'; %Replacing the entries
B = B.'; %Transposing again to get the matrix in the correct order
Edit:
As suggested by Wolfie for the same algorithm, you can get rid of conversion to double and the use of find with:
B = 1-eye(N);
B(logical(B)) = A.';
B = B.';
If you want to insert any vector on a diagonal of a matrix, one can use plain indexing. The following snippet gives you the indices of the desired diagonal, given the size of the square matrix n (matrix is n by n), and the number of the diagonal k, where k=0 corresponds to the main diagonal, positive numbers of k to upper diagonals and negative numbers of k to lower diagonals. ixd finally gives you the 2D indices.
function [idx] = diagidx(n,k)
% n size of square matrix
% k number of diagonal
if k==0 % identity
idx = [(1:n).' (1:n).']; % [row col]
elseif k>0 % Upper diagonal
idx = [(1:n-k).' (1+k:n).'];
elseif k<0 % lower diagonal
idx = [(1+abs(k):n).' (1:n-abs(k)).'];
end
end
Usage:
n=10;
k=3;
A = rand(n);
idx = diagidx(n,k);
A(idx) = 1:(n-k);

How to represent a vector as a matrix?

I have a vector of length 3. i want to represent it as a matrix of dimension 4*2. ie) if the length of vector is n then matrix should be of dimension (n+1)*2. The matrix should have elements arranged as follows:
Vector= [2 3 4]
Matrix = [0 2;2 3;3 4;4 0]
You can solve your problem easily with simple operations:
vector = [2 3 4];
matrix = [0 vector; vector 0]';
' is used to transpose the matrix.
Additionally there are two useful functions in Matlab to manipulate matrices and vectors:
reshape()
repmat()
The command reshape from Matlab is the basis of my answer to your question:
B = reshape(A,m,n) returns the m-by-n matrix B whose elements are taken column-wise from A. An error results if A does not have m*n elements (from the official Matlab help).
You basically add zeros at the beginning and at the end and then have every number in the vector occur twice (if you "unfold"/reshape the matrix). So lets construct the desired matrix by reversing this description:
%set input vector
v = [2 3 4];
%"double" the numbers, v_ is my temporary storage variable
v_ = [v; v];
%align all numbers along one dimension
v_ = reshape(v_, 2*length(v), 1)
%add zeros at beginning and end
v_ = [0 v_ 0];
%procude final matrix
m = reshape(v_, length(v)+1, 2);
in short
%set input vector
v = [2 3 4];
%"double" the numbers, v_ is my temporary storage variable
%all values are aligned as row vector
%zeros are added at beginning and end
v_ = [0, v, v, 0];
%produce final matrix
m = reshape(v_, length(v)+1, 2);
I haven't checked it, since I don't have a Matlab at hand right now, but you should get the idea.
Edit
The answer by 13aumi manages this task even without the reshape command. However, you need to pay close attention to the shape of v (row- vs- column-vector).

splitting a matrix row-wise and and finding a linear regression coeff

A= [1 1
2 2
3 3
. .
. .
. .
N N]
I have an [N,2] matrix and I need to split it row-wise into some number of [N/4,2] submatrices. Then for each submatrix I need to find linear regression where the first column of each submatrix is my x data and the second column is my y data. The output should be a struct with fields a,b,c,d.... and values of linear regression for each submatrix
First I tried splitting the matrix with mat2cell where k = length(N)/4 and mat = mat2cell(A, [k k k k], [1 1]).
Next I tried converting mat into struct with out = cell2struct(mat,fields,1) where fields = {'col1','col2'} and use
new = structfun(#(x)polyfit(x.col1, x.col2,1), out,'UniformOutput', false)
But I get the error:
Inputs to STRUCTFUN must be scalar structures.
Does anyone know how to do it? Many thanks
The most straightforawrd way (and probably the fastest) to do this is with a good old for loop:
A = [1:64;1:64]'; % Demo data
m = 4;
N = size(A,1);
k = N/m; % Assumes that length is evenly divisible by 4
c = zeros(m,2); % Coefficients
for i = 1:m
c(i,:) = polyfit(A((i-1)*k+1:i*k,1),A(i-1)*k+1:i*k,2),1);
end
Or rather than using cell2struct and structfun you can use cellfun:
A = [1:64;1:64]'; % Demo data
m = 4;
N = size(A,1);
k = N/m; % Assumes that length is evenly divisible by 4
c = cellfun(#(x)polyfit(x(:,1),x(:,2),1).',mat2cell(A,k+zeros(1,m),2),'UniformOutput',false)
or alternatively
Ac = mat2cell(A,k+zeros(1,m),[1 1])
c = cellfun(#(x1,x2)polyfit(x1,x2,1).',Ac(:,1),Ac(:,2),'UniformOutput',false)
You can convert the output of cellfun to a matrix with:
c = [c{:}].'
As for why you're getting the error, your variable out is a 4-by-1 struct array (array of structures) rather than a simple (scalar) structure of arrays. The documentation for structfun points out this requirement in the description of the short function: "Apply function to each field of scalar structure." This video from The MathWorks tries to explain the difference.

Matlab d-dimensional multipication table?

I'm new to Matlab and I'm trying to solve a problem that involves creating a d dimensional multiplication table where each edge goes from 1 to n. The problem statement says that inputting d = 0 should return the number 1 and d = 1 should return a column vector with the elements 1 to n.
Ideally, I would just create a matrix of 1 to n along d dimensions and then iterate through for each element setting it equal to the product of the indices, but I don't know how to create the d dimensional matrix.
Can anyone help me with this problem?
You can create the table with repeated use of bsxfun. At each iteration, the vector 1,2,...,n is shifted to a new dimension and multiplied (with singleton expansion) by the previous result.
%// Data
d = 3;
n = 10;
%// Computations
vector = (1:n).'; %// first dimension: column vector
result = 1; %// initialization
for n = 1:d
result = bsxfun(#times, result, vector); %// new dimension
vector = shiftdim(vector,-1); %// shift to the next dimension
end