简体   繁体   中英

Cost-effective creation of a symmetric matrix in MATLAB

I'm fairly new to MATLAB and have a piece of code which creates a distance matrix. To be more precise, it creates a distance matrix D between points that lie on an undirected graph, such that Dij is the shortest path between the points on that graph. This matrix is obviously symmetric (because the graph is undirected) and the following is the code snippet that I use to create it:

D = zeros(size(data,1));
for i = 1:size(data, 1)
    for j = 1:size(data, 1)
        [D(i, j), ~, ~] = graphshortestpath(G, i, j, 'Directed', false);
    end
end

This is obviously very wasteful, since I'm not exploiting the symmetry of the matrix. Is there any way in which I can compute only the upper triangular part of the matrix and then somehow "append" the lower triangular part to it, such that I reduce my computations from n^2 to n^2 / 2?

Any help appreciated,

Jason

Sure. Just think about the order of iteration, to figure out which triangle is reached first.

D = zeros(size(data,1));
for i = 1:size(data, 1)
    for j = 1:size(data, 1)
        if j > i
            [D(i, j), ~, ~] = graphshortestpath(G, i, j, 'Directed', false);
        else
            D(i, j) = D(j, i);
        end
    end
end

If diagonal elements aren't identically zero, you can use if j >= i instead.

For undirected and unweighted graph, an alternative way of computing Distance matrix

May help if u are trying to reduce your runtime. In the case of Matlab, most of the time, I find scanning entry by entry is slower. I am just guessing your purpose of asking the question, sorry if I am out of topic.

Given a Adjacency Matix ( G ), I would compute the distance matrix in following way,

Assumptions: 1. G is undirected & unweighted ( matrix filled with '0' and '1' ) 2. N is the order of the graph with G is of size N x N

function [D,connect]=genDistance(G,N)

D = G;
B = G;
connect = 0;
i=1;
while((~connect)&&(i<N-1))    % the maximum distance from one vert to another
    i = i + 1;                % is N-1
    B = B * G;                % G to the power of i
    D = D + i * (D==0&B>0);   % D==0 & B>0 the entries to be updated 
    connect = ( min(min(D)) )>0;  %check if D has zero entry
end
D ( eye(N) ) = 0 ; %clear diagonal entries
  • (i,j) entry in "G power k" will give you the number of walks of length k from Vi to Vj in G
  • in the end, connect will tell you whether the graph is connected

You can generate indices for the lower part of the matrix G with

N = length(G);
[irow, icol] = find(tril(ones(N),-1));

Then you can loop through those indices:

D = zeros(size(G));
for i = 1:numel(irow)
   [D(irow(i), icol(i)] = graphshortestpath(G, irow(i), icol(i), 'Directed', false);
end
D = D + D';

Another option is to use ARRAYFUN with those indices and SQUAREFORM to convert the resulted vector into a square matrix:

D = arrayfun(@(x,y) graphshortestpath(G,x,y, 'Directed', false), irow, icol);
D = squareform(D);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM