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
84113static 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