Reverse process of a matrix expansion on Matlab - arrays

My program allows to multiply a given B matrix with a z factor with some characteristics listed below, to give an H matrix. I would like to have a programming idea to do the inverse of what I programmed. That is to say with a given H matrix find the value of the B matrix.
For example with a matrix B = [-1 -1 ; 1 0]
I get with my code a matrix :
H = [ 0 0 0 0 0 0 ;
0 0 0 0 0 0 ;
0 0 0 0 0 0 ;
0 1 0 1 0 0 ;
0 0 1 0 1 0 ;
1 0 0 0 0 1 ]
I would like to have from a code H the value of the matrix B.
To specify the matrix H from the matrix B, it is necessary that:
Each coefficient -1 is replaced by a null matrix of dimension z*z;
Each coefficient 0 is replaced by an identity matrix of dimension z*z;
Each coefficient 1,2,...,z-1 is replaced by a circulating permutation matrix of dimension z*z shifted by 1,2,...,z-1 position to the right.
From a matrix B and the expansion factors z , we construct an extended binary H matrix with n-k rows and n columns.
My code :
clear;
close all;
B = [-1 -1 ; 1 0];
z = 3;
H = zeros(size(B)*z);
Y = eye(z);
for X1 = 1:size(B,1)
for X2 = 1:size(B,2)
X3 = B(X1,X2);
if (X3 > -1)
X4 = circshift(Y,[0 X3]);
else
X4 = zeros(z);
end
Y1 = (X1-1)*z+1:X1*z;
Y2 = (X2-1)*z+1:X2*z;
H(Y1,Y2) = X4;
end
end
[M,N] = size(H);
Any suggestions?

