John_3265
John_3265

Reputation: 71

Reshape potentially very large 1D-array into multidimensional matrix with variable dimensions

I have to postprocess data from a parametric analysis which has as output a 1D-array with the results. I would like to reshape this 1D array into a multidimensional matrix which has the dimensions of my investigated parameters (to be in the right order), and those dimensions may vary in number.

I could came up with a function based on for-loops, but the problem is that with very large arrays I run out of RAM. I am perfectly aware that this is not the smartest way to do this. I was wondering if there is a smarter way to manipulate such a large array and to do the same job as my function does.

function [Tensor, n_dimensions]=reshape_array(Data,ndim)

n_dimensions=length(ndim);
n_elements=prod(ndim);

reshape_string=[];
for i=n_dimensions:-1:1
    if i==1
    reshape_string=strcat(reshape_string, ' ndim(', num2str(i) , ')])'); 
    elseif i== n_dimensions
    reshape_string=strcat(reshape_string, ' [ndim(', num2str(i) , ')'); 
    else
    reshape_string=strcat(reshape_string, ' ndim(', num2str(i) , ') '); 
    end

end

invert_string=[];
for i=1:n_dimensions
    if i==1
    invert_string=strcat(invert_string, 'ndim(', num2str(i) , '),'); 
    elseif i== n_dimensions
    invert_string=strcat(invert_string, ' ndim(', num2str(i) , ')'); 
    else
    invert_string=strcat(invert_string, ' ndim(', num2str(i) , '),'); 
    end

end

reshape_statement=strcat('reshape(Data,',reshape_string);
invert_statement=strcat('zeros(',invert_string,');');

Tens1=eval(reshape_statement);
Tens2=eval(invert_statement);

nLoops=length(ndim);
str = '';
str_dim_tens='';
str_dim_indeces='';
for i=1:nLoops
    str = strcat(sprintf('%s \n for i%d=1:',str,i), sprintf('%d',ndim(i)));
    if i<nLoops
    str_dim_tens=strcat(str_dim_tens,'i',num2str(i),',');
    else
    str_dim_tens=strcat(str_dim_tens,'i',num2str(i));
    end
end

for i=nLoops:-1:1
    if i~=1
    str_dim_indeces=strcat(str_dim_indeces,'i',num2str(i),',');
    else
    str_dim_indeces=strcat(str_dim_indeces,'i',num2str(i));
    end
end

str = strcat(sprintf('%s \n Tens2(%s)=Tens1(%s);',str,str_dim_tens,str_dim_indeces));

for i=1:nLoops
    str = sprintf('%s \n end',str);
end

eval(str)

Tensor=Tens2;

end

as an example,

ndim=[2 3];
Data=1:2*3
[Tensor, n_dimensions]=reshape_array(Data,ndim);

n_dimensions =

     2

Tensor =

     1     2     3
     4     5     6

I would work with more dimensions (e.g. minimum 4) and Data arrays with millions of elements. An example could be M(10,10,10,300000) This is why I was looking for the least computationally expensive method to do the job.

Thank you for your help!

Upvotes: 1

Views: 125

Answers (1)

Luis Mendo
Luis Mendo

Reputation: 112659

From your code, you want to fill the elements in the reshaped array using a dimension order which is the opposite of Matlab's column-major default; that is, you start from the last dimenson, then the second last, etc.

This can be done by reshaping into an array with the dimensions in reverse order (using reshape) and the reversing the order of dimensions back (using permute).

n_dimensions = numel(ndim);
Tensor = reshape(Data, ndim(end:-1:1)); % reshape with dimensions in reverse order
Tensor = permute(Tensor, n_dimensions:-1:1); % reverse back order of dimensions

Upvotes: 5

Related Questions