Modifying the elements of matrix from indices (MATLAB)

I have a number of elements m for example m=4. And the matrix is square of dimensions m*m
P =
1 2 3 4
2 3 4 3
3 4 3 2
4 3 2 1
using the following program to replace the indices 1, 2, 3...m with its sub-matrices:
m=input('Initialize a number of elements'); % Number of elements in the matrix
P=hankel(1:m,m:-1:1);
% Initialisation of sub-matrices of dimensions (m-1 x m-1)
a=zeros(m-1,m-1,m-2);
a(:,:,1)=eye(m-1); % First sub-matrix is always an identity matrix with indice = 1 in P
for k=2:m-1
a(:,:,k)=circshift(a(:,:,k-1),1,2 ); % Other sub-matrices of indice = 2 to m-1
end
a(:,:,m) = zeros(m-1); % Final sub-matrix of indice = m (always null)
% Replacing the sub-matrices of indices 1,2,...m in P
N = zeros(m*(m-1));
a = num2cell(a,[1 2]);
for ii = 1:m
for jj = 1:m
N((m-1)*(ii-1)+1:(m-1)*ii,(m-1)*(jj-1)+1:(m-1)*jj) = a{P(ii,jj)};
end
end
I added this part of program to find always two indices of sum=m. For example in the case of m=4 the indices are 1 and 3 to find 1+3=m
indice=0;
while sum(indice)~=m
indice=randi([1,m-1],[1,2]);
end
So the indice 2 is not used here. We use just 1, 3 and m.
I need to add a part in the prgram that replace all the sub-matrices of indices that are not used (in this example indice 2) with null matrices in the matrix N. How can I do that please.

4 Comments

randi() can return [2 2], so it's not true that index 2 can never be used.
m = 4;
indice = 0;
while sum(indice) ~= m
indice = randi([1,m-1],[1 2]);
end
disp(indice)
2 2
@_ In my case I won't that the indice gives the result as two same indices ([2 2] for example). The indices must be different and then I have to add a part in the prgram that replace all the sub-matrices of indices that are not used (in this example indice 2) with null matrices in the matrix N.
Are you saying that you have some code to prevent repeated indices, e.g., [2 2], or that you still need to write such code?
Also, what do you mean by null matrices? A matrix of the appropriate size which is all NaNs?
@_ For the repeated indices, I still need to modify this part in such a way it prevents this repetition.
By null matrix I mean zero matrix (its elements are all zeros)

Sign in to comment.

 Accepted Answer

Here is a function you can use to get a pair of random indices that sum to m but are never [m/2 m/2]:
function idx = get_random_index(m)
if mod(m,2) % m is odd: no chance of getting m/2 from randi()
idx = randi([1 m-1]); % just use the result from randi()
else % m is even: could get m/2 from randi(), so use randi()
% to get an integer between 1 and m-2, then increase it
% by 1 if it is >= m/2, so you end up with a random index
% between 1 and m-1 excluding m/2
% e.g., for m == 4:
% randi() returns 1: idx = 1
% randi() returns 2: idx = 3
% e.g., for m == 6:
% randi() returns 1: idx = 1
% randi() returns 2: idx = 2
% randi() returns 3: idx = 4
% randi() returns 4: idx = 5
idx = randi([1 m-2]);
if idx >= m/2
idx = idx+1;
end
end
idx = [idx m-idx]; % return the 2 indices whose sum is m
end

6 Comments

