0
votes

I am trying to use meshgrid in Matlab together with Chebfun to get rid of double for loops. I first define a quasi-matrix of N functions,

%Define functions of type Chebfun
N = 10; %number of functions
x = chebfun('x', [0 8]); %Domain
psi = [];
for i = 1:N 
psi = [psi sin(i.*pi.*x./8)];
end

A sample calculation would be to compute the double sum $\sum_{i,j=1}^10 psi(:,i).*psi(:,j)$. I can achieve this using two for loops in Matlab,

h = 0; 
for i = 1:N
for j = 1:N
h = h + psi(:,i).*psi(:,j);
end
end 

I then tried to use meshgrid to vectorize in the following way:

[i j] = meshgrid(1:N,1:N);
h = psi(:,i).*psi(:,j);

I get the error "Column index must be a vector of integers". How can I overcome this issue so that I can get rid of my double for loops and make my code a bit more efficient?

1

1 Answers

2
votes

BTW, Chebfun is not part of native MATLAB and you have to download it in order to run your code: http://www.chebfun.org/. However, that shouldn't affect how I answer your question.

Basically, psi is a N column matrix and it is your desire to add up products of all combinations of pairs of columns in psi. You have the right idea with meshgrid, but what you should do instead is unroll the 2D matrix of coordinates for both i and j so that they're single vectors. You'd then use this and create two N^2 column matrices that is in such a way where each column corresponds to that exact column numbers specified from i and j sampled from psi. You'd then do an element-wise multiplication between these two matrices and sum across all of the columns for each row. BTW, I'm going to use ii and jj as variables from the output of meshgrid instead of i and j. Those variables are reserved for the complex number in MATLAB and I don't want to overshadow those unintentionally.

Something like this:

%// Your code
N = 10; %number of functions
x = chebfun('x', [0 8]); %Domain
psi = [];
for i = 1:N 
psi = [psi sin(i.*pi.*x./8)];
end

%// New code
[ii,jj] = meshgrid(1:N, 1:N);

%// Create two matrices and sum
matrixA = psi(:, ii(:));
matrixB = psi(:, jj(:));
h = sum(matrixA.*matrixB, 2);

If you want to do away with the temporary variables, you can do it in one statement after calling meshgrid:

h = sum(psi(:, ii(:)).*psi(:, jj(:)), 2);

I don't have Chebfun installed, but we can verify that this calculates what we need with a simple example:

rng(123);
N = 10;
psi = randi(20, N, N);

Running this code with the above more efficient solution gives us:

>> h

h =

        8100
       17161
       10816
       12100
       14641
        9216
       10000
        8649
        9025
       11664

Also, running the above double for loop code also gives us:

>> h

h =

        8100
       17161
       10816
       12100
       14641
        9216
       10000
        8649
        9025
       11664

If you want to be absolutely sure, we can have both codes run with the outputs as separate variables, then check if they're equal:

%// Setup
rng(123);
N = 10;
psi = randi(20, N, N);

%// Old code
h = 0; 
for i = 1:N
    for j = 1:N
        h = h + psi(:,i).*psi(:,j);
    end
end 

%// New code
[ii,jj] = meshgrid(1:N, 1:N);
hnew = sum(psi(:, ii(:)).*psi(:, jj(:)), 2);

%// Check for equality
eql = isequal(h, hnew);

eql checks if both variables are equal, and we do get them as such:

>> eql

eql =

     1