1616#include <LAGraphX.h>
1717
1818//Merging two ordered arrays of internal vertices in the add function
19- static GrB_Index * merge_all_paths (GrB_Index * n , const void * left , const GrB_Index na , const void * right , const GrB_Index nb ){
20- GrB_Index * a = (GrB_Index * ) left ;
21- GrB_Index * b = (GrB_Index * ) right ;
22-
23- if (na == 0 && nb == 0 ) {
24- * n = 0 ;
25- return NULL ;
26- }
27-
19+ static GrB_Index * merge_all_paths (GrB_Index * n , const GrB_Index * a , const size_t na , const GrB_Index * b , const size_t nb )
20+ {
2821 GrB_Index * tmp = malloc ((na + nb ) * sizeof (GrB_Index ));
2922
30- GrB_Index ia = 0 , ib = 0 , outn = 0 ;
23+ size_t ia = 0 , ib = 0 , outn = 0 ;
24+ // Handle the first elements of both arrays to initialize tmp and avoid checking if tmp is empty in the loop
3125 if (na > 0 && nb > 0 ) {
3226 if (a [0 ] < b [0 ]) {
3327 tmp [outn ++ ] = a [ia ++ ];
@@ -73,49 +67,92 @@ static GrB_Index* merge_all_paths(GrB_Index* n, const void* left, const GrB_Inde
7367 return tmp ;
7468}
7569
76- void clear_elem_all_paths (AllPathsElem * z ){
77- if (z -> middle ){
78- free (z -> middle );
79- z -> middle = NULL ;
70+ static GrB_Index * insert_all_paths (size_t * n , const GrB_Index * arr , size_t len , GrB_Index value )
71+ {
72+ // Array is ordered, so we can use binary search to find the position to insert value
73+ size_t l = 0 , r = len , m = 0 ;
74+ while (l < r ) {
75+ m = l + (r - l ) / 2 ;
76+ if (arr [m ] < value ) l = m + 1 ;
77+ else r = m ;
8078 }
81- z -> n = 0 ;
79+
80+ // If value is already in the array, return the original array
81+ if (l < len && arr [l ] == value ) {
82+ GrB_Index * tmp = malloc (len * sizeof (GrB_Index ));
83+ memcpy (tmp , arr , len * sizeof (GrB_Index ));
84+ * n = len ;
85+ return tmp ;
86+ }
87+
88+ GrB_Index * tmp = malloc ((len + 1 ) * sizeof (GrB_Index ));
89+ memcpy (tmp , arr , l * sizeof (GrB_Index ));
90+ tmp [l ] = value ;
91+ memcpy (tmp + l + 1 , arr + l , (len - l ) * sizeof (GrB_Index ));
92+
93+ * n = len + 1 ;
94+ return tmp ;
8295}
8396
8497void add_all_paths (AllPathsElem * z , AllPathsElem * x , AllPathsElem * y )
8598{
86- //temp is needed to avoid freeing the memory of z in case z == x or z == y
87- AllPathsElem temp ;
88- temp .middle = merge_all_paths (& temp .n , x -> middle , x -> n , y -> middle , y -> n );
89- clear_elem_all_paths (x );
90- clear_elem_all_paths (y );
91- z -> middle = temp .middle ;
92- z -> n = temp .n ;
99+ // temp is needed to avoid freeing the memory of z in case z == x or z == y
100+ AllPathsElem temp ;
101+
102+ // x->n and y->n are not equal to zero
103+ if (x -> n == 1 && y -> n == 1 ) {
104+ if (x -> data .single_elem == y -> data .single_elem ) {
105+ temp .n = 1 ;
106+ temp .data .single_elem = x -> data .single_elem ;
107+ } else {
108+ temp .n = 2 ;
109+ temp .data .middle = malloc (2 * sizeof (GrB_Index ));
110+ if (x -> data .single_elem < y -> data .single_elem ) {
111+ temp .data .middle [0 ] = x -> data .single_elem ;
112+ temp .data .middle [1 ] = y -> data .single_elem ;
113+ } else {
114+ temp .data .middle [0 ] = y -> data .single_elem ;
115+ temp .data .middle [1 ] = x -> data .single_elem ;
116+ }
117+ }
118+ } else if (x -> n == 1 ) {
119+ temp .data .middle = insert_all_paths (& temp .n , y -> data .middle , y -> n , x -> data .single_elem );
120+ } else if (y -> n == 1 ) {
121+ temp .data .middle = insert_all_paths (& temp .n , x -> data .middle , x -> n , y -> data .single_elem );
122+ } else {
123+ temp .data .middle = merge_all_paths (& temp .n , x -> data .middle , x -> n , y -> data .middle , y -> n );
124+ }
125+
126+ if (x -> n > 1 ){
127+ free (x -> data .middle );
128+ }
129+ if (y -> n > 1 ){
130+ free (y -> data .middle );
131+ }
132+
133+ * z = temp ;
93134}
94135
95136void mult_all_paths (AllPathsElem * z ,
96137 const AllPathsElem * x , GrB_Index ix , GrB_Index jx ,
97138 const AllPathsElem * y , GrB_Index iy , GrB_Index jy ,
98139 const void * theta )
99140{
100- z -> middle = malloc (sizeof (GrB_Index ));
101- z -> middle [0 ] = jx ;
141+ z -> data .single_elem = jx ;
102142 z -> n = 1 ;
103143}
104144
105145void set_all_paths (AllPathsElem * z , const AllPathsElem * x , const bool * edge_exist )
106146{
107- AllPathsElem temp ;
108- temp . middle = NULL ;
109- temp . n = 0 ;
110-
111- if ( edge_exist && * edge_exist ){
112- temp . middle = malloc ( sizeof ( GrB_Index ));
113- temp . n = 1 ;
114- temp . middle [ 0 ] = GrB_INDEX_MAX ; //GrB_INDEX_MAX - marker of A->eps and A->t
147+ if ( * edge_exist )
148+ {
149+ z -> data . single_elem = GrB_INDEX_MAX ; // A special value to indicate that this path corresponds to a terminal rule (A->t) or an epsilon rule (A->eps)
150+ z -> n = 1 ;
151+ }
152+ else {
153+ z -> n = x -> n ;
154+ z -> data . single_elem = x -> data . single_elem ;
115155 }
116-
117- z -> middle = merge_all_paths (& z -> n , x -> middle , x -> n , temp .middle , temp .n );
118- clear_elem_all_paths (& temp );
119156}
120157
121158#define MULT_PATH_INDEX_DEFN \
@@ -124,26 +161,25 @@ void set_all_paths(AllPathsElem *z, const AllPathsElem *x, const bool *edge_exis
124161" const AllPathsElem *y, GrB_Index iy, GrB_Index jy, \n" \
125162" const void *theta) \n" \
126163"{ \n" \
127- " z->middle = malloc(sizeof(GrB_Index)); \n" \
128- " z->middle[0] = jx; \n" \
164+ " z->data.single_elem = jx; \n" \
129165" z->n = 1; \n" \
130166"}"
131167
132168//Adding the count of all internal vertices in a reduction
133169void add_get_nvals_all_paths (AllPathsElem * z , const AllPathsElem * x , const AllPathsElem * y )
134170{
135171 z -> n = x -> n + y -> n ;
136- z -> middle = NULL ;
137172}
138173
139174//Made global so that the get_nvals_all_paths matches the GrB_Matrix_nvals signature
140- static GrB_Type * AllPaths_type_get_nvals = NULL ;
175+ static GrB_Type AllPaths_type = NULL ;
141176static GrB_Monoid AllPaths_monoid_get_nvals = NULL ;
142177
143178//A function that replaces GrB_Matrix_nvals in Reachability to check if new vertices have been added to the matrix.
144- GrB_Info get_nvals_all_paths (GrB_Index * nvals , const GrB_Matrix A ){
179+ static GrB_Info get_nvals_all_paths (GrB_Index * nvals , const GrB_Matrix A )
180+ {
145181 GrB_Scalar s = NULL ;
146- GrB_Scalar_new (& s , * AllPaths_type_get_nvals );
182+ GrB_Scalar_new (& s , AllPaths_type );
147183 GrB_Info info = GrB_reduce (s , NULL , AllPaths_monoid_get_nvals , A , NULL );
148184
149185 if (info != GrB_SUCCESS )
@@ -152,50 +188,23 @@ GrB_Info get_nvals_all_paths(GrB_Index *nvals, const GrB_Matrix A){
152188 return info ;
153189 }
154190
155- AllPathsElem result = {0 , NULL };
156- GrB_Info extract_info = GrB_Scalar_extractElement_UDT (& result , s );
157-
158- if (extract_info == GrB_NO_VALUE )
191+ AllPathsElem result = {0 };
192+ info = GrB_Scalar_extractElement_UDT (& result , s );
193+ if (info == GrB_NO_VALUE )
159194 {
160195 result .n = 0 ;
161196 }
162- else if (extract_info != GrB_SUCCESS )
197+ else if (info != GrB_SUCCESS )
163198 {
164199 GrB_free (& s );
165- return extract_info ;
200+ return info ;
166201 }
167202
168203 * nvals = result .n ;
169204 GrB_free (& s );
170205 return GrB_SUCCESS ;
171206}
172207
173- //To test the non-reduction approach in the future
174- GrB_Info get_nvals_all_paths2 (GrB_Index * nvals , const GrB_Matrix A ){
175- GrB_Index accum = 0 ;
176- GxB_Iterator iterator ;
177- GxB_Iterator_new (& iterator );
178- GrB_Info info = GxB_Matrix_Iterator_attach (iterator , A , NULL );
179- info = GxB_Matrix_Iterator_seek (iterator , 0 );
180- AllPathsElem val ;
181-
182- while (info != GxB_EXHAUSTED )
183- {
184- GxB_Iterator_get_UDT (iterator , (void * ) & val );
185- accum += val .n ;
186- info = GxB_Matrix_Iterator_next (iterator );
187- }
188-
189- GrB_free (& iterator );
190- * nvals = accum ;
191-
192- return GrB_SUCCESS ;
193- }
194-
195- // all_paths_ptr_t is a pointer to the type of elements of the outputs matrices.
196- // Use GrB_free(all_paths_ptr_t) after you finish working with the outputs matrices.
197- // Important: Do not free all_paths_ptr_t until all work with the output matrices is complete.
198- // Accessing matrices after freeing their type is undefined behavior.
199208GrB_Info LAGraph_CFL_AllPaths (
200209 // Output
201210 GrB_Matrix * outputs , // Array of matrices containing results.
@@ -207,6 +216,8 @@ GrB_Info LAGraph_CFL_AllPaths(
207216 // There are paths from I to M by nonterminal N1 and from M to J by nonterminal N2,
208217 // and A->N1 N2 where outputs[k] corresponds to nonterminal A.
209218 // GrB_INDEX_MAX in the array is a special value for A->eps and A->t.
219+ // AllPaths type - elements of the output matrices.
220+ GrB_Type * all_paths_ptr_t , // Pass a pointer to GrB_Type.
210221 // Input
211222 const GrB_Matrix * adj_matrices , // Array of adjacency matrices representing the graph.
212223 // The length of this array is equal to the count of
@@ -216,9 +227,6 @@ GrB_Info LAGraph_CFL_AllPaths(
216227 // is an edge between nodes i and j with the label of
217228 // the terminal corresponding to index 't' (where t is
218229 // in the range [0, terms_count - 1]).
219- GrB_Type * all_paths_ptr_t , // AllPaths type - elements of the output matrices.
220- // Pass a pointer to GrB_Type and
221- // free it after you finish working with outputs matrices.
222230 int64_t terms_count , // The total number of terminal symbols in the CFG.
223231 int64_t nonterms_count , // The total number of non-terminal symbols in the CFG.
224232 const LAGraph_rule_WCNF * rules , // The rules of the CFG.
@@ -230,7 +238,6 @@ GrB_Info LAGraph_CFL_AllPaths(
230238 return (GrB_NOT_IMPLEMENTED );
231239#else
232240 // Semiring components
233- GrB_Type AllPaths_type = NULL ;
234241 GrB_BinaryOp AllPaths_add = NULL ;
235242 GrB_BinaryOp AllPaths_add_get_nvals = NULL ;
236243 GrB_Monoid AllPaths_monoid = NULL ;
@@ -244,12 +251,11 @@ GrB_Info LAGraph_CFL_AllPaths(
244251 GrB_free (all_paths_ptr_t );
245252 GRB_TRY (GrB_Type_new (all_paths_ptr_t , sizeof (AllPathsElem )));
246253 AllPaths_type = * all_paths_ptr_t ;
247- AllPaths_type_get_nvals = all_paths_ptr_t ;
248254
249255 GRB_TRY (GrB_Scalar_new (& Theta , GrB_BOOL ));
250256 GRB_TRY (GrB_Scalar_setElement_BOOL (Theta , false));
251257
252- AllPathsElem bottom = {0 , NULL };
258+ AllPathsElem bottom = {0 };
253259 GRB_TRY (GrB_Scalar_new (& bottom_scalar , AllPaths_type ));
254260 GRB_TRY (GrB_Scalar_setElement_UDT (bottom_scalar , (void * )(& bottom )));
255261
@@ -304,19 +310,62 @@ GrB_Info LAGraph_CFL_AllPaths(
304310 AllPaths_add_get_nvals ,
305311 (void * )(& bottom )));
306312
307- CFL_Semiring semiring = {.type = AllPaths_type ,
313+ CFL_Semiring semiring = {
314+ .type = AllPaths_type ,
308315 .semiring = AllPaths_semiring ,
309316 .add = AllPaths_add ,
310317 .mult = AllPaths_mult ,
311318 .init_path = AllPaths_set ,
312319 .bottom_scalar = bottom_scalar ,
313- .get_nvals = get_nvals_all_paths };
320+ .get_nvals = get_nvals_all_paths };
314321
315322 LG_TRY (LAGraph_CFPQ_core (outputs , adj_matrices , terms_count , nonterms_count , rules , rules_count , & semiring , msg ));
316323
317- AllPaths_type = NULL ;
318- AllPaths_type_get_nvals = NULL ;
319324 LG_FREE_WORK ;
320325 return GrB_SUCCESS ;
321326#endif
322327}
328+
329+ // Helper function to free the output matrix of LAGraph_CFL_AllPaths, which contains elements of type AllPathsElem with dynamically allocated arrays of intermediate vertices.
330+ static void free_AllPaths_matrix (GrB_Matrix * ptr_output )
331+ {
332+ GxB_Iterator iterator ;
333+ GxB_Iterator_new (& iterator );
334+ GrB_Info info = GxB_Matrix_Iterator_attach (iterator , * ptr_output , NULL );
335+ info = GxB_Matrix_Iterator_seek (iterator , 0 );
336+ AllPathsElem val ;
337+
338+ while (info != GxB_EXHAUSTED )
339+ {
340+ GxB_Iterator_get_UDT (iterator , (void * )& val );
341+ if (val .n > 1 && val .data .middle != NULL ) {
342+ free (val .data .middle );
343+ }
344+ info = GxB_Matrix_Iterator_next (iterator );
345+ }
346+
347+ GrB_free (& iterator );
348+ GrB_free (ptr_output );
349+ }
350+
351+ // Free outputs and all_paths_ptr_t after you have finished working with the output matrices from LAGraph_CFL_AllPaths.
352+ GrB_Info LAGraph_CFL_AllPaths_free_outputs (GrB_Matrix * outputs , int64_t nonterms_count , GrB_Type * all_paths_ptr_t )
353+ {
354+ #if GxB_IMPLEMENTATION < GxB_VERSION (9 , 4 , 5 )
355+ return (GrB_NOT_IMPLEMENTED );
356+ #else
357+ if (outputs ) {
358+ for (size_t i = 0 ; i < nonterms_count ; i ++ ) {
359+ if (outputs [i ] == NULL )
360+ continue ;
361+ free_AllPaths_matrix (& outputs [i ]);
362+ outputs [i ] = NULL ;
363+ }
364+ free (outputs );
365+ }
366+ outputs = NULL ;
367+ GrB_free (all_paths_ptr_t );
368+ return GrB_SUCCESS ;
369+ #endif
370+ }
371+
0 commit comments