1
1
#include <stdio.h>
2
2
#include <stdlib.h>
3
+ #include <math.h>
3
4
#include "VerticesGroup.h"
4
5
#include "matrix.h"
5
6
#include "spmat.h"
7
+ #include "defs.h"
6
8
7
9
VerticesGroup * createVerticesGroup () {
8
10
VerticesGroup * group = malloc (sizeof (VerticesGroup ));
9
11
group -> size = 0 ;
10
- group -> edgesMinusBHatSubMatrix = NULL ;
11
12
group -> edgeSubMatrix = NULL ;
12
- group -> bSubMatrix = NULL ;
13
- group -> bHatSubMatrix = NULL ;
13
+ group -> modularitySubMatrix = NULL ;
14
+ group -> modularityRowSums = NULL ;
15
+ group -> modularityAbsColSum = NULL ;
14
16
return group ;
15
17
}
16
18
@@ -24,14 +26,13 @@ void freeVerticesGroup(VerticesGroup *group) {
24
26
node = temp ;
25
27
} while (node != group -> first );
26
28
}
27
- if (group -> bHatSubMatrix != NULL ) {
28
- freeMatrix (group -> bHatSubMatrix );
29
- }
30
- if (group -> edgesMinusBHatSubMatrix != NULL ) {
31
- freeMatrix (group -> edgesMinusBHatSubMatrix );
32
- }
29
+
33
30
if (group -> edgeSubMatrix != NULL ) {
31
+ /* the modulary was calculated, so all related data should be freed */
34
32
group -> edgeSubMatrix -> free (group -> edgeSubMatrix );
33
+ freeMatrix (group -> modularitySubMatrix );
34
+ free (group -> modularityRowSums );
35
+ free (group -> modularityAbsColSum );
35
36
}
36
37
}
37
38
@@ -53,49 +54,31 @@ VertexNode *addVertexToGroup(VerticesGroup *group, int index) {
53
54
return node ;
54
55
}
55
56
56
- void removeVertexFromGroup (VerticesGroup * group , VertexNode * node ) {
57
- if (group -> first == node ) {
58
- if (group -> size == 1 ) {
59
- group -> first = NULL ;
60
- } else {
61
- group -> first = node -> next ;
62
- }
63
- }
64
- node -> prev -> next = node -> next ;
65
- node -> next -> prev = node -> prev ;
66
- group -> size -- ;
67
- free (node );
68
- }
69
-
70
57
/**
71
- * Adds a sequence of indices to the group.
72
- * @param group the group to which nodes are added.
73
- * @param sequence a sequence of integers, representing nodes in a graph.
74
- * @param length the length of the input sequence.
58
+ * Get the 1-norm of the modularity matrix
59
+ * @param group vertices group
60
+ * @return 1-norm
75
61
*/
76
- void addSequence (VerticesGroup * group , int * sequence , int length ) {
77
- int i ;
78
- for (i = 0 ; i < length ; ++ i )
79
- addVertexToGroup (group , sequence [i ]);
62
+ double getModularityMatrixNorm1 (VerticesGroup * group ) {
63
+ return group -> modularityAbsColSum [group -> highestColSumIndex ];
80
64
}
81
65
82
66
/**
83
- * Create sub matrix
84
- * @param A edges matrix
85
- * @param M degrees sum
86
- * @param group
87
- * @return Fills group->bSubMatrix and group->bHatSubMatrix.
67
+ * Calculate the modularity sub matrix in the VerticesGroup object
68
+ * @param G graph object
69
+ * @param group vertices group containing the modularity sub matrix
88
70
*/
89
- void calculateSubMatrix ( Matrix * A , int M , VerticesGroup * group ) {
71
+ void calculateModularitySubMatrix ( Graph * G , VerticesGroup * group ) {
90
72
VertexNode * node ;
91
- double * row , expectedEdges ;
73
+ double * row , modularityEntry ;
92
74
int i = 0 , j ;
93
75
if (group -> size != 0 ) {
94
- group -> edgeSubMatrix = spmat_allocate_list (group -> size );
95
- group -> edgesMinusBHatSubMatrix = createMatrix (group -> size );
96
- group -> bSubMatrix = createMatrix (group -> size );
97
- group -> bHatSubMatrix = createMatrix (group -> size );
98
76
group -> verticesArr = malloc (sizeof (int ) * group -> size );
77
+ group -> edgeSubMatrix = spmat_allocate_list (group -> size );
78
+ group -> modularitySubMatrix = createMatrix (group -> size );
79
+ group -> modularityRowSums = calloc (group -> size , sizeof (double ));
80
+ group -> modularityAbsColSum = calloc (group -> size , sizeof (double ));
81
+ group -> highestColSumIndex = 0 ;
99
82
row = malloc (sizeof (double ) * group -> size );
100
83
node = group -> first ;
101
84
do {
@@ -105,41 +88,111 @@ void calculateSubMatrix(Matrix *A, int M, VerticesGroup *group) {
105
88
} while (node != group -> first );
106
89
for (i = 0 ; i < group -> size ; i ++ ) {
107
90
for (j = 0 ; j < group -> size ; j ++ ) {
108
- row [j ] = readVal (A , group -> verticesArr [i ], group -> verticesArr [j ]);
109
- /* For each vertex v: A[v][0] + ... + A[v][n-1] = deg(v) */
110
- expectedEdges = A -> rowSums [group -> verticesArr [i ]] * A -> rowSums [group -> verticesArr [j ]] / M ;
111
- setVal (group -> edgesMinusBHatSubMatrix , i , j , - expectedEdges );
112
- setVal (group -> bSubMatrix , i , j , row [j ] - expectedEdges );
113
- /* the case where delta(i,j)=0 */
91
+ row [j ] = readVal (G -> adjMat , group -> verticesArr [i ], group -> verticesArr [j ]);
92
+ modularityEntry = row [j ] - readVal (G -> expectedEdges , i , j );
93
+ setVal (group -> modularitySubMatrix , i , j , modularityEntry );
94
+ group -> modularityRowSums [i ] += modularityEntry ;
114
95
if (i != j ) {
115
- setVal (group -> bHatSubMatrix , i , j , row [j ] - expectedEdges );
96
+ /* the case of non diagonal values.
97
+ * the modularity matrix is symmetric, so we can add row sums instead of columns */
98
+ group -> modularityAbsColSum [i ] += fabs (modularityEntry );
116
99
}
117
100
}
118
- /* the case where i=j and so delta(i,j)=1. we subtract deg(i) from B[g][i][j]. */
119
- setVal (group -> bHatSubMatrix , i , i , readVal (group -> bSubMatrix , i , i ) - group -> bSubMatrix -> rowSums [i ]);
120
- setVal (group -> edgesMinusBHatSubMatrix , i , i ,
121
- readVal (group -> edgesMinusBHatSubMatrix , i , i ) - group -> bSubMatrix -> rowSums [i ]);
101
+ /* handle diagonal values */
102
+ modularityEntry = readVal (group -> modularitySubMatrix , i , i ) - group -> modularityRowSums [i ];
103
+ setVal (group -> modularitySubMatrix , i , i , modularityEntry );
104
+ group -> modularityAbsColSum [i ] += fabs (modularityEntry );
105
+ if (group -> modularityAbsColSum [i ] >= getModularityMatrixNorm1 (group )) {
106
+ /* replace highest column absolute sum */
107
+ group -> highestColSumIndex = i ;
108
+ }
109
+ /* TODO: improve instead of adding row at a time */
122
110
group -> edgeSubMatrix -> add_row (group -> edgeSubMatrix , row , i );
123
111
}
124
112
125
113
free (row );
126
114
}
127
115
}
128
116
117
+ /**
118
+ * Multiply the modularity matrix of a sub group of vertices by an eigenvector: s_t*B*s
119
+ * @param group the vertices group of the modularity matrix
120
+ * @param s eigenvector to multiply by
121
+ * @param res the vector multiplication result, should be allocated
122
+ * @param bothSides boolean, if set to 0 will only multiply by s on the right,
123
+ * storing the result in res and returning the the norm of res
124
+ * @return multiplication result (or the vector's norm if bothSides=0)
125
+ */
126
+ double multiplyModularityByVector (Graph * G , VerticesGroup * group , double * s , double * res , int bothSides ) {
127
+ int i ;
128
+ double numRes = 0 ;
129
+ /* the common value of all rows of the multiplication of the expectedEdges (K) matrix by s */
130
+ double degreesCommon = 0 , modularityNorm1 = getModularityMatrixNorm1 (group );
131
+ group -> edgeSubMatrix -> mult (group -> edgeSubMatrix , s , res );
132
+ for (i = 0 ; i < group -> size ; i ++ ) {
133
+ degreesCommon += G -> degrees [i ] * s [i ];
134
+ res [i ] += (modularityNorm1 - group -> modularityRowSums [i ]) * s [i ];
135
+ }
136
+ for (i = 0 ; i < group -> size ; i ++ ) {
137
+ res [i ] -= G -> degrees [i ] * degreesCommon / G -> degreeSum ;
138
+ if (bothSides ) {
139
+ numRes += s [i ] * res [i ];
140
+ } else {
141
+ numRes += res [i ] * res [i ];
142
+ }
143
+ }
144
+ if (!bothSides ) {
145
+ /* if the result is a vector, we return its norm */
146
+ numRes = sqrt (numRes );
147
+ }
148
+ return numRes ;
149
+ }
150
+
129
151
/**
130
152
* Calculate modularity delta of group's division given by an eigenvector
131
153
* @param group
132
154
* @param s eigenvector
133
- * @return
155
+ * @return modularity
134
156
*/
135
- double calculateModularity (VerticesGroup * group , double * s ) {
157
+ double calculateModularity (Graph * G , VerticesGroup * group , double * s ) {
136
158
double * res , numRes ;
137
159
res = malloc (group -> size * sizeof (double ));
138
- group -> edgeSubMatrix -> mult (group -> edgeSubMatrix , s , res );
139
- numRes = vectorMult (s , res , group -> size );
140
- matrixVectorMult (group -> edgesMinusBHatSubMatrix , s , res );
141
- numRes -= vectorMult (s , res , group -> size );
160
+ numRes = multiplyModularityByVector (G , group , s , res , 1 );
142
161
numRes *= 0.5 ;
143
162
free (res );
144
163
return numRes ;
145
164
}
165
+
166
+ /**
167
+ * Perform the power iteration algorithm
168
+ * @param group a vertices group, containing the modularity sub matrix
169
+ * @param vector initial vector for the algorithm
170
+ * @param vectorResult the eigenvector found by the algorithm, should be allocated
171
+ * @return the eigenvalue of the eigenvector 'vectorResult'.
172
+ */
173
+ double powerIteration (Graph * G , VerticesGroup * group , double * vector , double * vectorResult ) {
174
+ int i , con = 1 ;
175
+ double vectorNorm , dif , lambda , x , y ;
176
+ while (con ) {
177
+ x = y = 0 ;
178
+ vectorNorm = multiplyModularityByVector (G , group , vector , vectorResult , 0 );
179
+ con = 0 ;
180
+ /* printf("\n\n\ni\tvectorResult[i]\tvectorResult[i]/vectorSize\tvector[i]\tdiff\tsum\n"); */
181
+ for (i = 0 ; i < group -> size ; i ++ ) {
182
+ /* printf("%d\t%f\t%f\t%f\t%f\t%f\n", i,vectorResult[i], vectorResult[i]/vectorSize,vector[i], fabs(vectorResult[i]/vectorSize - vector[i]), vectorResult[i]/vectorSize + vector[i]); */
183
+ x += vector [i ] * vectorResult [i ];
184
+ y += vector [i ] * vector [i ];
185
+ vectorResult [i ] /= vectorNorm ;
186
+ dif = fabs (vectorResult [i ] - vector [i ]);
187
+ if (IS_POSITIVE (dif )) {
188
+ con = 1 ;
189
+ }
190
+ vector [i ] = vectorResult [i ];
191
+ }
192
+ }
193
+
194
+ /* compute the corresponding eigenvalue (with respect to the un-shifted B_hat) */
195
+ lambda = x / y ;
196
+ lambda -= getModularityMatrixNorm1 (group );
197
+ return lambda ;
198
+ }
0 commit comments