Coarsening for Algebraic Multigrid: Aggregation

Given a SPD matrix A, we describe an algebraic coarsening of a graph of A based on the concept of strong connectness and aggregation.

Contents

Usage of the function

clear all
help coarsenAMGa
  Parameters

Generate a test matrix

[node,elem] = squaremesh([0,1,0,1],1/32);

[node,elem] = circlemesh(0,0,1,1/11);
% [node,elem] = uniformrefine(node,elem);
% load lakemesh
% load bunny
[A,M] = assemblematrix(node,elem);
% A = M;  % test mass matrix. No coarsening is needed.
 - Min quality 0.8504 - Mean quality 0.9898 - Uniformity 2.94% 

Parameters

theta = 0.025;
N = size(A,1);
N0 = min(sqrt(N),10);       % number of the coarest nodes

Generate strong connectness matrix

D = spdiags(1./sqrt(diag(A)),0,N,N);
Am = D*A*D;  % normalize diagonal of A
[im,jm,sm] = find(Am);
idx = (-sm > theta);   % delete weakly connect off-diagonal and diagonal
As = sparse(im(idx),jm(idx),sm(idx),N,N); % matrix for strong connectness
As = As + speye(N);    % add diagonal
As1 = spones(As);      % graph of As
As2 = triu(As1*As1,1); % edges of the graph corresponding to As^2

Compute degree of vertex

deg = full(transpose(sum(As1))); % number of strongly connected neighbors
if sum(deg>0) < 0.1*sqrt(N)   % too few connected nodes e.g. A is mass matrix
    isC(round(rand(N0,1)*N)) = true; % randomly chose N0 nodes
    return                    % smoother is a good preconditioner
end
idx = (deg>0);
deg(idx) = deg(idx) + 0.1*rand(sum(idx),1); % break the equal degree case

Find an approximate maximal independent set and put to C set

isC = false(N,1);       % C: coarse node
isF = false(N,1);       % F: fine node
isU = true(N,1);
isS = true(N,1);          % S: selected set
isF(deg == 0) = true;   % isolated nodes are added into F set
% debug
close all;
% aggregrate numbering and pointer
aggN = 0;
node2agg = zeros(N,1);
agg2node = zeros(N,1);

set(gcf,'Units','normal');
set(gcf,'Position',[0.5,0.5,0.5,0.5]);
% showmesh(node,elem);
findnode(node,isU,'noindex','Color','k','MarkerSize',32);
axis equal; axis off;
m = 1;
while sum(isC) < N/2 && sum(isS) >N0
    % Mark all undecided nodes
    isS = false(N,1);  % S: selected set, changing in the coarsening
    isS(deg>0) = true;
    S = find(isS);
%     isS(S(2:2:end)) = false;
%     S = S(1:2:end);

    % debug
    fprintf('Coarsening ... \n');

    % Find marked nodes with local maximum degree
%     showagg(node,deg);
    [i,j] = find(As2(S,S));    % i,j and i<j: edges of subgraph S
    idx = deg(S(i)) >= deg(S(j));     % compare degree of vertices
    isS(S(j(idx))) = false;  % remove vertices with smaller degree
    isS(S(i(~idx))) = false;
%     showmesh(node,elem);
    findnode(node,isS,'noindex','Color','m','MarkerSize',60);
    fprintf('Number of chosen points: %6.0u\n',sum(isS));
    snapnow

    % Add new agg
    isC(isS) = true;
    newC = find(isS);
    newAgg = aggN+(1:length(newC));
    aggN = aggN + length(newC);
    node2agg(newC) = newAgg;
    agg2node(newAgg) = newC;
%     showagg(node,node2agg);

    % Remove coarse nodes and neighboring nodes from undecided set
    U = find(isU);
    [i,j] = find(As(isU,newC)); %#ok<*NASGU> use original connectivity
    isF(U(i)) = true;        % neighbor of C nodes are F nodes
    isU = ~(isF | isC);      % U: undecided set
    node2agg(U(i)) = node2agg(newC(j));      % add neighbors into the same aggregrate

    % update degree of U
    deg(newC) = 0;           % remove new selected coarse grid nodes
    deg(U(i)) = 0;           % remove neighbors of new selected coarse grid nodes
    U = find(isU);
    [i,j] = find(As(U,isF)); % find neighbor of fine nodes
    deg(U(i)) = 0;              % remove neighbors of existing agg

    % plot
    figure(1);
%     showmesh(node,elem);
%     findnode(node,isU,'noindex','Color','k','MarkerSize',30);
%     findnode(node,isF,'noindex','Color','y','MarkerSize',48);
%     findnode(node,isC,'noindex','Color','r','MarkerSize',52);
    showagg(node,node2agg,agg2node,As);
    fprintf('Add neighboring nodes into exisitng aggregates. \n');
    snapnow
    m = m + 1;
end
agg2node = agg2node(1:max(node2agg));
fprintf('Apply %2.0u times and Number of Coarse Nodes: %6.0u\n',m,sum(isC));
Coarsening ... 
Number of chosen points:     26
Add neighboring nodes into exisitng aggregates. 
Coarsening ... 
Number of chosen points:     12
Add neighboring nodes into exisitng aggregates. 
Coarsening ... 
Number of chosen points:      4
Add neighboring nodes into exisitng aggregates. 
Apply  4 times and Number of Coarse Nodes:     42

Add left vertices to existing aggregate

while any(isU)
    U = find(isU);
    [i,j] = find(As(:,isU)); %#ok<*NASGU> neighboring nodes of U
    % j: undecided vertices; i: neighbor of j
    neighborAgg = node2agg(i); % agg number of neighbors
    idx = (neighborAgg > 0);   % a interior nodes could be left
    [nAgg,neighborAgg] = max(sparse(neighborAgg(idx),j(idx),1));
    % a undecided node could be next to several aggregrates. find the one
    % with maximal neighboring aggregates.
    isbdU = (nAgg > 0);      % find undecided nodes next to
    bdU = U(isbdU);          % the boundary of aggregates
    node2agg(bdU) = neighborAgg(isbdU);
    % remove bdU from U and add to F
    isF(bdU) = true;
    isU(bdU) = false;

%     findnode(node,bdU,'noindex','Color','m');
    showagg(node,node2agg,agg2node,As);
    fprintf('Add left nodes nodes to strongly connected aggregates.\n');
    snapnow
end
Add left nodes nodes to strongly connected aggregates.

Check the number of nodes in aggregates

figure;
hist(node2agg,max(node2agg));