Skip to content

Commit af8c57e

Browse files
Merge pull request #364 from GomezGab/scc
SCC Global Removal and testing
2 parents f2d91bc + bc963e4 commit af8c57e

File tree

5 files changed

+571
-169
lines changed

5 files changed

+571
-169
lines changed

experimental/algorithm/LAGraph_scc.c

Lines changed: 173 additions & 88 deletions
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,19 @@
3434
#if LAGRAPH_SUITESPARSE
3535

3636
//****************************************************************************
37-
// global C arrays used in SelectOp
38-
GrB_Index *I = NULL, *V = NULL, *F = NULL, *B = NULL, *M = NULL;
37+
//arrays used in SelectOp
38+
typedef struct
39+
{
40+
uint64_t *F, *B;
41+
bool *M;
42+
} sccContext;
43+
#define SCCCONTEXT \
44+
"typedef struct \n" \
45+
"{\n" \
46+
" uint64_t *F, *B;\n" \
47+
" bool *M;\n" \
48+
"} sccContext;\n"
49+
3950

4051
// edge_removal:
4152
// - remove the edges connected to newly identified SCCs (vertices u with M[u]==1)
@@ -50,23 +61,39 @@ GrB_Index *I = NULL, *V = NULL, *F = NULL, *B = NULL, *M = NULL;
5061
// an edge (u, v) if either F[u]!=F[v] or B[u]!=B[v] holds, which can accelerate
5162
// the SCC computation in the future rounds.
5263

53-
void edge_removal (bool *z, const void *x, GrB_Index i, GrB_Index j, const void *thunk) ;
54-
void edge_removal (bool *z, const void *x, GrB_Index i, GrB_Index j, const void *thunk)
64+
void edge_removal (bool *z, const void *x, GrB_Index i, GrB_Index j, const sccContext *thunk) ;
65+
void edge_removal (bool *z, const void *x, GrB_Index i, GrB_Index j, const sccContext *thunk)
5566
{
56-
(*z) = (!M[i] && !M[j] && F[i] == F[j] && B[i] == B[j]) ;
67+
(*z) = (!thunk->M[i] && !thunk->M[j]
68+
&& thunk->F[i] == thunk->F[j]
69+
&& thunk->B[i] == thunk->B[j]) ;
5770
}
71+
#define EDGE_REMOVAL \
72+
"void edge_removal \n" \
73+
"(bool *z, const void *x, GrB_Index i, GrB_Index j, const sccContext *thunk)\n" \
74+
"{\n" \
75+
" (*z) = (!thunk->M[i] && !thunk->M[j] \n" \
76+
" && thunk->F[i] == thunk->F[j] \n" \
77+
" && thunk->B[i] == thunk->B[j]) ;\n" \
78+
"}\n"
5879

5980
//****************************************************************************
6081
// trim_one: remove the edges connected to trivial SCCs
6182
// - A vertex is a trivial SCC if it has no incoming or outgoing edges.
6283
// - M[i] = i | if vertex i is a trivial SCC
6384
// M[i] = n | otherwise
6485

65-
void trim_one (bool *z, const void *x, GrB_Index i, GrB_Index j, const void *thunk) ;
66-
void trim_one (bool *z, const void *x, GrB_Index i, GrB_Index j, const void *thunk)
86+
void trim_one (bool *z, const void *x, GrB_Index i, GrB_Index j, const sccContext *thunk) ;
87+
void trim_one (bool *z, const void *x, GrB_Index i, GrB_Index j, const sccContext *thunk)
6788
{
68-
(*z) = (M[i] == M[j]) ;
89+
(*z) = (thunk->F[i] == thunk->F[j]) ;
6990
}
91+
#define TRIM_ONE \
92+
"void trim_one\n" \
93+
"(bool *z, const void *x, GrB_Index i, GrB_Index j, const sccContext *thunk)\n" \
94+
"{\n" \
95+
" (*z) = (thunk->F[i] == thunk->F[j]) ;\n" \
96+
"}\n"
7097