@_ Thank you so much!
What about the other part of replacing the sub matrices of the unused indice with zero bits if you can help me please!
Since N is initialized with zeros, you can simply skip populating the relevant part of N when P(ii,jj) == m/2:
% m=input('Initialize a number of elements'); % Number of elements in the matrix
m = 4;
P=hankel(1:m,m:-1:1)
P = 4×4
1 2 3 4 2 3 4 3 3 4 3 2 4 3 2 1
% Initialisation of sub-matrices of dimensions (m-1 x m-1)
a=zeros(m-1,m-1,m-2);
a(:,:,1)=eye(m-1); % First sub-matrix is always an identity matrix with indice = 1 in P
for k=2:m-1
a(:,:,k)=circshift(a(:,:,k-1),1,2 ); % Other sub-matrices of indice = 2 to m-1
end
a(:,:,m) = zeros(m-1); % Final sub-matrix of indice = m (always null)
% Replacing the sub-matrices of indices 1,2,...m in P
N = zeros(m*(m-1));
a = num2cell(a,[1 2]);
for ii = 1:m
for jj = 1:m
% if P(ii,jj) == m/2, then the corresponding sub-matrix in N needs
% to be all zeros, which it already is, so there is nothing to do
% in that case.
% Just set the sub-matrix when P(ii,jj) ~= m/2:
if P(ii,jj) ~= m/2
N((m-1)*(ii-1)+1:(m-1)*ii,(m-1)*(jj-1)+1:(m-1)*jj) = a{P(ii,jj)};
end
end
end
disp(N);
1 0 0 0 0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 1 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 1 0 0 0 0 0 1 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 1 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 0 1
Thank. You! It's correct in this case where m=4,because for indices we have just 1 and 3. But in the general case, we cannot always set the sub matrices as zeros when the indice is 2. I give you an example: if we have m=5, here the indices can be [2 3] so the other sub matrices of indices (1,4) will be all zeros. Or for the same m=5 we can find indices [1 4] and here the other sub matrices of indices (2,3) will be all zeros. That's why we have first to put the code of the indices that you gave me and than according to the choosen indices we choose which sub matrices must be zeros. Hope that you understand me.
OK. I wasn't sure how getting the random indices related to populating N with sub-matrices, but I think it makes sense now. You want to get a single pair of random indices and only populate N where P is one of those indices, right? If so, then it might look like this:
% m=input('Initialize a number of elements'); % Number of elements in the matrix
m = 5;
P=hankel(1:m,m:-1:1)
P = 5×5
1 2 3 4 5 2 3 4 5 4 3 4 5 4 3 4 5 4 3 2 5 4 3 2 1
% Initialisation of sub-matrices of dimensions (m-1 x m-1)
a=zeros(m-1,m-1,m-2);
a(:,:,1)=eye(m-1); % First sub-matrix is always an identity matrix with indice = 1 in P
for k=2:m-1
a(:,:,k)=circshift(a(:,:,k-1),1,2 ); % Other sub-matrices of indice = 2 to m-1
end
a(:,:,m) = zeros(m-1); % Final sub-matrix of indice = m (always null)
idx = get_random_index(m)
idx = 1×2
4 1
% Replacing the sub-matrices of indices 1,2,...m in P
N = zeros(m*(m-1));
a = num2cell(a,[1 2]);
for ii = 1:m
for jj = 1:m
if ismember(P(ii,jj),idx)
N((m-1)*(ii-1)+1:(m-1)*ii,(m-1)*(jj-1)+1:(m-1)*jj) = a{P(ii,jj)};
end
end
end
disp(N);
1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 1
function idx = get_random_index(m)
if mod(m,2) % m is odd: no chance of getting m/2 from randi()
idx = randi([1 m-1]); % just use the result from randi()
else % m is even: could get m/2 from randi(), so use randi()
% to get an integer between 1 and m-2, then increase it
% by 1 if it is >= m/2, so you end up with a random index
% between 1 and m-1 excluding m/2
% e.g., for m == 4:
% randi() returns 1: idx = 1
% randi() returns 2: idx = 3
% e.g., for m == 6:
% randi() returns 1: idx = 1
% randi() returns 2: idx = 2
% randi() returns 3: idx = 4
% randi() returns 4: idx = 5
idx = randi([1 m-2]);
if idx >= m/2
idx = idx+1;
end
end
idx = [idx m-idx]; % return the 2 indices whose sum is m
end
@_ Thank you so much! it works exactly as I want
I appreciate your help

Sign in to comment.

More Answers (0)

Tags

Asked:

on 11 Mar 2022

Commented:

on 12 Mar 2022

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!