baptiste
baptiste

Reputation: 95

Create a d-dimensional tensor dynamically

I would like to create a d-dimensional tensor using d as an input and without the if statement as below:

if d == 2
   B = zeros(r,r);
   for i = 1:r
       B(i,i) = 1;
   end                
elseif d == 3
   B = zeros(r,r,r);
   for i = 1:r
       B(i,i,i) = 1;
   end
end

Is there a more efficient way?

Upvotes: 3

Views: 135

Answers (2)

Luis Mendo
Luis Mendo

Reputation: 112749

This does what you want for arbitrary r and d:

B = zeros(repmat(r,1,d)); % initiallize as d×d×···×d array filled with 0
B(linspace(1,end,r)) = 1; % write 1 in the "diagonal". end can be replaced by r^d

Some notes on how it works:

  • zeros can take a vector as input, which allows the number of dimensions to be specified dynamically.
  • Linear indexing is being used to specify the positions containing 1.
  • end is being used within a function call. This is a not very well known feature.

Equivalently, you can first build the array in linear form and then reshape it:

B = reshape(mod(1:r^d, (r^d-1)/(r-1))==1, repmat(r,1,d));

Notes:

  • The step between entries containing 1, in linear indexing, is (r^d-1)/(r-1).
  • reshape allows a vector as input to specify dimensions, similar to zeros.

Upvotes: 3

rahnema1
rahnema1

Reputation: 15867

You can use accumarray:

f = @(d,r)accumarray(repmat((1:r).',1 , d), 1);

> f(2,5)
=
1   0   0   0   0
0   1   0   0   0
0   0   1   0   0
0   0   0   1   0
0   0   0   0   1

Here is the basic signature of accumarray:

accumarray( subs , val )

Using accumarray we can create an n-dimensional array where subs represents the position of points that will be filled in the array and val represents the value of them.

If subs provided as a matrix , its number of columns determines the number of dimensions of the resultant array and each row represents position of each point.

For example for d = 2 and r = 5 we want to create a (5 x 5) array that has 1s in the following positions: [1 1],[2 2],[3 3],[4 4],[5 5].

Using repmat we can create subs:

subs = repmat ((1:5).' , 1, 2)

=
1 1
2 2
3 3
4 4
5 5

val is set to 1 so all specified positions will be filled by 1.

.

Upvotes: 4

Related Questions