7198
//****************************************************************************
7299
// label propagation
@@ -78,56 +105,63 @@ void trim_one (bool *z, const void *x, GrB_Index i, GrB_Index j, const void *thu
78105

79106
#undef LG_FREE_ALL
80107
#define LG_FREE_ALL \
108+
{ \
81109
GrB_free (&s) ; \
82-
GrB_free (&t) ;
110+
GrB_free (&t) ; \
111+
}
83112

84113
static GrB_Info propagate (GrB_Vector label, GrB_Vector mask,
85-
GrB_Matrix A, GrB_Matrix AT, GrB_Index n, char *msg)
114+
const GrB_Matrix A, const GrB_Matrix AT, GrB_Index n, char *msg)
86115
{
87116
GrB_Info info;
88117
// semirings
89-
90118
GrB_Vector s = NULL, t = NULL;
91119
GRB_TRY (GrB_Vector_new (&s, GrB_UINT64, n));
92120
GRB_TRY (GrB_Vector_new (&t, GrB_UINT64, n));
93121
GRB_TRY (GrB_assign (s, mask, 0, label, GrB_ALL, 0, 0));
122+
// GxB_fprint(s, GxB_SHORT, stdout);
94123
GRB_TRY (GrB_assign (t, 0, 0, label, GrB_ALL, 0, 0));
124+
GRB_TRY (GrB_wait(A, GrB_MATERIALIZE));
95125

96-
GrB_Index active;
126+
bool active;
97127
while (true)
98128
{
129+
// GRB_TRY (GrB_mxv
130+
// (t, 0, GrB_MIN_UINT64, GrB_MIN_SECOND_SEMIRING_UINT64, AT, s, 0));
99131
GRB_TRY (GrB_vxm (t, 0, GrB_MIN_UINT64,
100132
GrB_MIN_FIRST_SEMIRING_UINT64, s, A, 0));
101-
GRB_TRY (GrB_eWiseMult (mask, 0, 0, GxB_ISNE_UINT64, t, label, 0));
102-
GRB_TRY (GrB_assign (label, mask, 0, t, GrB_ALL, 0, 0));
103-
GRB_TRY (GrB_reduce (&active, 0, GrB_PLUS_MONOID_UINT64, mask, 0));
104-
if (active == 0) break;
105-
GRB_TRY (GrB_Vector_clear (s));
133+
GRB_TRY (GrB_eWiseMult (mask, 0, 0, GrB_NE_UINT64, t, label, 0));
134+
GRB_TRY (GrB_assign (label, NULL, NULL, t, GrB_ALL, n, NULL));
135+
GRB_TRY (GrB_reduce (&active, 0, GrB_LOR_MONOID_BOOL, mask, 0));
136+
if (!active) break;
137+
GRB_TRY (GrB_Vector_clear(s));
106138
GRB_TRY (GrB_assign (s, mask, 0, label, GrB_ALL, 0, 0));
139+
GRB_TRY (GrB_wait(s, GrB_MATERIALIZE));
107140
}
108141

109142
LG_FREE_ALL ;
110143
return GrB_SUCCESS;
111144
}
112-
113145
//****************************************************************************
114146

115147
#undef LG_FREE_ALL
116148
#define LG_FREE_ALL \
117-
LAGraph_Free ((void **) &I, msg); \
118-
LAGraph_Free ((void **) &V, msg); \
119-
LAGraph_Free ((void **) &F, msg); \
120-
LAGraph_Free ((void **) &B, msg); \
121-
LAGraph_Free ((void **) &M, msg); \
149+
LAGraph_Free ((void **) &contx.F, msg); \
150+
LAGraph_Free ((void **) &contx.B, msg); \
151+
LAGraph_Free ((void **) &contx.M, msg); \
122152
GrB_free (&ind); \
123153
GrB_free (&inf); \
124154
GrB_free (&f); \
125155
GrB_free (&b); \
156+
GrB_free (&D); \
157+
GrB_free (&x); \
126158
GrB_free (&mask); \
159+
GrB_free (&m2); \
127160
GrB_free (&FW); \
128161
GrB_free (&BW); \
129162
GrB_free (&sel1); \
130163
GrB_free (&sel2); \
164+
GrB_free (&contx_type); \
131165
GrB_free (&scc);
132166

133167
#endif
@@ -143,108 +177,159 @@ int LAGraph_scc
143177
#if LAGRAPH_SUITESPARSE
144178

145179
LG_CLEAR_MSG ;
146-
147-
GrB_Info info;
180+
sccContext contx = {NULL, NULL, NULL};
181+
GrB_Info info = GrB_SUCCESS;
182+
GrB_Type contx_type = NULL;
183+
GrB_Type type_F = NULL, type_B = NULL, type_M = NULL;
184+
int hand_F = GrB_DEFAULT, hand_B = GrB_DEFAULT, hand_M = GrB_DEFAULT;
185+
uint64_t n_F = 0, n_B = 0, n_M = 0, size_F = 0, size_B = 0, size_M = 0;
148186
GrB_Vector scc = NULL ;
149187
GrB_Vector ind = NULL ;
150188
GrB_Vector inf = NULL ;
151-
GrB_Vector f = NULL, b = NULL, mask = NULL ;
189+
GrB_Vector x = NULL ;
190+
GrB_Vector f = NULL, b = NULL, mask = NULL, m2 = NULL;
152191
GrB_IndexUnaryOp sel1 = NULL, sel2 = NULL ;
153192
GrB_Monoid Add = NULL ;
154-
GrB_Matrix FW = NULL, BW = NULL;
155-
156-
if (result == NULL || A == NULL) return (GrB_NULL_POINTER) ;
193+
GrB_Matrix FW = NULL, BW = NULL, D = NULL;
194+
LG_ASSERT(result != NULL, GrB_NULL_POINTER);
195+
LG_ASSERT(A != NULL, GrB_NULL_POINTER);
157196

158197
GrB_Index n, ncols, nvals;
159198
GRB_TRY (GrB_Matrix_nrows (&n, A));
160199
GRB_TRY (GrB_Matrix_ncols (&ncols, A));
161-
if (n != ncols) return (GrB_DIMENSION_MISMATCH) ;
162-
163-
// store the graph in both directions (forward / backward)
164-
GRB_TRY (GrB_Matrix_new (&FW, GrB_BOOL, n, n));
165-
GRB_TRY (GrB_Matrix_new (&BW, GrB_BOOL, n, n));
166-
GRB_TRY (GrB_transpose (FW, 0, 0, A, GrB_DESC_T0)); // FW = A
167-
GRB_TRY (GrB_transpose (BW, 0, 0, A, 0)); // BW = A'
168-
169-
// check format
170-
int32_t A_format, AT_format;
171-
GRB_TRY (GrB_get (FW, &A_format , GrB_STORAGE_ORIENTATION_HINT));
172-
GRB_TRY (GrB_get (BW, &AT_format, GrB_STORAGE_ORIENTATION_HINT));
173-
174-
bool is_csr = (A_format == GrB_ROWMAJOR && AT_format == GrB_ROWMAJOR);
175-
if (!is_csr) return (GrB_INVALID_VALUE) ;
176-
177-
LG_TRY (LAGraph_Malloc ((void **) &I, n, sizeof (GrB_Index), msg)) ;
178-
LG_TRY (LAGraph_Malloc ((void **) &V, n, sizeof (GrB_Index), msg)) ;
179-
LG_TRY (LAGraph_Malloc ((void **) &F, n, sizeof (GrB_Index), msg)) ;
180-
LG_TRY (LAGraph_Malloc ((void **) &B, n, sizeof (GrB_Index), msg)) ;
181-
LG_TRY (LAGraph_Malloc ((void **) &M, n, sizeof (GrB_Index), msg)) ;
182-
183-
for (GrB_Index i = 0; i < n; i++)
184-
I[i] = V[i] = i;
185-
200+
LG_ASSERT(n == ncols, GrB_DIMENSION_MISMATCH);
201+
202+
#if !LG_SUITESPARSE_GRAPHBLAS_V10
203+
LG_TRY (LAGraph_Malloc ((void **) &contx.F, n, sizeof (uint64_t), msg)) ;
204+
LG_TRY (LAGraph_Malloc ((void **) &contx.B, n, sizeof (uint64_t), msg)) ;
205+
LG_TRY (LAGraph_Malloc ((void **) &contx.M, n, sizeof (bool), msg)) ;
206+
#endif
186207
// scc: the SCC identifier for each vertex
187208
// scc[u] == n: not assigned yet
188209
GRB_TRY (GrB_Vector_new (&scc, GrB_UINT64, n));
189210
// vector of indices: ind[i] == i
190211
GRB_TRY (GrB_Vector_new (&ind, GrB_UINT64, n));
191-
GRB_TRY (GrB_Vector_build (ind, I, V, n, GrB_PLUS_UINT64));
212+
GRB_TRY (GrB_Vector_assign_UINT64 (
213+
ind, NULL, NULL, (uint64_t) 0, GrB_ALL, n, NULL)) ;
214+
GRB_TRY (GrB_Vector_apply_IndexOp_UINT64 (
215+
ind, NULL, NULL, GrB_ROWINDEX_INT64, ind, 0, NULL)) ;
192216
// vector of infinite value: inf[i] == n
193217
GRB_TRY (GrB_Vector_new (&inf, GrB_UINT64, n));
194-
GRB_TRY (GrB_assign (inf, 0, 0, n, GrB_ALL, 0, 0));
218+
GRB_TRY (GrB_assign (inf, NULL, NULL, n, GrB_ALL, 0, NULL));
195219
// other vectors
196220
GRB_TRY (GrB_Vector_new (&f, GrB_UINT64, n));
197221
GRB_TRY (GrB_Vector_new (&b, GrB_UINT64, n));
198-
GRB_TRY (GrB_Vector_new (&mask, GrB_UINT64, n));
199-
GRB_TRY (GrB_IndexUnaryOp_new (&sel1, (void *) trim_one, GrB_BOOL, GrB_UINT64, GrB_UINT64));
200-
GRB_TRY (GrB_IndexUnaryOp_new (&sel2, (void *) edge_removal, GrB_BOOL, GrB_UINT64, GrB_UINT64));
222+
GRB_TRY (GrB_Vector_new (&mask, GrB_BOOL, n));
223+
GRB_TRY (GrB_Vector_new (&m2, GrB_BOOL, n));
224+
GRB_TRY (GrB_Vector_new (&x, GrB_BOOL, n));
225+
GRB_TRY (GxB_Type_new (
226+
&contx_type, sizeof(sccContext), "sccContext", SCCCONTEXT)) ;
227+
228+
GRB_TRY (GxB_IndexUnaryOp_new (
229+
&sel1, (GxB_index_unary_function) trim_one,
230+
GrB_BOOL, GrB_UINT64, contx_type,
231+
// NULL, NULL
232+
"trim_one", TRIM_ONE
233+
));
234+
GRB_TRY (GxB_IndexUnaryOp_new (
235+
&sel2, (GxB_index_unary_function) edge_removal,
236+
GrB_BOOL, GrB_UINT64, contx_type,
237+
// NULL, NULL
238+
"edge_removal", EDGE_REMOVAL
239+
));
240+
241+
// store the graph in both directions (forward / backward)
242+
GRB_TRY (GrB_Matrix_new (&FW, GrB_BOOL, n, n));
243+
GRB_TRY (GrB_Matrix_new (&BW, GrB_BOOL, n, n));
244+
GRB_TRY (GrB_Matrix_assign_BOOL(
245+
FW, A, NULL, true, GrB_ALL, n, GrB_ALL, n, GrB_DESC_S)) ;
246+
GRB_TRY (GrB_transpose (BW, NULL, NULL, FW, NULL)); // BW = FW'
247+
248+
// check format
249+
int32_t A_format, AT_format;
250+
GRB_TRY (GrB_get (FW, &A_format , GrB_STORAGE_ORIENTATION_HINT));
251+
GRB_TRY (GrB_get (BW, &AT_format, GrB_STORAGE_ORIENTATION_HINT));
252+
253+
bool is_csr = (A_format == GrB_ROWMAJOR && AT_format == GrB_ROWMAJOR);
254+
LG_ASSERT (is_csr, GrB_INVALID_VALUE) ;
201255

