简体   繁体   English

在MATLAB中构造邻接矩阵

[英]Construct adjacency matrix in MATLAB

Consider a set of points arranged on a grid of size N-by-M. 考虑布置在N×M大小的网格上的一组点。 I am trying to build the adjacency matrix such that neighboring points are connected. 我试图建立邻接矩阵,以便相邻点连接。

For example, in a 3x3 grid with a graph: 例如,在带有图形的3x3网格中:

1-2-3
| | |
4-5-6
| | |
7-8-9

We should have the corresponding adjacency matrix: 我们应该有相应的邻接矩阵:

+---+------------------------------------------------------+
|   |   1     2     3     4     5     6     7     8     9  |
+---+------------------------------------------------------+
| 1 |   0     1     0     1     0     0     0     0     0  |
| 2 |   1     0     1     0     1     0     0     0     0  |
| 3 |   0     1     0     0     0     1     0     0     0  |
| 4 |   1     0     0     0     1     0     1     0     0  |
| 5 |   0     1     0     1     0     1     0     1     0  |
| 6 |   0     0     1     0     1     0     0     0     1  |
| 7 |   0     0     0     1     0     0     0     1     0  |
| 8 |   0     0     0     0     1     0     1     0     1  |
| 9 |   0     0     0     0     0     1     0     1     0  |
+---+------------------------------------------------------+

As a bonus, the solution should work for both 4- and 8-connected neighboring points, that is: 另外,该解决方案应适用于4和8连接的相邻点,即:

   o             o  o  o
o  X  o   vs.    o  X  o
   o             o  o  o

This the code that I have so far: 这是我到目前为止的代码:

N = 3; M = 3;
adj = zeros(N*M);

for i=1:N
    for j=1:M
        k = sub2ind([N M],i,j);
        if i>1
            ii=i-1; jj=j;
            adj(k,sub2ind([N M],ii,jj)) = 1; 
        end
        if i<N
            ii=i+1; jj=j;
            adj(k,sub2ind([N M],ii,jj)) = 1; 
        end
        if j>1
            ii=i; jj=j-1;
            adj(k,sub2ind([N M],ii,jj)) = 1; 
        end
        if j<M
            ii=i; jj=j+1;
            adj(k,sub2ind([N M],ii,jj)) = 1; 
        end
    end
end

How can this improved to avoid all the looping? 如何改进以避免所有循环?

If you notice, there is a distinct pattern to the adjacency matrices you are creating. 如果您注意到,正在创建的邻接矩阵有一个独特的模式。 Specifically, they are symmetric and banded . 具体来说,它们是对称且带状的 You can take advantage of this fact to easily create your matrices using the diag function (or the spdiags function if you want to make a sparse matrix). 您可以利用这个事实来轻松地使用diag函数(或spdiags函数,如果要创建稀疏矩阵)来创建矩阵。 Here is how you can create the adjacency matrix for each case, using your sample matrix above as an example: 以下是使用上面的示例矩阵作为示例的每种情况下创建邻接矩阵的方法:

4-connected neighbors: 4个连接的邻居:

mat = [1 2 3; 4 5 6; 7 8 9];                 % Sample matrix
[r, c] = size(mat);                          % Get the matrix size
diagVec1 = repmat([ones(c-1, 1); 0], r, 1);  % Make the first diagonal vector
                                             %   (for horizontal connections)
diagVec1 = diagVec1(1:end-1);                % Remove the last value
diagVec2 = ones(c*(r-1), 1);                 % Make the second diagonal vector
                                             %   (for vertical connections)
adj = diag(diagVec1, 1)+diag(diagVec2, c);   % Add the diagonals to a zero matrix
adj = adj+adj.';                             % Add the matrix to a transposed copy of
                                             %   itself to make it symmetric

And you'll get the following matrix: 您将获得以下矩阵:

adj =

     0  1  0  1  0  0  0  0  0
     1  0  1  0  1  0  0  0  0
     0  1  0  0  0  1  0  0  0
     1  0  0  0  1  0  1  0  0
     0  1  0  1  0  1  0  1  0
     0  0  1  0  1  0  0  0  1
     0  0  0  1  0  0  0  1  0
     0  0  0  0  1  0  1  0  1
     0  0  0  0  0  1  0  1  0


8-connected neighbors: 8个相连的邻居:

mat = [1 2 3; 4 5 6; 7 8 9];                 % Sample matrix
[r, c] = size(mat);                          % Get the matrix size
diagVec1 = repmat([ones(c-1, 1); 0], r, 1);  % Make the first diagonal vector
                                             %   (for horizontal connections)
diagVec1 = diagVec1(1:end-1);                % Remove the last value
diagVec2 = [0; diagVec1(1:(c*(r-1)))];       % Make the second diagonal vector
                                             %   (for anti-diagonal connections)
diagVec3 = ones(c*(r-1), 1);                 % Make the third diagonal vector
                                             %   (for vertical connections)
diagVec4 = diagVec2(2:end-1);                % Make the fourth diagonal vector
                                             %   (for diagonal connections)
adj = diag(diagVec1, 1)+...                  % Add the diagonals to a zero matrix
      diag(diagVec2, c-1)+...
      diag(diagVec3, c)+...
      diag(diagVec4, c+1);
adj = adj+adj.';                             % Add the matrix to a transposed copy of
                                             %   itself to make it symmetric

And you'll get the following matrix: 您将获得以下矩阵:

adj =

     0  1  0  1  1  0  0  0  0
     1  0  1  1  1  1  0  0  0
     0  1  0  0  1  1  0  0  0
     1  1  0  0  1  0  1  1  0
     1  1  1  1  0  1  1  1  1
     0  1  1  0  1  0  0  1  1
     0  0  0  1  1  0  0  1  0
     0  0  0  1  1  1  1  0  1
     0  0  0  0  1  1  0  1  0

Just for fun, here's a solution to construct the adjacency matrix by computing the distance between all pairs of points on the grid (not the most efficient way obviously) 只是为了好玩,这是一种通过计算网格上所有对点之间的距离来构造邻接矩阵的解决方案(显然不是最有效的方法)

N = 3; M = 3;                  %# grid size
CONNECTED = 8;                 %# 4-/8- connected points

%# which distance function
if CONNECTED == 4,     distFunc = 'cityblock';
elseif CONNECTED == 8, distFunc = 'chebychev'; end

%# compute adjacency matrix
[X Y] = meshgrid(1:N,1:M);
X = X(:); Y = Y(:);
adj = squareform( pdist([X Y], distFunc) == 1 );

And here's some code to visualize the adjacency matrix and the graph of connected points: 这是一些代码,用于可视化邻接矩阵和连接点图:

%# plot adjacency matrix
subplot(121), spy(adj)

