Line data Source code
1 : //------------------------------------------------------------------------------
2 : // LAGraph_FastGraphletTransform: fast graphlet transform
3 : //------------------------------------------------------------------------------
4 :
5 : // LAGraph, (c) 2019-2022 by The LAGraph Contributors, All Rights Reserved.
6 : // SPDX-License-Identifier: BSD-2-Clause
7 : //
8 : // For additional details (including references to third party source code and
9 : // other files) see the LICENSE file or contact permission@sei.cmu.edu. See
10 : // Contributors.txt for a full list of contributors. Created, in part, with
11 : // funding and support from the U.S. Government (see Acknowledgments.txt file).
12 : // DM22-0790
13 :
14 : // Contributed by Tanner Hoke, Texas A&M University
15 :
16 : //------------------------------------------------------------------------------
17 :
18 : // LAGraph_FastGraphletTransform: computes the Fast Graphlet Transform of
19 : // an undirected graph. No self edges are allowed on the input graph.
20 :
21 : // TODO: rename this, and add to src (but it uses GxB)
22 :
23 : // https://arxiv.org/pdf/2007.11111.pdf
24 :
25 : //------------------------------------------------------------------------------
26 : #define F_UNARY(f) ((void (*)(void *, const void *)) f)
27 :
28 : #define LG_FREE_WORK \
29 : { \
30 : GrB_free (&C_3) ; \
31 : GrB_free (&d_0) ; \
32 : GrB_free (&d_1) ; \
33 : GrB_free (&d_2) ; \
34 : GrB_free (&d_3) ; \
35 : GrB_free (&d_4) ; \
36 : GrB_free (&d_5) ; \
37 : GrB_free (&d_6) ; \
38 : GrB_free (&d_7) ; \
39 : GrB_free (&d_8) ; \
40 : GrB_free (&d_9) ; \
41 : GrB_free (&d_10) ; \
42 : GrB_free (&d_11) ; \
43 : GrB_free (&d_12) ; \
44 : GrB_free (&d_13) ; \
45 : GrB_free (&d_14) ; \
46 : GrB_free (&d_15) ; \
47 : GrB_free (&d_2) ; \
48 : GrB_free (&v) ; \
49 : GrB_free (&p_1_minus_one) ; \
50 : GrB_free (&p_1_minus_two) ; \
51 : GrB_free (&two_c_3) ; \
52 : GrB_free (&p_1_p_1_had) ; \
53 : GrB_free (&C_42) ; \
54 : GrB_free (&P_2) ; \
55 : GrB_free (&D_1) ; \
56 : GrB_free (&D_4c) ; \
57 : GrB_free (&D_43) ; \
58 : GrB_free (&U_inv) ; \
59 : GrB_free (&F_raw) ; \
60 : GrB_free (&C_4) ; \
61 : GrB_free (&Sub_one_mult) ; \
62 : GrB_free (&T) ; \
63 : if (A_Tiles != NULL) \
64 : { \
65 : for (int i = 0; i < tile_cnt; ++i) GrB_free (&A_Tiles [i]) ; \
66 : } \
67 : if (D_Tiles != NULL) \
68 : { \
69 : for (int i = 0; i < tile_cnt; ++i) GrB_free (&D_Tiles [i]) ; \
70 : } \
71 : if (C_Tiles != NULL) \
72 : { \
73 : for (int i = 0; i < tile_cnt; ++i) GrB_free (&C_Tiles [i]) ; \
74 : } \
75 : LAGraph_Free ((void **) &neighbors, msg) ; \
76 : LAGraph_Free ((void **) &k4cmn, msg) ; \
77 : LAGraph_Free ((void **) &f15, msg) ; \
78 : LAGraph_Free ((void **) &I, msg) ; \
79 : LAGraph_Free ((void **) &isNeighbor, msg) ; \
80 : LAGraph_Free ((void **) &J, msg) ; \
81 : LAGraph_Free ((void **) &vals, msg) ; \
82 : LAGraph_Free ((void **) &A_Tiles, msg) ; \
83 : LAGraph_Free ((void **) &D_Tiles, msg) ; \
84 : LAGraph_Free ((void **) &C_Tiles, msg) ; \
85 : LAGraph_Free ((void **) &Tile_nrows, msg) ; \
86 : }
87 :
88 : #define LG_FREE_ALL \
89 : { \
90 : LG_FREE_WORK ; \
91 : }
92 :
93 : #define F_UNARY(f) ((void (*)(void *, const void *)) f)
94 :
95 : #include "LG_internal.h"
96 : #include "LAGraphX.h"
97 :
98 993 : void sub_one_mult (int64_t *z, const int64_t *x) { (*z) = (*x) * ((*x)-1) ; }
99 :
100 2 : int LAGraph_FastGraphletTransform
101 : (
102 : // outputs:
103 : GrB_Matrix *F_net, // 16-by-n matrix of graphlet counts
104 : // inputs:
105 : LAGraph_Graph G,
106 : bool compute_d_15, // probably this makes most sense
107 : char *msg
108 : )
109 : {
110 : #if LAGRAPH_SUITESPARSE
111 :
112 2 : LG_CLEAR_MSG ;
113 2 : GrB_Index const U_inv_I[] = {0, 1, 2, 2, 3, 3, 4, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 9, 9, 9, 10, 10, 10, 10, 11, 11, 11, 12, 12, 12, 12, 13, 13, 14, 14, 15} ;
114 2 : GrB_Index const U_inv_J[] = {0, 1, 2, 4, 3, 4, 4, 5, 9, 10, 12, 13, 14, 15, 6, 10, 11, 12, 13, 14, 15, 7, 9, 10, 13, 14, 15, 8, 11, 14, 15, 9, 13, 15, 10, 13, 14, 15, 11, 14, 15, 12, 13, 14, 15, 13, 15, 14, 15, 15} ;
115 2 : int64_t const U_inv_X[] = {1, 1, 1, -2, 1, -1, 1, 1, -2, -1, -2, 4, 2, -6, 1, -1, -2, -2, 2, 4, -6, 1, -1, -1, 2, 1, -3, 1, -1, 1, -1, 1, -2, 3, 1, -2, -2, 6, 1, -2, 3, 1, -1, -1, 3, 1, -3, 1, -3, 1} ;
116 2 : GrB_Index const U_inv_nvals = 50;
117 2 : GrB_UnaryOp Sub_one_mult = NULL ;
118 2 : int tile_cnt = 0 ;
119 2 : GrB_Matrix *A_Tiles = NULL ;
120 2 : GrB_Matrix *D_Tiles = NULL ;
121 2 : GrB_Matrix *C_Tiles = NULL ;
122 2 : GrB_Index *Tile_nrows = NULL ;
123 2 : GrB_Matrix T = NULL ;
124 :
125 2 : GrB_Index *neighbors = NULL ;
126 2 : GrB_Index *k4cmn = NULL ;
127 2 : int64_t *f15 = NULL ;
128 2 : GrB_Index *I = NULL ;
129 2 : int *isNeighbor = NULL ;
130 2 : GrB_Index *J = NULL ;
131 2 : int64_t *vals = NULL ;
132 :
133 2 : GrB_Matrix C_3 = NULL,
134 2 : A = NULL,
135 2 : C_42 = NULL,
136 2 : P_2 = NULL,
137 2 : D_1 = NULL,
138 2 : D_4c = NULL,
139 2 : D_43 = NULL,
140 2 : U_inv = NULL,
141 2 : F_raw = NULL,
142 2 : C_4 = NULL ;
143 :
144 2 : GrB_Vector d_0 = NULL,
145 2 : d_1 = NULL,
146 2 : d_2 = NULL,
147 2 : d_3 = NULL,
148 2 : d_4 = NULL,
149 2 : d_5 = NULL,
150 2 : d_6 = NULL,
151 2 : d_7 = NULL,
152 2 : d_8 = NULL,
153 2 : d_9 = NULL,
154 2 : d_10 = NULL,
155 2 : d_11 = NULL,
156 2 : d_12 = NULL,
157 2 : d_13 = NULL,
158 2 : d_14 = NULL,
159 2 : d_15 = NULL;
160 :
161 2 : GrB_Vector v = NULL,
162 2 : two_c_3 = NULL,
163 2 : p_1_minus_one = NULL,
164 2 : p_1_minus_two = NULL,
165 2 : p_1_p_1_had = NULL ;
166 :
167 : GrB_Index nvals ;
168 : int64_t ntri ;
169 :
170 2 : A = G->A ;
171 :
172 : GrB_Index n ;
173 2 : GRB_TRY (GrB_Matrix_nrows (&n, A)) ;
174 :
175 : //--------------------------------------------------------------------------
176 : // compute d_0 = e
177 : //--------------------------------------------------------------------------
178 :
179 : // d_0 = e
180 2 : GRB_TRY (GrB_Vector_new (&d_0, GrB_INT64, n)) ;
181 2 : GRB_TRY (GrB_assign (d_0, NULL, NULL, 1, GrB_ALL, n, NULL)) ;
182 :
183 : //--------------------------------------------------------------------------
184 : // compute d_1 = Ae (in_degree)
185 : //--------------------------------------------------------------------------
186 :
187 : // GRB_TRY (GrB_Vector_new (&d_1, GrB_INT64, n)) ;
188 :
189 : // d_1 = Ae (in_degree)
190 2 : LG_TRY (LAGraph_Cached_OutDegree (G, msg)) ;
191 :
192 2 : GRB_TRY (GrB_Vector_dup (&d_1, G->out_degree)) ;
193 :
194 : //--------------------------------------------------------------------------
195 : // compute d_2 = p_2
196 : //--------------------------------------------------------------------------
197 :
198 2 : GRB_TRY (GrB_Vector_new (&d_2, GrB_INT64, n)) ;
199 :
200 : // TODO: use LAGraph_plus_second_int64
201 : // d_2 = p_2 = A*p_1 - c_2 = A*d_1 - d_1
202 2 : GRB_TRY (GrB_mxv (d_2, NULL, NULL, GxB_PLUS_SECOND_INT64, A, d_1, NULL)) ;
203 2 : GRB_TRY (GrB_eWiseMult (d_2, NULL, NULL, GrB_MINUS_INT64, d_2, d_1, NULL)) ;
204 :
205 : //--------------------------------------------------------------------------
206 : // compute d_3 = hadamard(p_1, p_1 - 1) / 2
207 : //--------------------------------------------------------------------------
208 :
209 2 : GRB_TRY (GrB_Vector_new (&d_3, GrB_INT64, n)) ;
210 :
211 2 : GRB_TRY (GrB_UnaryOp_new (&Sub_one_mult, F_UNARY (sub_one_mult), GrB_INT64, GrB_INT64)) ;
212 :
213 2 : GRB_TRY (GrB_apply (d_3, NULL, NULL, Sub_one_mult, d_1, NULL)) ;
214 2 : GRB_TRY (GrB_apply (d_3, NULL, NULL, GrB_DIV_INT64, d_3, (int64_t) 2, NULL)) ;
215 :
216 : //--------------------------------------------------------------------------
217 : // compute d_4 = C_3e/2
218 : //--------------------------------------------------------------------------
219 :
220 2 : GRB_TRY (GrB_Matrix_new (&C_3, GrB_INT64, n, n)) ;
221 2 : GRB_TRY (GrB_Vector_new (&d_4, GrB_INT64, n)) ;
222 :
223 : // TODO: use LAGraph_plus_first_int64
224 : // C_3 = hadamard(A, A^2)
225 2 : GRB_TRY (GrB_mxm (C_3, A, NULL, GxB_PLUS_FIRST_INT64, A, A, GrB_DESC_ST1)) ;
226 :
227 : // d_4 = c_3 = C_3e/2
228 2 : GRB_TRY (GrB_reduce (d_4, NULL, NULL, GrB_PLUS_MONOID_INT64, C_3, NULL)) ;
229 2 : GRB_TRY (GrB_apply (d_4, NULL, NULL, GrB_DIV_INT64, d_4, (int64_t) 2, NULL)) ;
230 :
231 : //--------------------------------------------------------------------------
232 : // compute d_5 = p_3 = A*d_2 - hadamard(p_1, p_1 - 1) - 2c_3
233 : //--------------------------------------------------------------------------
234 :
235 2 : GRB_TRY (GrB_Vector_new (&v, GrB_INT64, n)) ;
236 2 : GRB_TRY (GrB_Vector_new (&two_c_3, GrB_INT64, n)) ;
237 2 : GRB_TRY (GrB_Vector_new (&d_5, GrB_INT64, n)) ;
238 :
239 : // v = hadamard(p_1, p_1 - 1)
240 2 : GRB_TRY (GrB_apply (v, NULL, NULL, Sub_one_mult, d_1, NULL)) ;
241 :
242 : // two_c_3 = 2 * c_3 = 2 * d_4
243 2 : GRB_TRY (GrB_apply (two_c_3, NULL, NULL, GrB_TIMES_INT64, 2, d_4, NULL)) ;
244 :
245 : // d_5 = A * d_2
246 : // TODO: use LAGraph_plus_second_int64
247 2 : GRB_TRY (GrB_mxv (d_5, NULL, NULL, GxB_PLUS_SECOND_INT64, A, d_2, NULL)) ;
248 :
249 : // d_5 -= hadamard(p_1, p_1 - 1)
250 2 : GRB_TRY (GrB_eWiseAdd (d_5, NULL, NULL, GrB_MINUS_INT64, d_5, v, NULL)) ;
251 :
252 : // d_5 -= two_c_3
253 2 : GRB_TRY (GrB_eWiseAdd (d_5, NULL, NULL, GrB_MINUS_INT64, d_5, two_c_3, NULL)) ;
254 :
255 : //--------------------------------------------------------------------------
256 : // compute d_6 = hadamard(d_2, p_1-1) - 2c_3
257 : //--------------------------------------------------------------------------
258 :
259 2 : GRB_TRY (GrB_Vector_new (&p_1_minus_one, GrB_INT64, n)) ;
260 2 : GRB_TRY (GrB_Vector_new (&d_6, GrB_INT64, n)) ;
261 :
262 : // p_1_minus_one = p_1 - 1
263 2 : GRB_TRY (GrB_apply (p_1_minus_one, NULL, NULL, GrB_MINUS_INT64, d_1, (int64_t) 1, NULL)) ;
264 :
265 : // d_6 = hadamard(d_2, p_1-1)
266 2 : GRB_TRY (GrB_eWiseMult (d_6, NULL, NULL, GrB_TIMES_INT64, d_2, p_1_minus_one, NULL)) ;
267 :
268 : // d_6 -= 2c_3
269 2 : GRB_TRY (GrB_eWiseAdd (d_6, NULL, NULL, GrB_MINUS_INT64, d_6, two_c_3, NULL)) ;
270 :
271 : //--------------------------------------------------------------------------
272 : // compute d_7 = A*hadamard(p_1-1, p_1-2) / 2
273 : //--------------------------------------------------------------------------
274 :
275 2 : GRB_TRY (GrB_Vector_new (&p_1_minus_two, GrB_INT64, n)) ;
276 2 : GRB_TRY (GrB_Vector_new (&p_1_p_1_had, GrB_INT64, n)) ;
277 2 : GRB_TRY (GrB_Vector_new (&d_7, GrB_INT64, n)) ;
278 :
279 2 : GRB_TRY (GrB_apply (p_1_minus_two, NULL, NULL, GrB_MINUS_INT64, d_1, (int64_t) 2, NULL)) ;
280 2 : GRB_TRY (GrB_eWiseMult (p_1_p_1_had, NULL, NULL, GrB_TIMES_INT64, p_1_minus_one, p_1_minus_two, NULL)) ;
281 :
282 : // TODO: use LAGraph_plus_second_int64
283 2 : GRB_TRY (GrB_mxv (d_7, NULL, NULL, GxB_PLUS_SECOND_INT64, A, p_1_p_1_had, NULL)) ;
284 2 : GRB_TRY (GrB_apply (d_7, NULL, NULL, GrB_DIV_INT64, d_7, (int64_t) 2, NULL)) ;
285 :
286 : //--------------------------------------------------------------------------
287 : // compute d_8 = hadamard(p_1, p_1_p_1_had) / 6
288 : //--------------------------------------------------------------------------
289 :
290 2 : GRB_TRY (GrB_Vector_new (&d_8, GrB_INT64, n)) ;
291 :
292 2 : GRB_TRY (GrB_eWiseMult (d_8, NULL, NULL, GrB_TIMES_INT64, d_1, p_1_p_1_had, NULL)) ;
293 2 : GRB_TRY (GrB_apply (d_8, NULL, NULL, GrB_DIV_INT64, d_8, (int64_t) 6, NULL)) ;
294 :
295 : //--------------------------------------------------------------------------
296 : // compute d_9 = A*c_3 - 2*c_3
297 : //--------------------------------------------------------------------------
298 :
299 2 : GRB_TRY (GrB_Vector_new (&d_9, GrB_INT64, n)) ;
300 :
301 : // TODO: use LAGraph_plus_second_int64
302 2 : GRB_TRY (GrB_mxv (d_9, NULL, NULL, GxB_PLUS_SECOND_INT64, A, d_4, NULL)) ;
303 2 : GRB_TRY (GrB_eWiseAdd (d_9, NULL, NULL, GrB_MINUS_INT64, d_9, two_c_3, NULL)) ;
304 :
305 : //--------------------------------------------------------------------------
306 : // compute d_10 = C_3 * (p_1 - 2)
307 : //--------------------------------------------------------------------------
308 :
309 2 : GRB_TRY (GrB_Vector_new (&d_10, GrB_INT64, n)) ;
310 :
311 : // TODO: use GrB_PLUS_TIMES_INT64
312 2 : GRB_TRY (GrB_mxv (d_10, NULL, NULL, GxB_PLUS_TIMES_INT64, C_3, p_1_minus_two, NULL)) ;
313 :
314 : //--------------------------------------------------------------------------
315 : // compute d_11 = hadamard(p_1 - 2, c_3)
316 : //--------------------------------------------------------------------------
317 :
318 2 : GRB_TRY (GrB_Vector_new (&d_11, GrB_INT64, n)) ;
319 :
320 2 : GRB_TRY (GrB_eWiseMult (d_11, NULL, NULL, GrB_TIMES_INT64, p_1_minus_two, d_4, NULL)) ;
321 :
322 : //--------------------------------------------------------------------------
323 : // compute d_12 = c_4 = C_{4,2}e/2
324 : //--------------------------------------------------------------------------
325 :
326 2 : GRB_TRY (GrB_Matrix_new (&C_4, GrB_INT64, n, 1)) ;
327 2 : GRB_TRY (GrB_Matrix_new (&D_1, GrB_INT64, n, n)) ;
328 :
329 2 : GRB_TRY (GrB_Vector_new (&d_12, GrB_INT64, n)) ;
330 :
331 : // D_1 = diag(d_1)
332 : // TODO: use GrB_Matrix_diag
333 2 : GRB_TRY (GxB_Matrix_diag (D_1, d_1, (int64_t) 0, NULL)) ;
334 :
335 : // TODO: true GxB starts here. For vanilla method, put this
336 : // in a single call to GrB_mxm to compute C_4
337 :
338 2 : GRB_TRY (GrB_Matrix_nvals (&nvals, A));
339 :
340 2 : const GrB_Index entries_per_tile = 1000;
341 2 : GrB_Index ntiles = (nvals + entries_per_tile - 1) / entries_per_tile ;
342 :
343 2 : LG_TRY (LAGraph_Calloc ((void **) &A_Tiles, ntiles, sizeof (GrB_Matrix),
344 : msg)) ;
345 2 : LG_TRY (LAGraph_Calloc ((void **) &D_Tiles, ntiles, sizeof (GrB_Matrix),
346 : msg)) ;
347 2 : LG_TRY (LAGraph_Calloc ((void **) &C_Tiles, ntiles, sizeof (GrB_Matrix),
348 : msg)) ;
349 2 : LG_TRY (LAGraph_Calloc ((void **) &Tile_nrows, ntiles, sizeof (GrB_Index),
350 : msg)) ;
351 :
352 2 : GrB_Index Tile_ncols [1] = {n} ;
353 :
354 2 : int64_t tot_deg = 0 ;
355 2 : GrB_Index last_row = -1 ;
356 43 : for (GrB_Index i = 0; i < n; ++i)
357 : {
358 41 : int64_t deg = 0 ;
359 41 : GRB_TRY (GrB_Vector_extractElement (°, d_1, i)) ;
360 41 : if (i == n - 1 || (tot_deg / entries_per_tile != (tot_deg + deg) / entries_per_tile))
361 : {
362 2 : Tile_nrows [tile_cnt++] = i - last_row ;
363 2 : last_row = i ;
364 : }
365 41 : tot_deg += deg ;
366 : }
367 :
368 2 : GRB_TRY (GxB_Matrix_split (A_Tiles, tile_cnt, 1, Tile_nrows, Tile_ncols, A, NULL)) ;
369 2 : GRB_TRY (GxB_Matrix_split (D_Tiles, tile_cnt, 1, Tile_nrows, Tile_ncols, D_1, NULL)) ;
370 :
371 : #define TRY(method) \
372 : { \
373 : GrB_Info info2 = method ; \
374 : if (info2 != GrB_SUCCESS) \
375 : { \
376 : GrB_free (&A_i) ; \
377 : GrB_free (&C_Tiles [i_tile]) ; \
378 : GrB_free (&e) ; \
379 : info1 = info2 ; \
380 : continue ; \
381 : } \
382 : }
383 :
384 : int save_nthreads_outer, save_nthreads_inner ;
385 2 : LG_TRY (LAGraph_GetNumThreads (&save_nthreads_outer, &save_nthreads_inner, msg)) ;
386 2 : LG_TRY (LAGraph_SetNumThreads (1, 1, msg)) ;
387 :
388 : int i_tile;
389 2 : GrB_Info info1 = GrB_SUCCESS ;
390 : #pragma omp parallel for num_threads(omp_get_max_threads()) schedule(dynamic,1)
391 4 : for (i_tile = 0; i_tile < tile_cnt; ++i_tile)
392 : {
393 2 : GrB_Matrix A_i = NULL, e = NULL ;
394 :
395 2 : TRY (GrB_Matrix_new (&e, GrB_INT64, n, 1)) ;
396 2 : TRY (GrB_assign (e, NULL, NULL, (int64_t) 1, GrB_ALL, n, GrB_ALL, 1, NULL)) ;
397 :
398 2 : TRY (GrB_Matrix_new (&A_i, GrB_INT64, Tile_nrows [i_tile], n)) ;
399 2 : TRY (GrB_Matrix_new (&C_Tiles [i_tile], GrB_INT64, Tile_nrows [i_tile], 1)) ;
400 :
401 2 : TRY (GrB_mxm (A_i, NULL, NULL, GxB_PLUS_PAIR_INT64, A_Tiles [i_tile], A, NULL)) ;
402 2 : TRY (GrB_eWiseAdd (A_i, NULL, NULL, GrB_MINUS_INT64, A_i, D_Tiles [i_tile], NULL)) ;
403 2 : TRY (GrB_apply (A_i, NULL, NULL, Sub_one_mult, A_i, NULL)) ;
404 :
405 : // multiply A_i by it on the right
406 2 : TRY (GrB_mxm (C_Tiles [i_tile], NULL, NULL, GxB_PLUS_FIRST_INT64, A_i, e, NULL)) ;
407 :
408 2 : GrB_free (&A_i) ;
409 2 : GrB_free (&e) ;
410 : }
411 :
412 2 : GRB_TRY (info1) ;
413 :
414 2 : LG_TRY (LAGraph_SetNumThreads (save_nthreads_outer, save_nthreads_inner, msg)) ;
415 :
416 2 : GRB_TRY (GxB_Matrix_concat (C_4, C_Tiles, tile_cnt, 1, NULL)) ;
417 :
418 2 : if (A_Tiles != NULL)
419 : {
420 4 : for (int i = 0; i < tile_cnt; ++i) GrB_free (&A_Tiles [i]) ;
421 : }
422 2 : if (D_Tiles != NULL)
423 : {
424 4 : for (int i = 0; i < tile_cnt; ++i) GrB_free (&D_Tiles [i]) ;
425 : }
426 2 : if (C_Tiles != NULL)
427 : {
428 4 : for (int i = 0; i < tile_cnt; ++i) GrB_free (&C_Tiles [i]) ;
429 : }
430 2 : LAGraph_Free ((void **) &Tile_nrows, msg) ;
431 2 : LAGraph_Free ((void **) &A_Tiles, msg) ;
432 2 : LAGraph_Free ((void **) &D_Tiles, msg) ;
433 2 : LAGraph_Free ((void **) &C_Tiles, msg) ;
434 :
435 : // d_12 = sum (C_4)
436 2 : GRB_TRY (GrB_reduce (d_12, NULL, NULL, GrB_PLUS_MONOID_INT64, C_4, NULL)) ;
437 2 : GRB_TRY (GrB_apply (d_12, NULL, NULL, GrB_DIV_INT64, d_12, 2, NULL)) ;
438 :
439 : //--------------------------------------------------------------------------
440 : // compute d_13 = D_{4,c}e/2
441 : //--------------------------------------------------------------------------
442 :
443 2 : GRB_TRY (GrB_Matrix_new (&D_4c, GrB_INT64, n, n)) ;
444 2 : GRB_TRY (GrB_Vector_new (&d_13, GrB_INT64, n)) ;
445 :
446 2 : GRB_TRY (GrB_eWiseMult (D_4c, NULL, NULL, GrB_MINUS_INT64, C_3, A, NULL)) ; // can be mult because we mask with A next
447 2 : GRB_TRY (GrB_mxm (D_4c, A, NULL, GxB_PLUS_SECOND_INT64, A, D_4c, GrB_DESC_S)) ;
448 :
449 : // d_13 = D_{4,c}*e/2
450 2 : GRB_TRY (GrB_reduce (d_13, NULL, NULL, GrB_PLUS_INT64, D_4c, NULL)) ;
451 2 : GRB_TRY (GrB_apply (d_13, NULL, NULL, GrB_DIV_INT64, d_13, (int64_t) 2, NULL)) ;
452 :
453 : //--------------------------------------------------------------------------
454 : // compute d_14 = D_{4,3}e/2 = hadamard(A, C_42)e/2
455 : //--------------------------------------------------------------------------
456 :
457 2 : GRB_TRY (GrB_Matrix_new (&D_43, GrB_INT64, n, n)) ;
458 2 : GRB_TRY (GrB_Vector_new (&d_14, GrB_INT64, n)) ;
459 2 : GRB_TRY (GrB_Matrix_new (&C_42, GrB_INT64, n, n)) ;
460 2 : GRB_TRY (GrB_Matrix_new (&P_2, GrB_INT64, n, n)) ;
461 :
462 : // P_2 = A*A - diag(d_1)
463 2 : GRB_TRY (GrB_eWiseAdd (P_2, A, NULL, GrB_MINUS_INT64, C_3, D_1, NULL)) ;
464 :
465 : // C_42 = hadamard(P_2, P_2 - 1)
466 2 : GRB_TRY (GrB_apply (C_42, A, NULL, Sub_one_mult, P_2, NULL)) ;
467 :
468 2 : GRB_TRY (GrB_eWiseMult (D_43, NULL, NULL, GrB_TIMES_INT64, A, C_42, NULL)) ;
469 :
470 : // d_14 = D_{4,3}*e/2
471 2 : GRB_TRY (GrB_reduce (d_14, NULL, NULL, GrB_PLUS_INT64, D_43, NULL)) ;
472 2 : GRB_TRY (GrB_apply (d_14, NULL, NULL, GrB_DIV_INT64, d_14, (int64_t) 2, NULL)) ;
473 :
474 : //--------------------------------------------------------------------------
475 : // compute d_15 = Te/6
476 : //--------------------------------------------------------------------------
477 :
478 : // TODO: computing d_15 requires GxB iterators. For vanilla GrB,
479 : // export the CSR matrix and use it directly.
480 :
481 2 : if (compute_d_15)
482 : {
483 2 : LG_TRY (LAGraph_KTruss (&T, G, 4, msg)) ;
484 2 : GRB_TRY (GrB_Vector_new (&d_15, GrB_INT64, n)) ;
485 :
486 2 : int nthreads = 1 ;
487 : // todo: parallelize this...
488 : //#pragma omp parallel for num_threads(nthreads)
489 : //for (int tid = 0 ; tid < nthreads ; tid++)
490 : {
491 :
492 : // allocate workspcae
493 2 : LG_TRY (LAGraph_Malloc ((void **) &neighbors, n,
494 : sizeof (GrB_Index), msg)) ;
495 2 : LG_TRY (LAGraph_Malloc ((void **) &k4cmn, n,
496 : sizeof (GrB_Index), msg)) ;
497 2 : LG_TRY (LAGraph_Malloc ((void **) &f15, n,
498 : sizeof (int64_t), msg)) ;
499 2 : LG_TRY (LAGraph_Malloc ((void **) &I, n,
500 : sizeof (GrB_Index), msg)) ;
501 2 : LG_TRY (LAGraph_Malloc ((void **) &isNeighbor, n,
502 : sizeof (int), msg)) ;
503 :
504 43 : for (int i = 0; i < n; ++i) {
505 41 : neighbors [i] = k4cmn [i] = f15 [i] = isNeighbor [i] = 0 ;
506 41 : I [i] = i ;
507 : }
508 :
509 : // thread tid operates on T(row1:row2-1,:)
510 2 : GrB_Index row1 = 0;//tid * (n / nthreads) ;
511 2 : GrB_Index row2 = n;//(tid == nthreads - 1) ? n : ((tid+1) * (n / nthreads)) ;
512 :
513 : GxB_Iterator riterator ;
514 2 : GxB_Iterator_new (&riterator) ;
515 2 : GRB_TRY (GxB_rowIterator_attach (riterator, T, NULL)) ;
516 :
517 : GxB_Iterator iterator ;
518 2 : GxB_Iterator_new (&iterator) ;
519 2 : GRB_TRY (GxB_rowIterator_attach (iterator, T, NULL)) ;
520 :
521 : // seek to T(row1,:)
522 2 : GrB_Info info = GxB_rowIterator_seekRow (iterator, row1) ;
523 43 : while (info != GxB_EXHAUSTED)
524 : {
525 : // iterate over entries in T(i,:)
526 41 : GrB_Index idx2 = GxB_rowIterator_getRowIndex (iterator) ;
527 41 : if (idx2 >= row2) break ;
528 41 : int neighbor_cnt = 0 ;
529 109 : while (info == GrB_SUCCESS)
530 : {
531 : // working with edge (idx2, j)
532 68 : GrB_Index j = GxB_rowIterator_getColIndex (iterator) ;
533 :
534 68 : if (j > idx2) {
535 34 : neighbors [neighbor_cnt++] = j ;
536 34 : isNeighbor [j] = 1 ;
537 : }
538 :
539 68 : info = GxB_rowIterator_nextCol (iterator) ;
540 : }
541 :
542 75 : for (int neighbor_id = 0 ; neighbor_id < neighbor_cnt ; ++neighbor_id) {
543 34 : GrB_Index j = neighbors [neighbor_id] ;
544 34 : int cmn_cnt = 0 ;
545 34 : info = GxB_rowIterator_seekRow(riterator, j) ;
546 :
547 180 : while (info == GrB_SUCCESS) { // iterate over neighbors of j
548 146 : GrB_Index k = GxB_rowIterator_getColIndex (riterator) ;
549 146 : if (k > j && isNeighbor [k]) {
550 31 : k4cmn [cmn_cnt++] = k ;
551 31 : isNeighbor [k] = -1 ;
552 : }
553 146 : info = GxB_rowIterator_nextCol (riterator) ;
554 : }
555 : // check every combination
556 65 : for (int k_1 = 0 ; k_1 < cmn_cnt ; k_1++) {
557 31 : GrB_Index k = k4cmn [k_1] ;
558 31 : info = GxB_rowIterator_seekRow(riterator, k) ;
559 :
560 164 : while (info == GrB_SUCCESS) { // iterate over neighbors of k
561 133 : GrB_Index l = GxB_rowIterator_getColIndex (riterator) ;
562 133 : if (l > k && isNeighbor [l] == -1) {
563 13 : f15[idx2]++ ;
564 13 : f15[j]++ ;
565 13 : f15[k]++ ;
566 13 : f15[l]++ ;
567 : }
568 133 : info = GxB_rowIterator_nextCol (riterator) ;
569 : }
570 : }
571 65 : for (int k_1 = 0 ; k_1 < cmn_cnt ; k_1++) {
572 31 : isNeighbor[k4cmn[k_1]] = 1 ;
573 : }
574 : }
575 :
576 75 : for (int neighbor_id = 0 ; neighbor_id < neighbor_cnt ; ++neighbor_id) {
577 34 : GrB_Index j = neighbors [neighbor_id] ;
578 34 : isNeighbor [j] = 0 ;
579 : }
580 :
581 : // move to the next row, T(i+1,:)
582 41 : info = GxB_rowIterator_nextRow (iterator) ;
583 : }
584 2 : GrB_free (&iterator) ;
585 2 : GrB_free (&riterator) ;
586 2 : GrB_free (&T) ;
587 2 : GRB_TRY (GrB_Vector_build (d_15, I, f15, n, NULL)) ;
588 :
589 : // free workspace
590 2 : LAGraph_Free ((void **) &neighbors, msg) ;
591 2 : LAGraph_Free ((void **) &k4cmn, msg) ;
592 2 : LAGraph_Free ((void **) &f15, msg) ;
593 2 : LAGraph_Free ((void **) &I, msg) ;
594 2 : LAGraph_Free ((void **) &isNeighbor, msg) ;
595 : }
596 : }
597 :
598 : //--------------------------------------------------------------------------
599 : // construct raw frequencies matrix F_raw
600 : //--------------------------------------------------------------------------
601 :
602 2 : GRB_TRY (GrB_Matrix_new (&F_raw, GrB_INT64, 16, n)) ;
603 :
604 2 : GrB_Vector d[16] = {d_0, d_1, d_2, d_3, d_4, d_5, d_6, d_7, d_8, d_9, d_10, d_11, d_12, d_13, d_14, d_15} ;
605 :
606 34 : for (int i = 0; i < 15 + (compute_d_15 ? 1 : 0); ++i)
607 : {
608 32 : GRB_TRY (GrB_Vector_nvals (&nvals, d[i]));
609 :
610 : // allocate workspace
611 32 : LG_TRY (LAGraph_Malloc ((void **) &J, nvals, sizeof (GrB_Index), msg)) ;
612 32 : LG_TRY (LAGraph_Malloc ((void **) &vals, nvals, sizeof (int64_t),
613 : msg)) ;
614 :
615 32 : GRB_TRY (GrB_Vector_extractTuples (J, vals, &nvals, d[i])) ;
616 678 : for (int j = 0; j < nvals; ++j) {
617 646 : GRB_TRY (GrB_Matrix_setElement (F_raw, vals[j], i, J[j])) ;
618 : }
619 :
620 : // free workspace
621 32 : LAGraph_Free ((void **) &J, msg) ;
622 32 : LAGraph_Free ((void **) &vals, msg) ;
623 : }
624 :
625 : //--------------------------------------------------------------------------
626 : // construct U_inv
627 : //--------------------------------------------------------------------------
628 :
629 2 : GRB_TRY (GrB_Matrix_new (&U_inv, GrB_INT64, 16, 16)) ;
630 2 : GRB_TRY (GrB_Matrix_build (U_inv, U_inv_I, U_inv_J, U_inv_X, U_inv_nvals, GrB_PLUS_INT64)) ;
631 :
632 : //--------------------------------------------------------------------------
633 : // construct net frequencies matrix F_net
634 : //--------------------------------------------------------------------------
635 :
636 2 : GRB_TRY (GrB_Matrix_new (F_net, GrB_INT64, 16, n)) ;
637 2 : GRB_TRY (GrB_mxm (*F_net, NULL, NULL, GxB_PLUS_TIMES_INT64, U_inv, F_raw, NULL)) ;
638 2 : GrB_Vector f_net = NULL ;
639 2 : GRB_TRY (GrB_Vector_new (&f_net, GrB_INT64, 16)) ;
640 2 : GRB_TRY (GrB_reduce (f_net, NULL, NULL, GrB_PLUS_INT64, *F_net, NULL)) ;
641 2 : GRB_TRY (GrB_free (&f_net)) ;
642 :
643 : //--------------------------------------------------------------------------
644 : // free work
645 : //--------------------------------------------------------------------------
646 :
647 2 : LG_FREE_WORK ;
648 2 : return (GrB_SUCCESS) ;
649 : #else
650 : return (GrB_NOT_IMPLEMENTED) ;
651 : #endif
652 : }
|