202256
// remove trivial SCCs
203-
GRB_TRY (GrB_reduce (f, 0, GrB_PLUS_UINT64, GrB_PLUS_UINT64, FW, 0));
204-
GRB_TRY (GrB_reduce (b, 0, GrB_PLUS_UINT64, GrB_PLUS_UINT64, BW, 0));
205-
GRB_TRY (GrB_eWiseMult (mask, 0, GxB_LAND_UINT64, GxB_LAND_UINT64, f, b, 0));
257+
GRB_TRY (GrB_Vector_assign_BOOL (x, NULL, NULL, 0, GrB_ALL, n, NULL)) ;
258+
GRB_TRY (GrB_mxv (m2, NULL, NULL, GxB_ANY_PAIR_BOOL, FW, x, NULL)) ;
259+
GRB_TRY (GrB_mxv (mask, m2, NULL, GxB_ANY_PAIR_BOOL, BW, x, GrB_DESC_S)) ;
206260
GRB_TRY (GrB_Vector_nvals (&nvals, mask));
207261

208-
GRB_TRY (GrB_assign (scc, 0, 0, ind, GrB_ALL, 0, 0));
209-
GRB_TRY (GrB_assign (scc, mask, 0, n, GrB_ALL, 0, 0));
210-
GRB_TRY (GrB_Vector_clear (mask));
262+
GRB_TRY (GrB_assign (scc, NULL, NULL, ind, GrB_ALL, 0, NULL));
263+
GRB_TRY (GrB_assign (scc, mask, NULL, n, GrB_ALL, 0, NULL));
211264

212265
if (nvals < n)
213266
{
214-
GRB_TRY (GrB_Vector_extractTuples (I, M, &n, scc));
215-
GRB_TRY (GrB_select (FW, 0, 0, sel1, FW, 0, 0));
216-
GRB_TRY (GrB_select (BW, 0, 0, sel1, BW, 0, 0));
267+
// No reason for context.
268+
#if LG_SUITESPARSE_GRAPHBLAS_V10
269+
GRB_TRY(GxB_Vector_unload(
270+
scc, (void **) &contx.F, &type_F, &n_F, &size_F, &hand_F, NULL)) ;
271+
#else
272+
GRB_TRY (GrB_Vector_extractTuples_UINT64 (NULL, contx.F, &n, scc));
273+
#endif
274+
GRB_TRY (GrB_Matrix_select_UDT (
275+
FW, NULL, NULL, sel1, FW, &contx, NULL)) ;
276+
GRB_TRY (GrB_Matrix_select_UDT (
277+
BW, NULL, NULL, sel1, BW, &contx, NULL)) ;
278+
#if LG_SUITESPARSE_GRAPHBLAS_V10
279+
GRB_TRY(GxB_Vector_load(
280+
scc, (void **) &contx.F, type_F, n_F, size_F, hand_F, NULL)) ;
281+
#endif
217282
}
218283