%# plot connected points on grid
[xx yy] = gplot(adj, [X Y]);
subplot(122), plot(xx, yy, 'ks-', 'MarkerFaceColor','r')
axis([0 N+1 0 M+1])
%# add labels
[X Y] = meshgrid(1:N,1:M);
X = reshape(X',[],1) + 0.1; Y = reshape(Y',[],1) + 0.1;
text(X, Y(end:-1:1), cellstr(num2str((1:N*M)')) )

8_已连接4_已连接

I just found this question when searching for the same problem. 我在搜索相同问题时才发现此问题。 However, none of the provided solutions worked for me because of the problem size which required the use of sparse matrix types. 但是,由于问题大小需要使用稀疏矩阵类型,因此所提供的解决方案都不适合我。 Here is my solution which works on large scale instances: 这是我的解决方案,适用于大规模实例:

function W = getAdjacencyMatrix(I)

[m, n] = size(I);

I_size = m*n;

% 1-off diagonal elements
V = repmat([ones(m-1,1); 0],n, 1);
V = V(1:end-1); % remove last zero

% n-off diagonal elements
U = ones(m*(n-1), 1);

% get the upper triangular part of the matrix
W = sparse(1:(I_size-1),    2:I_size, V, I_size, I_size)...
  + sparse(1:(I_size-m),(m+1):I_size, U, I_size, I_size);

% finally make W symmetric
W = W + W';

Just came across this question. 刚遇到这个问题。 I have a nice working m-function (link: sparse_adj_matrix.m ) that is quite general. 我有一个很好的正常工作的m函数(链接: sparse_adj_matrix.m )。

It can handle 4-connect grid (radius 1 according to L1 norm), 8-connect grid (radius 1 according to L_infty norm). 它可以处理4个连接网格(根据L1规范的半径1),8个连接网格(根据L_infty规范的半径1)。
It can also support 3D (and arbitrarily higher domensional grids). 它还可以支持3D(以及任意更高的三维网格)。
The function can also connect nodes further than radius = 1. 该函数还可以连接半径= 1以外的节点。

Here's the signiture of the function: 这是函数的签名:


% Construct sparse adjacency matrix (provides ii and jj indices into the
% matrix)
%
% Usage:
%   [ii jj] = sparse_adj_matrix(sz, r, p)
%
% inputs:
%   sz - grid size (determine the number of variables n=prod(sz), and the
%        geometry/dimensionality)
%   r  - the radius around each point for which edges are formed
%   p  - in what p-norm to measure the r-ball, can be 1,2 or 'inf'
%
% outputs
%   ii, jj - linear indices into adjacency matrix (for each pair (m,n)
%   there is also the pair (n,m))
%
% How to construct the adjacency matrix?
% >> A = sparse(ii, jj, ones(1,numel(ii)), prod(sz), prod(sz));
%
%
% Example:
% >> [ii jj] = sparse_adj_matrix([10 20], 1, inf);
% construct indices for 200x200 adjacency matrix for 8-connect graph over a
% grid of 10x20 nodes.
% To visualize the graph:
% >> [r c]=ndgrid(1:10,1:20);
% >> A = sparse(ii, jj, 1, 200, 200);;
% >> gplot(A, [r(:) c(:)]);

Your current code doesn't seem so bad. 您当前的代码似乎还不错。 One way or another you need to iterate over all neighbor pairs. 您需要一种或另一种方式遍历所有邻居对。 If you really need to optimize the code, I would suggest: 如果您确实需要优化代码,我建议:

  • loop over node indices i, where 1 <= i <= (N*M) 循环遍历节点索引i,其中1 <= i <= (N*M)
  • don't use sub2ind() for efficiency, the neighbors of node i are simpy [iM, i+1, i+M, i-1] in clockwise order 不要使用sub2ind()来提高效率,节点i的邻居按顺时针顺序为simpy [iM, i+1, i+M, i-1]

Notice that to get all neighbor pairs of nodes: 请注意,要获取所有邻居对节点:

  • you only have to compute the "right" neighbors (ie horizontal edges) for nodes i % M != 0 (since Matlab isn't 0-based but 1-based) 您只需要计算i % M != 0节点的“正确”邻居(即水平边缘)(因为Matlab不是基于0而是基于1)
  • you only have to compute "above" neighbors (ie vertical edges) for nodes i > M 您只需要计算节点i > M “上方”邻居(即垂直边缘)
  • there is a similar rule for diagonal edges 对角线边缘也有类似的规则

This would leed to a single loop (but same number of N*M iterations), doesn't call sub2ind(), and has only two if statements in the loop. 这将导致一个循环(但N * M迭代次数相同),不调用sub2ind(),并且循环中只有两个if语句。

For each node in the graph add a connection to the right and one downwards. 对于图中的每个节点,在右侧添加一个连接,在下方添加一个连接。 Check that you don't overreach your grid. 检查您没有超出网格范围。 Consider the following function that builds the adjacency matrix. 考虑以下构建邻接矩阵的函数。

function  adj = AdjMatrixLattice4( N, M )
    % Size of adjacency matrix
    MN = M*N;
    adj = zeros(MN,MN);

    % number nodes as such
    %  [1]---[2]-- .. --[M]
    %   |     |          |
    % [M+1]-[M+2]- .. -[2*M]
    %   :     :          :
    %   []    []   ..  [M*N]     

    for i=1:N
        for j=1:N
            A = M*(i-1)+j;          %Node # for (i,j) node
            if(j<N)                
                B = M*(i-1)+j+1;    %Node # for node to the right
                adj(A,B) = 1;
                adj(B,A) = 1;
            end
            if(i<M)
                B = M*i+j;          %Node # for node below
                adj(A,B) = 1;       
                adj(B,A) = 1;
            end            
        end
    end    
end

Example as above AdjMatrixLattice4(3,3)= 上面的示例AdjMatrixLattice4(3,3)=

 0     1     0     1     0     0     0     0     0
 1     0     1     0     1     0     0     0     0
 0     1     0     0     0     1     0     0     0
 1     0     0     0     1     0     1     0     0
 0     1     0     1     0     1     0     1     0
 0     0     1     0     1     0     0     0     1
 0     0     0     1     0     0     0     1     0
 0     0     0     0     1     0     1     0     1
 0     0     0     0     0     1     0     1     0

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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