modularity_dir.m 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124
  1. function [Ci,Q]=modularity_dir(A,gamma)
  2. %MODULARITY_DIR Optimal community structure and modularity
  3. %
  4. % Ci = modularity_dir(W);
  5. % [Ci Q] = modularity_dir(W);
  6. %
  7. % The optimal community structure is a subdivision of the network into
  8. % nonoverlapping groups of nodes in a way that maximizes the number of
  9. % within-group edges, and minimizes the number of between-group edges.
  10. % The modularity is a statistic that quantifies the degree to which the
  11. % network may be subdivided into such clearly delineated groups.
  12. %
  13. % Inputs:
  14. % W,
  15. % directed weighted/binary connection matrix
  16. % gamma,
  17. % resolution parameter (optional)
  18. % gamma>1, detects smaller modules
  19. % 0<=gamma<1, detects larger modules
  20. % gamma=1, classic modularity (default)
  21. %
  22. % Outputs:
  23. % Ci, optimal community structure
  24. % Q, maximized modularity
  25. %
  26. % Note:
  27. % This algorithm is essentially deterministic. The only potential
  28. % source of stochasticity occurs at the iterative finetuning step, in
  29. % the presence of non-unique optimal swaps. However, the present
  30. % implementation always makes the first available optimal swap and
  31. % is therefore deterministic.
  32. %
  33. % References:
  34. % Leicht and Newman (2008) Phys Rev Lett 100:118703.
  35. % Reichardt and Bornholdt (2006) Phys Rev E 74:016110.
  36. %
  37. % 2008-2016
  38. % Mika Rubinov, UNSW
  39. % Jonathan Power, WUSTL
  40. % Dani Bassett, UCSB
  41. % Xindi Wang, Beijing Normal University
  42. % Roan LaPlante, Martinos Center for Biomedical Imaging
  43. % Modification History:
  44. % Jul 2008: Original (Mika Rubinov)
  45. % Oct 2008: Positive eigenvalues made insufficient for division (Jonathan Power)
  46. % Dec 2008: Fine-tuning made consistent with Newman's description (Jonathan Power)
  47. % Dec 2008: Fine-tuning vectorized (Mika Rubinov)
  48. % Sep 2010: Node identities permuted (Dani Bassett)
  49. % Dec 2013: Gamma resolution parameter included (Mika Rubinov)
  50. % Dec 2013: Detection of maximum real part of eigenvalues enforced (Mika Rubinov)
  51. % Thanks to Mason Porter and Jack Setford, University of Oxford
  52. % Dec 2015: Single moves during fine-tuning enforced (Xindi Wang)
  53. % Jan 2017: Removed node permutation and updated documentation (Roan LaPlante)
  54. if ~exist('gamma','var')
  55. gamma = 1;
  56. end
  57. N=length(A); %number of vertices
  58. % n_perm = randperm(N); %DB: randomly permute order of nodes
  59. % A = A(n_perm,n_perm); %DB: use permuted matrix for subsequent analysis
  60. Ki=sum(A,1); %in-degree
  61. Ko=sum(A,2); %out-degree
  62. m=sum(Ki); %number of edges
  63. b=A-gamma*(Ko*Ki).'/m;
  64. B=b+b.'; %directed modularity matrix
  65. Ci=ones(N,1); %community indices
  66. cn=1; %number of communities
  67. U=[1 0]; %array of unexamined communites
  68. ind=1:N;
  69. Bg=B;
  70. Ng=N;
  71. while U(1) %examine community U(1)
  72. [V,D]=eig(Bg);
  73. [~,i1]=max(real(diag(D))); %maximal positive (real part of) eigenvalue of Bg
  74. v1=V(:,i1); %corresponding eigenvector
  75. S=ones(Ng,1);
  76. S(v1<0)=-1;
  77. q=S.'*Bg*S; %contribution to modularity
  78. if q>1e-10 %contribution positive: U(1) is divisible
  79. qmax=q; %maximal contribution to modularity
  80. Bg(logical(eye(Ng)))=0; %Bg is modified, to enable fine-tuning
  81. indg=ones(Ng,1); %array of unmoved indices
  82. Sit=S;
  83. while any(indg) %iterative fine-tuning
  84. Qit=qmax-4*Sit.*(Bg*Sit); %this line is equivalent to:
  85. [qmax,imax]=max(Qit.*indg); %for i=1:Ng
  86. Sit(imax)=-Sit(imax); % Sit(i)=-Sit(i);
  87. indg(imax)=nan; % Qit(i)=Sit.'*Bg*Sit;
  88. if qmax>q % Sit(i)=-Sit(i);
  89. q=qmax; %end
  90. S=Sit;
  91. end
  92. end
  93. if abs(sum(S))==Ng %unsuccessful splitting of U(1)
  94. U(1)=[];
  95. else
  96. cn=cn+1;
  97. Ci(ind(S==1))=U(1); %split old U(1) into new U(1) and into cn
  98. Ci(ind(S==-1))=cn;
  99. U=[cn U]; %#ok<AGROW>
  100. end
  101. else %contribution nonpositive: U(1) is indivisible
  102. U(1)=[];
  103. end
  104. ind=find(Ci==U(1)); %indices of unexamined community U(1)
  105. bg=B(ind,ind);
  106. Bg=bg-diag(sum(bg)); %modularity matrix for U(1)
  107. Ng=length(ind); %number of vertices in U(1)
  108. end
  109. s=Ci(:,ones(1,N)); %compute modularity
  110. Q=~(s-s.').*B/(2*m);
  111. Q=sum(Q(:));
  112. % Ci_corrected = zeros(N,1); % DB: initialize Ci_corrected
  113. % Ci_corrected(n_perm) = Ci; % DB: return order of nodes to the order used at the input stage.
  114. % Ci = Ci_corrected; % DB: output corrected community assignments