219284
GRB_TRY (GrB_Matrix_nvals (&nvals, FW));
220285
while (nvals > 0)
221286
{
222-
GRB_TRY (GrB_eWiseMult (mask, 0, 0, GxB_ISEQ_UINT64, scc, inf, 0));
223-
GRB_TRY (GrB_assign (f, 0, 0, ind, GrB_ALL, 0, 0));
287+
GRB_TRY (GrB_Vector_apply_BinaryOp2nd_UINT64 (
288+
mask, NULL, NULL, GrB_EQ_UINT64, scc, n, NULL));
289+
GRB_TRY (GrB_assign (f, NULL, NULL, ind, GrB_ALL, 0, NULL));
224290
LG_TRY (propagate (f, mask, FW, BW, n, msg));
225291

226-
GRB_TRY (GrB_eWiseMult (mask, 0, 0, GxB_ISEQ_UINT64, f, ind, 0));
227-
GRB_TRY (GrB_assign (b, 0, 0, inf, GrB_ALL, 0, 0));
228-
GRB_TRY (GrB_assign (b, mask, 0, ind, GrB_ALL, 0, 0));
292+
GRB_TRY (GrB_eWiseMult (mask, NULL, NULL, GrB_EQ_UINT64, f, ind, NULL));
293+
GRB_TRY (GrB_Vector_assign_UINT64 (
294+
b, NULL, NULL, n, GrB_ALL, 0, NULL)) ;
295+
GRB_TRY (GrB_assign (b, mask, NULL, ind, GrB_ALL, 0, NULL));
229296
LG_TRY (propagate (b, mask, BW, FW, n, msg));
230297

231-
GRB_TRY (GrB_eWiseMult (mask, 0, 0, GxB_ISEQ_UINT64, f, b, 0));
232-
GRB_TRY (GrB_assign (scc, mask, GrB_MIN_UINT64, f, GrB_ALL, 0, 0));
233-
234-
GRB_TRY (GrB_Vector_extractTuples (I, F, &n, f));
235-
GRB_TRY (GrB_Vector_extractTuples (I, B, &n, b));
236-
GRB_TRY (GrB_Vector_extractTuples (I, M, &n, mask));
237-
238-
GRB_TRY (GrB_select (FW, 0, 0, sel2, FW, 0, 0));
239-
GRB_TRY (GrB_select (BW, 0, 0, sel2, BW, 0, 0));
240-
298+
GRB_TRY (GrB_eWiseMult (mask, NULL, NULL, GrB_EQ_UINT64, f, b, NULL));
299+
GRB_TRY (GrB_assign (scc, mask, GrB_MIN_UINT64, f, GrB_ALL, 0, NULL));
300+
301+
#if LG_SUITESPARSE_GRAPHBLAS_V10
302+
GRB_TRY(GxB_Vector_unload(
303+
f, (void **) &contx.F, &type_F, &n_F, &size_F, &hand_F, NULL)) ;
304+
GRB_TRY(GxB_Vector_unload(
305+
b, (void **) &contx.B, &type_B, &n_B, &size_B, &hand_B, NULL)) ;
306+
GRB_TRY(GxB_Vector_unload(
307+
mask, (void **) &contx.M, &type_M, &n_M, &size_M, &hand_M, NULL
308+
)) ;
309+
#else
310+
GRB_TRY (GrB_Vector_extractTuples_UINT64 (NULL, contx.F, &n, f));
311+
GRB_TRY (GrB_Vector_extractTuples_UINT64 (NULL, contx.B, &n, b));
312+
GRB_TRY (GrB_Vector_extractTuples_BOOL (NULL, contx.M, &n, mask));
313+
#endif
314+
315+
GRB_TRY (GrB_Matrix_select_UDT (
316+
FW, NULL, NULL, sel2, FW, &contx, NULL)) ;
317+
GRB_TRY (GrB_Matrix_select_UDT (
318+
BW, NULL, NULL, sel2, BW, &contx, NULL)) ;
319+
#if LG_SUITESPARSE_GRAPHBLAS_V10
320+
GRB_TRY(GxB_Vector_load(
321+
f, (void **) &contx.F, type_F, n_F, size_F, hand_F, NULL)) ;
322+
GRB_TRY(GxB_Vector_load(
323+
b, (void **) &contx.B, type_B, n_B, size_B, hand_B, NULL)) ;
324+
GRB_TRY(GxB_Vector_load(
325+
mask, (void **) &contx.M, type_M, n_M, size_M, hand_M, NULL
326+
)) ;
327+
#endif
241328
GRB_TRY (GrB_Matrix_nvals (&nvals, FW));
242329
}
243-
GRB_TRY (GrB_eWiseMult (mask, 0, 0, GxB_ISEQ_UINT64, scc, inf, 0));
244-
GRB_TRY (GrB_assign (scc, mask, 0, ind, GrB_ALL, 0, 0));
245-
246-
GRB_TRY (GrB_eWiseMult (mask, 0, 0, GxB_ISEQ_UINT64, scc, ind, 0));
247-
GRB_TRY (GrB_reduce (&nvals, 0, GrB_PLUS_MONOID_UINT64, mask, 0));
330+
GRB_TRY (GrB_Vector_apply_BinaryOp2nd_UINT64 (
331+
mask, NULL, NULL, GrB_EQ_UINT64, scc, n, NULL));
332+
GRB_TRY (GrB_assign (scc, mask, NULL, ind, GrB_ALL, 0, NULL));
248333

249334
*result = scc;
250335
scc = NULL;

0 commit comments

Comments
 (0)