1

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.

TEX
  • 2,249
  • 20
  • 43
  • Do you need `A(n,:,:,:)=[];A(:,n,:,:)=[];A(:,:,n,:)=[];A(:,:,:,n)=[];` ? It is the same as `A(1:n-1, 1:n-1, 1:n-1, 1:n-1)` – rahnema1 Aug 12 '19 at 15:29
  • Thanks. The problem is that the number of "commas" inside `A` in your comment depends on `n`. For example, in your comment you are using 3 commas, i.e., you are assuming `n=4`. Instead, I want to be generic. – TEX Aug 12 '19 at 15:34
  • If `n=3`: `A(1:n-1,1:n-1, 1:n-1)`. If `n=4`: `A(1:n-1,1:n-1, 1:n-1, 1:n-1)`. If `n=5`: `A(1:n-1,1:n-1, 1:n-1, 1:n-1, 1-n-1)`, etc. – TEX Aug 12 '19 at 15:35
  • 2
    Use `idx = repmat({1:n-1},1,n); A(idx{:})`. If it is correct let me to post it as an answer. – rahnema1 Aug 12 '19 at 15:36

1 Answers1

4

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{:});
obchardon
  • 10,614
  • 1
  • 17
  • 33
  • Would it be beneficial to generalize this further for the `randn` function by creating an input string and then use `eval` to run the command – medicine_man Aug 12 '19 at 15:57
  • 1
    @medicine_man: `eval` is never beneficial. Pretend it doesn't exist! You can call `randn` with a single size argument: `randn([n,n,n,n])` -- I bet you know how to generalize that to any number of dimensions. Otherwise you could do: `indx={n,n,n,n}; randn(indx{:})`. – Cris Luengo Aug 12 '19 at 16:02
  • 1
    @obchardon: You can use the string `':'` in your indexing cell array too. That would simplify the code a bit. – Cris Luengo Aug 12 '19 at 16:02
  • I have never had any issues with `eval`, although many others seem to not like this command. I have no idea why, honestly. – medicine_man Aug 12 '19 at 16:03
  • 1
    @medicine_man: it's a security risk, it slows down code, it makes code harder to read, etc. etc. There are many Q&As here that discuss the issues with `eval`. For example: https://stackoverflow.com/questions/10272522/use-and-implications-of-evalexpression-in-matlab-code/10272578 – Cris Luengo Aug 12 '19 at 16:08
  • Actually, you are not indexing a matrix with a cell array (that's not possible). Rather, you are indexing a matrix with the _comma-separated list_ generated from a cell array. Also, the suggestion you refer to was not mine :-) – Luis Mendo Aug 12 '19 at 23:13