matlab coder: cannot transpose a matrix that is incorrectly deemed to be 3-D when it should always be 2-D

281 views Asked by At

I have a function (with the code given below) that I wish to convert into a MEX file. I am trying to use matlab coder to do so.

%% Inputs
dof = 3;
num_divs = 72;

ind_cr =
     0     0
     1     1
     1     2
     2     2
     1     3
     2     3
     3     3

ind_switch =
     1
     1
     1
     0
     1
     0
     0

len_stat_atoms =
           1
          72
        5184
          72
      373248
        5184
          72

num_stat_atoms =
   108
   111
   111
     3
   111
     3
     3

coordFile = 
    [3x1        double]
    [3x1        double]
    [3x72x3     double]
    [3x5184x3   double]
    [3x373248x4 double]

radii_cell = 
    [108x1x3      double]
    [111x72x3     double]
    [111x5184x3   double]
    [  3x72x3     double]
    [111x373248x4 double]
    [  3x5184x4   double]
    [  3x72x4     double]

stat_cell = 
    [3x1x108      double]
    [3x72x111     double]
    [3x5184x111   double]
    [3x72x3       double]
    [3x373248x111 double]
    [3x5184x3     double]
    [3x72x3       double]    


%% Code that calls function
for i = 1:(dof*(dof+1)/2+1)
    %% Load matrices
    radii_mat = radii_cell{i,1};
    stat_mat = stat_cell{i,1};
    if ind_switch(i)
        coordFile_mat = coordFile{ind_cr(i,2)+2};
    end
    %% Call the function
    potential_mat = func_test(i,coordFile_mat,radii_mat,stat_mat,...
        ind_cr,len_stat_atoms,num_stat_atoms,num_coord_atoms,...
        counter,num_divs,dof);
end


%% Function code
function potential_mat = func_test(i,coordFile_mat,radii_mat,stat_mat,...
    ind_cr,len_stat_atoms,num_stat_atoms,num_coord_atoms,...
    counter,num_divs,dof);

potential_mat = zeros(num_coord_atoms,num_divs^dof);
for j = 1:size(coordFile_mat,3)
    %% Compute distances
    a = zeros(3,len_stat_atoms(i));
    a = coordFile_mat(:,1:len_stat_atoms(i),j);

    b = zeros(3,len_stat_atoms(i),num_stat_atoms(i));
    b = repmat(a,[1 1 num_stat_atoms(i)]);

    c = zeros(1,len_stat_atoms(i),num_stat_atoms(i));
    c = sqrt(sum((b - stat_mat).^2,1));

    d = zeros(len_stat_atoms(i),num_stat_atoms(i));
    d = shiftdim(c,1);

    distances = zeros(num_stat_atoms(i),len_stat_atoms(i));
    distances = d';

    %% Compute clashes and potentials
    clashes = distances < radii_mat(:,:,j);
    potentials = zeros(size(distances));
    potentials(clashes) = (1-(distances(clashes)./radii_mat(find(clashes)+numel(clashes)*(j-1))).^6).^2;

    %% Iterate over nodes
    col = ind_cr(i,1); row = ind_cr(i,2);
    if col == 1
        ind_kron = repmat(1:size(potentials,2),[num_divs^(dof-row) 1]);
        potentials = potentials(:,ind_kron(:)');
    elseif row == dof
        vec_repmat = [1 num_divs^(col-1)];
        potentials = repmat(potentials,vec_repmat);
    elseif col > 0
        vec_repmat = [1 num_divs^(col-1)];
        ind_kron = repmat(1:size(potentials,2),[num_divs^(dof-row) 1]);
        potentials = repmat(potentials(:,ind_kron(:)'),vec_repmat);
    else
        potentials = repmat(sum(potentials),[1 num_divs^dof]);
    end
    counter = counter+1;
    potential_mat(counter,:) = sum(potentials,1);
end

end

The problem occurs at the second line below, where it throws an error because it cannot transpose an ND matrix.

d = shiftdim(c,1);
distances = d';

Matlab coder identifies c to be of size 1 x :? x :?, which is correct. The d = shiftdim(c,1) line should then yield a 2D matrix of size :? x :?, which I then transpose. However, it fails to correctly shift the dimensions of d, and gives it a size of :? x :? x :?. This then causes the transpose error. How can I resolve this problem? Furthermore, for my own edification, why is matlab coder unable to correctly assign the dimensions of my variables, specifically a, b, c, d, and distances?

1

There are 1 answers

0
chappjc On BEST ANSWER

The docs describe this as an Incompatibility with MATLAB in Determining Size of Variable-Size N-D Arrays (d is created in a loop, so seems to be variable size):

For variable-size N-D arrays, the size function can return a different result in generated code than in MATLAB. In generated code, size(A) returns a fixed-length output because it does not drop trailing singleton dimensions of variable-size N-D arrays. By contrast, size(A) in MATLAB returns a variable-length output because it drops trailing singleton dimensions.

For example, if the shape of array A is :?x:?x:? and size(A,3)==1, size(A) returns:

  • Three-element vector in generated code
  • Two-element vector in MATLAB code

The issue addressed in the above documentation pertains to the use of the size function. However, in your case, you just want to be able to transpose. The workaround is to use permute, since the transpose is a general case of permute:

% after shiftdim:
distances = permute(d,[2 1 3])   % same as d' for 2d array, but handles 3d

You could also cut out the shiftdim entirely:

distances = permute(c,[2 3 1])

Also, I don't have much experience with Coder, but does it really require all those initializations with zeros? They seem unnecessary.