Skip to content

Commit 2678f79

Browse files
committed
update: union, reduce and insert
and LAGraph_CFL_AllPaths_free_outputs
1 parent 0c0931c commit 2678f79

3 files changed

Lines changed: 210 additions & 159 deletions

File tree

experimental/algorithm/LAGraph_CFL_AllPaths.c

Lines changed: 132 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -16,18 +16,12 @@
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

8497
void 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

95136
void 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

105145
void 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
133169
void 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;
141176
static 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.
199208
GrB_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

Comments
 (0)