Assuming that all of the input matrices are well-formed, you can determine the mapping based on the first row of each block. For example, the block mapping to 1:
0 1 0
0 0 1
1 0 0
has a 1 in column 2 of row 1. Similarly, a one in column 1 maps to 0, and column 3 maps to 2. No ones in the row maps to -1. So we just need to find the column containing the 1 in the first row.
Annoyingly, find returns null when it doesn't find a nonzero value rather than 0 (which is what we would want in this case). We can adjust to this by adding a value to the matrix row that is only 1 when all of the others are 0.
If you have the Image Processing Toolbox, you can use blockproc to handle the looping for you:
B = blockproc(H, [z z], #(A)find([~any(A.data(1,:)) A.data(1,:)])-2);
Otherwise, just loop over the blocks and apply the function to each one.

Related

MATLAB : Obtain a matrix by adding its last lines to the first lines of the basic matrix

I have a matrix B and I would like to obtain a new matrix C from B by adding its last w*a rows to the first w*a rows (w and a will be defined afterwards).
My matrix B is generally defined by :
I would like to obtain matrix C defined in a general way by:
The characteristics of matrices B and C are:
L and w are defined real values;
B0,B1,...,Bw are of dimension: a by b;
B is of dimension: [(L+w)×a] by (L×b);
C is of dimension: (L×a) by (L×b).
Example: For L = 4 and w = 2 I obtain the following matrix B:
The w*a = 2*1 = 2 last rows of B are:
The w*a = 2*1 = 2 first rows of B are:
By adding the two matrices we have:
The matrix C thus obtained is then:
For B0 = [1 0], B1 = [0 1] and B2 = [1 1]. We obtain :
B0, B1 and B2 are of dimension a by b i.e. 1 by 2;
B is of dimension: [(L+w )×(a)] by (L×b) i.e. [(4+2)×1] by (4×2) i.e. 6 by 8;
C is of dimension: (L×a) by (L×b) i.e. (4×1) by (4×2) i.e. 4 by 8.
The matrices B and C that I get are as follows:
B =
1 0 0 0 0 0 0 0
0 1 1 0 0 0 0 0
1 1 0 1 1 0 0 0
0 0 1 1 0 1 1 0
0 0 0 0 1 1 0 1
0 0 0 0 0 0 1 1
C =
1 0 0 0 1 1 0 1
0 1 1 0 0 0 1 1
1 1 0 1 1 0 0 0
0 0 1 1 0 1 1 0
I would like to have some suggestions on how to program this construction so that from a given matrix B I can deduce the matrix C.
Matlab's range indexing should help you do this in a few steps. The key things to remember are that ranges are inclusive, i.e. A[1:3] is a three 3x1 matrix, and that you can use the keyword end to automatically index the end of the matrix row or column.
%% Variables from OP example
w = 2;
L = 4;
B0 = [1 0];
B1 = [0 1];
B2 = [1 1];
[a, b] = size(B0);
% Construct B
BX = [B0;B1;B2]
B = zeros((L+w)*a, L*b);
for ii = 0:L-1
B(ii+1:ii+w+1, ii*b+1:ii*b+b) = BX;
end
%% Construct C <- THIS PART IS THE ANSWER TO THE QUESTION
% Grab first rows of B
B_first = B(1:end-w*a, :) % Indexing starts at first row, continues to w*a rows before the end, and gets all columns
% Grab last rows of B
B_last = B(end-w*a+1:end, :); % Indexing starts at w*a rows before the end, continues to end. Plus one is needed to avoid off by one error.
% Initialize C to be the same as B_first
C = B_first;
% Add B_last to the first rows of C
C(1:w*a, :) = C(1:w*a, :) + B_last;
I get the output
C =
1 0 0 0 0 0 1 1 0 1
0 1 1 0 0 0 0 0 1 1
1 1 0 1 1 0 0 0 0 0
0 0 1 1 0 1 1 0 0 0
0 0 0 0 1 1 0 1 1 0

How to unfold a Matrix on Matlab?

I have a given matrix H and I would like to unfold (expand) it to find a matrix B by following the method below :
Let H be a matrix of dimension m × n. Let x = gcd (m,n)
The matrix H is cut in two parts.
The cutting pattern being such that :
The "diagonal cut" is made by alternately moving c = n/x units to the right (we move c units to the right several times).
We alternately move c-b = m/x units down (i.e. b = (n-m)/x) (we move b units down several times).
After applying this "diagonal cut" of the matrix, we copy and paste the two parts repeatedly to obtain the matrix B.
Exemple : Let the matrix H of dimension m × n = 5 × 10 defined by :
1 0 1 1 1 0 1 1 0 0
0 1 1 0 0 1 1 0 1 1
1 1 0 1 1 1 0 1 0 0
0 1 1 0 1 0 1 0 1 1
1 0 0 1 0 1 0 1 1 1
Let's calculate x = gcd (m,n) = gcd (5,10) = 5,
Alternatively move to the right : c = n/x = 10/5 = 2,
Alternatively move down : b = (n-m)/x = (10-5)/5 = 1.
Diagonal cutting diagram : The matrix H is cut in two parts.
The cutting pattern is such that :
We move c = 2 units to the right several times c = 2 units to the right,
We repeatedly move c - b = 1 unit downwards.
We get :
After applying this "diagonal cut" of the matrix, we copy and paste the two parts repeatedly to obtain the matrix :
Remark : In the matrices X, X1 and X2 the dashes are zeros.
The resulting matrix B is (L is factor) :
Any suggestions?
This can be done by creating a logical mask with the cutting pattern, and then element-wise multiplying the input by the mask and by its negation. Repeating by L can be done with blkdiag.
H = [1 0 1 1 1 0 1 1 0 0
0 1 1 0 0 1 1 0 1 1
1 1 0 1 1 1 0 1 0 0
0 1 1 0 1 0 1 0 1 1
1 0 0 1 0 1 0 1 1 1];
L = 2;
[m, n] = size(H);
x = gcd(m, n);
c = n / x;
b = (n-m)/x;
mask = repelem(tril(true(m/b)), b, c);
A = [H.*mask; H.*~mask];
A = repmat({A}, L, 1);
B = blkdiag(A{:});

Create a matrix with a diagonal and left-diagonal of all 1s in MATLAB

I would like to create a square matrix of size n x n where the diagonal elements as well as the left-diagonal are all equal to 1. The rest of the elements are equal to 0.
For example, this would be the expected result if the matrix was 5 x 5:
1 0 0 0 0
1 1 0 0 0
0 1 1 0 0
0 0 1 1 0
0 0 0 1 1
How could I do this in MATLAB?
Trivial using the tril function:
tril(ones(n),0) - tril(ones(n),-2)
And if you wanted a thicker line of 1s just adjust that -2:
n = 10;
m = 4;
tril(ones(n),0) - tril(ones(n),-m)
If you prefer to use diag like excaza suggested then try
diag(ones(n,1)) + diag(ones(n-1,1),-1)
but you can't control the 'thickness' of the stripe this way. However, for a thickness of 2, it might perform better. You'd have to test it though.
You can also use spdiags too to create that matrix:
n = 5;
v = ones(n,1);
d = full(spdiags([v v], [-1 0], n, n));
We get:
>> d
d =
1 0 0 0 0
1 1 0 0 0
0 1 1 0 0
0 0 1 1 0
0 0 0 1 1
The first two lines define the desired size of the matrix, assuming a square n x n as well as a vector of all ones that is of length n x 1. We then call spdiags to define where along the diagonal of this matrix this vector will be populating. We want to define the main diagonal to have all ones as well as the diagonal to the left of the main diagonal, or -1 away from the main diagonal. spdiags will adjust the total number of elements for the diagonal away from the main to compensate.
We also ensure that the output is of size n x n, but this matrix is actually sparse . We need to convert the matrix to full to complete the result.,
With a bit of indices juggling, you can also do this:
N = 5;
ind = repelem(1:N, 2); % [1 1 2 2 3 3 ... N N]
M = full(sparse(ind(2:end), ind(1:end-1), 1))
Simple approach using linear indexing:
n = 5;
M = eye(n);
M(2:n+1:end) = 1;
This can also be done with bsxfun:
n = 5; %// matrix size
d = [0 -1]; %// diagonals you want set to 1
M = double(ismember(bsxfun(#minus, 1:n, (1:n).'), d));
For example, to obtain a 5x5 matrix with the main diagonal and the two diagonals below set to 1, define n=5 and d = [0 -1 -2], which gives
M =
1 0 0 0 0
1 1 0 0 0
1 1 1 0 0
0 1 1 1 0
0 0 1 1 1

Change Random Element of a Matrix with small Restriction

I have a Vector 1xm, ShortMemory (SM), and a Matrix nxm, Agenda (AG).
SM only have positive integers and zeros.
Each column of AG only has one element equal to 1 and all the other elements of the same column equal to 0.
My objective is changing the position of the number 1 from a randomly choosen column from AG. The problem is that only columns that have a corresponding 0 in SM can be changed.
Example:
SM = [1 0 2];
AG = [1 1 0 ; 0 0 1 ; 0 0 0];
Randomly Generated number here
RandomColumn = 2;
The possible outcomes would be
AG = [1 0 0 ; 0 1 1 ; 0 0 0]; or AG = [1 0 0; 0 0 1 ; 0 1 0]; or AG = [1 1 0 ; 0 0 1 ; 0 0 0];
The Line that gets the 1 is also random but that's easy to do
I could do it by just getting random numbers between 1 and m but m can be very big in my problem and the number of zeros can be very small too, so it could potentially take alot of time. I could also do it with a cycle but it's Matlab and this is embeded on double cycle already.
Thanks
edit: Added commentary to the code for clarity.
edit: Corrected an error on possible outcome
My solution is based on following assumptions:
Objective is changing the position of the number 1 from a randomly choosen column from AG.
Only columns that have a corresponding 0 in SM can be changed.
Solution:
% input
SM = [1 0 2]
AG = [1 1 0 ; 0 0 1 ; 0 0 0]
% generating random column according to assumptions 1 and 2
RandomColumn1 = 1:size(AG,2);
RandomColumn1(SM~=0)=[];
RandomColumn1=RandomColumn1(randperm(length(RandomColumn1)));
RandomColumn=RandomColumn1(1);
% storing the current randomly chosen column before changing
tempColumn=AG(:,RandomColumn);
% shuffling the position of 1
AG(:,RandomColumn)=AG(randperm(size(AG,1)),RandomColumn);
% following checks if the column has remained same after shuffling. This while loop should execute (extremely) rarely.
while tempColumn==AG(:,RandomColumn)
tempColumn=AG(:,RandomColumn);
AG(:,RandomColumn)=AG(randperm(size(AG,1)),RandomColumn);
end
AG

How to resize / expand a matrix by adding zeros?

How is it possible to expand a quadratic - let's say NxN - matrix to a bigger on like a (N+k)x(N+k) matrix?
It's really all about resizing the matrix and filling the missing rows/columns with zeros such that not dimension mismatch occurs.
No need to do it more difficult than it is. MATLAB automatically pads with zeros if you assign something to an element outside of the original size:
n = 4;
A = [1 2; 3 4];
A(n,n) = 0;
A =
1 2 0 0
3 4 0 0
0 0 0 0
0 0 0 0
you can add zeros to a matrix using padarray... For example:
A = [1 2; 3 4];
B = padarray(A,[2 2],'post')
B =
1 2 0 0
3 4 0 0
0 0 0 0
0 0 0 0
Or, if you don't have the image processing toolbox, you can use matrix indexing:
B = zeros(size(A)+k, class(A));
B(k:end-k+1,k:end-k+1) = A;

Resources