3

I have two tensors: A is a second order tensor and B is a fourth order tensor. I know that when computing the double dot product (:) of two tensors, the rank of the resulting tensor will be decreased by two, so in my example the result should be a second order tensor.

However, when I write this code in MATLAB, it gives the following error:

Matrix dimensions must agree.

How can I solve this problem?

Eitan T
  • 32,660
  • 14
  • 72
  • 109
ISara sky
  • 35
  • 1
  • 1
  • 4

2 Answers2

3

The colon operator in MATLAB doesn't do what you expect, as it serves another functionality. In fact, there is no built-in implementation for a double inner product in MATLAB. You need to implement it by yourself, for instance:

idx = max(0, ndims(A) - 1); %// Index of first common dimension
B_t = permute(B, circshift(1:ndims(A) + ndims(B), [0, idx - 1]));
double_dot_prod = squeeze(sum(squeeze(sum(bsxfun(@times, A, B_t), idx)), idx));

where A and B are your tensors (i.e multi-dimensional matrices). Vectorizing this was a hard nut to crack, so I hope I got the math right!

If you want, you can put this code in a function for convenience. For the sake of good practice, also verify that both tensors are of second rank or higher. Here's a friendly copy-paste version for you:

function C = double_dot(A, B)
    assert(~isvector(A) && ~isvector(B))
    idx = max(0, ndims(A) - 1);
    B_t = permute(B, circshift(1:ndims(A) + ndims(B), [0, idx - 1]));
    C = squeeze(sum(squeeze(sum(bsxfun(@times, A, B_t), idx)), idx));

A word of advice: I suggest that you read online tutorials to get yourself familiar with the basics of the MATLAB language.

Eitan T
  • 32,660
  • 14
  • 72
  • 109
2

It's very unfortunate, but MATLAB has not implemented an inner product of tensors in their standard library to my knowledge. To produce a scalar version of the inner product, you need to either inefficiently iterate through each entry like:

function C = double_dot(A,B)
    for i=1:1:3
        for j=1:1:3
            C = C + A(i,j)*B(i,j);
        end
    end

Or you can run a slight modification of Eitan's vectorized code (above). His code produces a vector. The inner product of two tensors should be a scalar. So you need to sum across the final array that his code produces.

function C = double_dot(A, B)
    assert(~isvector(A) && ~isvector(B))
    idx = max(0, ndims(A) - 1);
    B_t = permute(B, circshift(1:ndims(A) + ndims(B), [0, idx - 1]));
    C = sum(squeeze(sum(squeeze(sum(bsxfun(@times, A, B_t), idx)), idx)));

Eitan's code is an implementation of the dot function in matlab (see https://www.mathworks.com/help/matlab/ref/dot.html). Note the section on the dot product of matricies. Instead you should more simply use:

function C = double_dot(A,B)
    C = sum(dot(A,B));
dlontine
  • 21
  • 1