From c76663fb0aa1bef286d546ce17fb6c8d358d0dcd Mon Sep 17 00:00:00 2001 From: Rodion Suvorov Date: Sun, 20 Jul 2025 14:00:11 +0300 Subject: [PATCH 01/38] feat: implement rpq-matrix algorithm with lor, concat and kleene opearions --- experimental/algorithm/LAGraph_RPQMatrix.c | 197 +++++++++++++++++++++ 1 file changed, 197 insertions(+) create mode 100644 experimental/algorithm/LAGraph_RPQMatrix.c diff --git a/experimental/algorithm/LAGraph_RPQMatrix.c b/experimental/algorithm/LAGraph_RPQMatrix.c new file mode 100644 index 0000000000..d79802416a --- /dev/null +++ b/experimental/algorithm/LAGraph_RPQMatrix.c @@ -0,0 +1,197 @@ +//------------------------------------------------------------------------------ +// LAGraph_RpqMatrix: regular path query algortithm +//------------------------------------------------------------------------------ + +#define LG_FREE_WORK \ + { \ + } + +#define LG_FREE_ALL \ + { \ + LG_FREE_WORK; \ + } + +#include "LG_internal.h" +#include "LAGraphX.h" +#include + +#define OK(s) \ + { \ + GrB_Info info = s; \ + if (!(info == GrB_SUCCESS)) \ + { \ + printf("GraphBLAS error: %d\n", info); \ + fprintf(stderr, "GraphBLAS error: %d\n", info); \ + } \ + } + +typedef enum RpqMatrixOp +{ + RPQ_MATRIX_OP_LABEL, + RPQ_MATRIX_OP_LOR, + RPQ_MATRIX_OP_CONCAT, + RPQ_MATRIX_OP_KLEENE, + RPQ_MATRIX_OP_KLEENE_L, + RPQ_MATRIX_OP_KLEENE_R, +} RpqMatrixOp; + +typedef struct RpqMatrixPlan +{ + RpqMatrixOp op; + struct RpqMatrixPlan *lhs; + struct RpqMatrixPlan *rhs; + GrB_Matrix mat; + GrB_Matrix res_mat; +} RpqMatrixPlan; + +static GrB_Semiring sr; +static GrB_Monoid op; + +GrB_Info LAGraph_RpqMatrix(RpqMatrixPlan *plan, char *msg); + +static GrB_Info LAGraph_RpqMatrixLor(RpqMatrixPlan *plan, char *msg) +{ + LG_ASSERT(plan != NULL, GrB_NULL_POINTER); + LG_ASSERT(plan->op == RPQ_MATRIX_OP_LOR, GrB_INVALID_VALUE); + LG_ASSERT(plan->res_mat == NULL, GrB_INVALID_VALUE); + + RpqMatrixPlan *lhs = plan->lhs; + RpqMatrixPlan *rhs = plan->rhs; + + LG_ASSERT(lhs != NULL, GrB_NULL_POINTER); + LG_ASSERT(rhs != NULL, GrB_NULL_POINTER); + + OK(LAGraph_RpqMatrix(lhs, msg)); + OK(LAGraph_RpqMatrix(rhs, msg)); + + GrB_Matrix lhs_mat = lhs->res_mat; + GrB_Matrix rhs_mat = rhs->res_mat; + + GRB_TRY(GrB_eWiseAdd(plan->res_mat, GrB_NULL, GrB_NULL, + op, lhs_mat, rhs_mat, GrB_DESC_R)); + + return (GrB_SUCCESS); +} + +static GrB_Info LAGraph_RpqMatrixConcat(RpqMatrixPlan *plan, char *msg) +{ + LG_ASSERT(plan != NULL, GrB_NULL_POINTER); + LG_ASSERT(plan->op == RPQ_MATRIX_OP_CONCAT, GrB_INVALID_VALUE); + LG_ASSERT(plan->res_mat == NULL, GrB_INVALID_VALUE); + + RpqMatrixPlan *lhs = plan->lhs; + RpqMatrixPlan *rhs = plan->rhs; + + LG_ASSERT(lhs != NULL, GrB_NULL_POINTER); + LG_ASSERT(rhs != NULL, GrB_NULL_POINTER); + + OK(LAGraph_RpqMatrix(lhs, msg)); + OK(LAGraph_RpqMatrix(rhs, msg)); + + GrB_Matrix lhs_mat = lhs->res_mat; + GrB_Matrix rhs_mat = rhs->res_mat; + + GRB_TRY(GrB_mxm(plan->res_mat, GrB_NULL, GrB_NULL, + sr, lhs_mat, rhs_mat, GrB_DESC_R)); + + return (GrB_SUCCESS); +} + +static GrB_Info LAGraph_RpqMatrixKleene(RpqMatrixPlan *plan, char *msg) +{ + LG_ASSERT(plan != NULL, GrB_NULL_POINTER); + LG_ASSERT(plan->op == RPQ_MATRIX_OP_KLEENE, GrB_INVALID_VALUE); + LG_ASSERT(plan->res_mat == NULL, GrB_INVALID_VALUE); + + RpqMatrixPlan *lhs = plan->lhs; + RpqMatrixPlan *rhs = plan->rhs; + + // Kleene star should have one child. Always right. + LG_ASSERT(lhs == NULL, GrB_NULL_POINTER); + LG_ASSERT(rhs != NULL, GrB_NULL_POINTER); + + OK(LAGraph_RpqMatrix(rhs, msg)); + + GrB_Matrix B = rhs->res_mat; + + // Creating identity matrix. + GrB_Index n; + GRB_TRY(GrB_Matrix_nrows(&n, B)); + GrB_Matrix E; + GRB_TRY(GrB_Matrix_new(&E, GrB_BOOL, n, n)); + + GrB_Vector v; + GRB_TRY(GrB_Vector_new(&v, GrB_BOOL, n)); + GRB_TRY(GrB_Vector_assign_BOOL(v, NULL, NULL, true, GrB_ALL, n, NULL)); + + GRB_TRY(GrB_Matrix_diag(&E, v, 0)); + + GRB_TRY(GrB_Vector_free(&v)); + + // B + E + GrB_Matrix BPE; + GRB_TRY(GrB_Matrix_new(&BPE, GrB_BOOL, n, n)); + GRB_TRY(GrB_eWiseAdd(BPE, GrB_NULL, GrB_NULL, + op, B, E, GrB_DESC_R)); + // S <- S x (B + E) + GrB_Matrix S, T; + GRB_TRY(GrB_Matrix_dup(&S, E)); + + bool changed = true; + GrB_Index nnz_S = n, nnz_T = 0; + while (changed) + { + // T = S * (B + E) + GRB_TRY(GrB_Matrix_new(&T, GrB_BOOL, n, n)); + GRB_TRY(GrB_mxm(T, GrB_NULL, GrB_NULL, + sr, S, BPE, GrB_DESC_R)); + + GRB_TRY(GrB_Matrix_nvals(&nnz_T, T)); + if (nnz_T != nnz_S) + { + changed = true; + nnz_S = nnz_T; + GRB_TRY(GrB_Matrix_free(&S)); + S = T; + } + else + { + changed = false; + GRB_TRY(GrB_Matrix_free(&T)); + } + } + plan->res_mat = S; + + GRB_TRY(GrB_Matrix_free(&E)); + GRB_TRY(GrB_Matrix_free(&BPE)); + return (GrB_SUCCESS); +} + +GrB_Info LAGraph_RpqMatrix(RpqMatrixPlan *plan, char *msg) +{ + if (plan->res_mat != NULL) + return (GrB_SUCCESS); + + switch (plan->op) + { + case RPQ_MATRIX_OP_LABEL: + LG_ASSERT(plan->lhs == NULL && plan->rhs == NULL, GrB_INVALID_VALUE); + plan->res_mat = plan->mat; + return (GrB_SUCCESS); + case RPQ_MATRIX_OP_LOR: + return LAGraph_RpqMatrixLor(plan, msg); + case RPQ_MATRIX_OP_CONCAT: + return LAGraph_RpqMatrixConcat(plan, msg); + case RPQ_MATRIX_OP_KLEENE: + return LAGraph_RpqMatrixKleene(plan, msg); + default: + LG_ASSERT(false, GrB_INVALID_VALUE); + } + return (GrB_SUCCESS); +} + +GrB_Info LAGraph_RpqMatrix_initialize() +{ + sr = LAGraph_any_one_bool; + op = GxB_ANY_BOOL_MONOID; +} \ No newline at end of file From 5c4ec36397d3cf2d0ff8db4363c405ae827fcde4 Mon Sep 17 00:00:00 2001 From: Rodion Suvorov Date: Sun, 20 Jul 2025 19:53:53 +0300 Subject: [PATCH 02/38] feat: add tests for rpq-matrix algorithm --- experimental/algorithm/LAGraph_RPQMatrix.c | 36 +++--- experimental/test/test_RPQMatrix.c | 129 +++++++++++++++++++++ include/LAGraphX.h | 48 ++++++++ 3 files changed, 195 insertions(+), 18 deletions(-) create mode 100644 experimental/test/test_RPQMatrix.c diff --git a/experimental/algorithm/LAGraph_RPQMatrix.c b/experimental/algorithm/LAGraph_RPQMatrix.c index d79802416a..c38cb50fe3 100644 --- a/experimental/algorithm/LAGraph_RPQMatrix.c +++ b/experimental/algorithm/LAGraph_RPQMatrix.c @@ -25,24 +25,24 @@ } \ } -typedef enum RpqMatrixOp -{ - RPQ_MATRIX_OP_LABEL, - RPQ_MATRIX_OP_LOR, - RPQ_MATRIX_OP_CONCAT, - RPQ_MATRIX_OP_KLEENE, - RPQ_MATRIX_OP_KLEENE_L, - RPQ_MATRIX_OP_KLEENE_R, -} RpqMatrixOp; - -typedef struct RpqMatrixPlan -{ - RpqMatrixOp op; - struct RpqMatrixPlan *lhs; - struct RpqMatrixPlan *rhs; - GrB_Matrix mat; - GrB_Matrix res_mat; -} RpqMatrixPlan; +// typedef enum RpqMatrixOp +// { +// RPQ_MATRIX_OP_LABEL, +// RPQ_MATRIX_OP_LOR, +// RPQ_MATRIX_OP_CONCAT, +// RPQ_MATRIX_OP_KLEENE, +// RPQ_MATRIX_OP_KLEENE_L, +// RPQ_MATRIX_OP_KLEENE_R, +// } RpqMatrixOp; + +// typedef struct RpqMatrixPlan +// { +// RpqMatrixOp op; +// struct RpqMatrixPlan *lhs; +// struct RpqMatrixPlan *rhs; +// GrB_Matrix mat; +// GrB_Matrix res_mat; +// } RpqMatrixPlan; static GrB_Semiring sr; static GrB_Monoid op; diff --git a/experimental/test/test_RPQMatrix.c b/experimental/test/test_RPQMatrix.c new file mode 100644 index 0000000000..43853afd62 --- /dev/null +++ b/experimental/test/test_RPQMatrix.c @@ -0,0 +1,129 @@ +#include +#include +#include +#include +#include +#include + +char msg[LAGRAPH_MSG_LEN]; + +//**************************************************************************** +void test_RPQMatrixKleene(void) +{ + LAGraph_Init(msg); + const char *nameA = "rpq_data/a.mtx"; + FILE *fA = fopen(nameA, "r"); + TEST_CHECK(fA != NULL); + GrB_Matrix A; + OK(LAGraph_MMRead(&A, fA, msg)); + OK(fclose(fA)); + RpqMatrixPlan graphA = { + .op = RPQ_MATRIX_OP_LABEL, + .lhs = NULL, + .rhs = NULL, + .mat = A, + .res_mat = NULL + }; + RpqMatrixPlan graphKleene = { + .op = RPQ_MATRIX_OP_KLEENE, + .lhs = NULL, + .rhs = &graphA, + .mat = NULL, + .res_mat = NULL + }; + GrB_Info res = LAGraph_RpqMatrix(&graphKleene,msg); + GrB_Matrix result_matrix = graphKleene.res_mat; + GrB_Index result; + GrB_Matrix_nvals(&result,result_matrix); + LAGraph_Finalize(msg); +} + +void test_RPQMatrixConc(void) +{ + LAGraph_Init(msg); + const char *nameA = "rpq_data/a.mtx"; + const char *nameB = "rpq_data/b.mtx"; + FILE *fA = fopen(nameA, "r"); + FILE *fB = fopen(nameB, "r"); + TEST_CHECK(fA != NULL); + TEST_CHECK(fB != NULL); + GrB_Matrix A, B; + OK(LAGraph_MMRead(&A, fA, msg)); + OK(LAGraph_MMRead(&B, fB, msg)); + OK(fclose(fA)); + OK(fclose(fB)); + RpqMatrixPlan graphA = { + .op = RPQ_MATRIX_OP_LABEL, + .lhs = NULL, + .rhs = NULL, + .mat = A, + .res_mat = NULL + }; + RpqMatrixPlan graphB = { + .op = RPQ_MATRIX_OP_LABEL, + .lhs = NULL, + .rhs = NULL, + .mat = B, + .res_mat = NULL + }; + RpqMatrixPlan graphConcat = { + .op = RPQ_MATRIX_OP_CONCAT, + .lhs = &graphA, + .rhs = &graphB, + .mat = NULL, + .res_mat = NULL + }; + GrB_Info res = LAGraph_RpqMatrix(&graphConcat,msg); + GrB_Matrix result_matrix = graphConcat.res_mat; + GrB_Index result; + GrB_Matrix_nvals(&result,result_matrix); + LAGraph_Finalize(msg); +} + +void test_RPQMatrixLor(void) +{ + LAGraph_Init(msg); + const char *nameA = "rpq_data/a.mtx"; + const char *nameB = "rpq_data/b.mtx"; + FILE *fA = fopen(nameA, "r"); + FILE *fB = fopen(nameB, "r"); + TEST_CHECK(fA != NULL); + TEST_CHECK(fB != NULL); + GrB_Matrix A, B; + OK(LAGraph_MMRead(&A, fA, msg)); + OK(LAGraph_MMRead(&A, fB, msg)); + OK(fclose(fA)); + OK(fclose(fB)); + RpqMatrixPlan graphA = { + .op = RPQ_MATRIX_OP_LABEL, + .lhs = NULL, + .rhs = NULL, + .mat = A, + .res_mat = NULL + }; + RpqMatrixPlan graphB = { + .op = RPQ_MATRIX_OP_LABEL, + .lhs = NULL, + .rhs = NULL, + .mat = B, + .res_mat = NULL + }; + RpqMatrixPlan graphLor = { + .op = RPQ_MATRIX_OP_LOR, + .lhs = &graphA, + .rhs = &graphB, + .mat = NULL, + .res_mat = NULL + }; + GrB_Info res = LAGraph_RpqMatrix(&graphLor,msg); + GrB_Matrix result_matrix = graphLor.res_mat; + GrB_Index result; + GrB_Matrix_nvals(&result,result_matrix); + LAGraph_Finalize(msg); +} + +TEST_LIST = { + {"RPQMatrixKleene", test_RPQMatrixKleene}, + {"RPQMatrixConc", test_RPQMatrixConc}, + {"RPQMatrixLor", test_RPQMatrixLor}, + {NULL, NULL}}; \ No newline at end of file diff --git a/include/LAGraphX.h b/include/LAGraphX.h index 7fa3655f2d..326fef7693 100644 --- a/include/LAGraphX.h +++ b/include/LAGraphX.h @@ -143,6 +143,31 @@ typedef struct } LAGraph_Contents ; +typedef enum RpqMatrixOp +{ + RPQ_MATRIX_OP_LABEL, + RPQ_MATRIX_OP_LOR, + RPQ_MATRIX_OP_CONCAT, + RPQ_MATRIX_OP_KLEENE, + RPQ_MATRIX_OP_KLEENE_L, + RPQ_MATRIX_OP_KLEENE_R, +} RpqMatrixOp; + +typedef struct RpqMatrixPlan +{ + RpqMatrixOp op; + struct RpqMatrixPlan *lhs; + struct RpqMatrixPlan *rhs; + GrB_Matrix mat; + GrB_Matrix res_mat; +} RpqMatrixPlan; + +LAGRAPHX_PUBLIC +GrB_Info LAGraph_Rpq_Matrix( + RpqMatrixPlan *plan, + char *msg + ); + LAGRAPHX_PUBLIC int LAGraph_SWrite_HeaderStart // write the first part of the JSON header ( @@ -847,6 +872,29 @@ int LAGraph_RegularPathQuery // nodes reachable from the starting by the ); //**************************************************************************** LAGRAPHX_PUBLIC +int LAGraph_RPQMatrix // nodes reachable from the starting by the + // path satisfying regular expression +( + // output: + GrB_Vector *reachable, // reachable(i) = true if node i is reachable + // from one of the starting nodes by a path + // satisfying regular constraints + // input: + LAGraph_Graph *R, // input non-deterministic finite automaton + // adjacency matrix decomposition + size_t nl, // total label count, # of matrices graph and + // NFA adjacency matrix decomposition + const GrB_Index *QS, // starting states in NFA + size_t nqs, // number of starting states in NFA + const GrB_Index *QF, // final states in NFA + size_t nqf, // number of final states in NFA + LAGraph_Graph *G, // input graph adjacency matrix decomposition + const GrB_Index *S, // source vertices to start searching paths + size_t ns, // number of source vertices + char *msg // LAGraph output message +); +//**************************************************************************** +LAGRAPHX_PUBLIC int LAGraph_VertexCentrality_Triangle // vertex triangle-centrality ( // outputs: From 718a3637fa3d5c123176d0f528758862617d36bd Mon Sep 17 00:00:00 2001 From: Rodion Suvorov Date: Fri, 25 Jul 2025 22:12:08 +0300 Subject: [PATCH 03/38] fix: correct test data filenames --- experimental/test/test_RPQMatrix.c | 164 ++++++++++++++++------------- 1 file changed, 88 insertions(+), 76 deletions(-) diff --git a/experimental/test/test_RPQMatrix.c b/experimental/test/test_RPQMatrix.c index 43853afd62..9555eb9dbd 100644 --- a/experimental/test/test_RPQMatrix.c +++ b/experimental/test/test_RPQMatrix.c @@ -6,52 +6,59 @@ #include char msg[LAGRAPH_MSG_LEN]; +#define LEN 512 //**************************************************************************** -void test_RPQMatrixKleene(void) -{ - LAGraph_Init(msg); - const char *nameA = "rpq_data/a.mtx"; - FILE *fA = fopen(nameA, "r"); - TEST_CHECK(fA != NULL); - GrB_Matrix A; - OK(LAGraph_MMRead(&A, fA, msg)); - OK(fclose(fA)); - RpqMatrixPlan graphA = { - .op = RPQ_MATRIX_OP_LABEL, - .lhs = NULL, - .rhs = NULL, - .mat = A, - .res_mat = NULL - }; - RpqMatrixPlan graphKleene = { - .op = RPQ_MATRIX_OP_KLEENE, - .lhs = NULL, - .rhs = &graphA, - .mat = NULL, - .res_mat = NULL - }; - GrB_Info res = LAGraph_RpqMatrix(&graphKleene,msg); - GrB_Matrix result_matrix = graphKleene.res_mat; - GrB_Index result; - GrB_Matrix_nvals(&result,result_matrix); - LAGraph_Finalize(msg); -} +// void test_RPQMatrixKleene(void) +// { +// LAGraph_Init(msg); +// const char *nameA = "rpq_data/a.mtx"; +// FILE *fA = fopen(nameA, "r"); +// TEST_CHECK(fA != NULL); +// GrB_Matrix A; +// OK(LAGraph_MMRead(&A, fA, msg)); +// OK(fclose(fA)); +// RpqMatrixPlan graphA = { +// .op = RPQ_MATRIX_OP_LABEL, +// .lhs = NULL, +// .rhs = NULL, +// .mat = A, +// .res_mat = NULL +// }; +// RpqMatrixPlan graphKleene = { +// .op = RPQ_MATRIX_OP_KLEENE, +// .lhs = NULL, +// .rhs = &graphA, +// .mat = NULL, +// .res_mat = NULL +// }; +// GrB_Info res = LAGraph_RpqMatrix(&graphKleene,msg); +// GrB_Matrix result_matrix = graphKleene.res_mat; +// GrB_Index result; +// GrB_Matrix_nvals(&result,result_matrix); +// LAGraph_Finalize(msg); +// } void test_RPQMatrixConc(void) { LAGraph_Init(msg); + fprintf(stderr,"start\n"); const char *nameA = "rpq_data/a.mtx"; const char *nameB = "rpq_data/b.mtx"; - FILE *fA = fopen(nameA, "r"); - FILE *fB = fopen(nameB, "r"); - TEST_CHECK(fA != NULL); - TEST_CHECK(fB != NULL); + char filenameA [LEN+1] ; + char filenameB [LEN+1] ; + snprintf (filenameA, LEN, LG_DATA_DIR "%s", nameA) ; + snprintf (filenameB, LEN, LG_DATA_DIR "%s", nameB) ; + FILE *fA = fopen(filenameA, "r"); + FILE *fB = fopen(filenameB, "r"); GrB_Matrix A, B; + fprintf(stderr,"before read\n"); + OK(LAGraph_MMRead(&A, fA, msg)); OK(LAGraph_MMRead(&B, fB, msg)); OK(fclose(fA)); OK(fclose(fB)); + fprintf(stderr,"before init\n"); RpqMatrixPlan graphA = { .op = RPQ_MATRIX_OP_LABEL, .lhs = NULL, @@ -73,6 +80,7 @@ void test_RPQMatrixConc(void) .mat = NULL, .res_mat = NULL }; + fprintf(stderr,"before run\n"); GrB_Info res = LAGraph_RpqMatrix(&graphConcat,msg); GrB_Matrix result_matrix = graphConcat.res_mat; GrB_Index result; @@ -80,50 +88,54 @@ void test_RPQMatrixConc(void) LAGraph_Finalize(msg); } -void test_RPQMatrixLor(void) -{ - LAGraph_Init(msg); - const char *nameA = "rpq_data/a.mtx"; - const char *nameB = "rpq_data/b.mtx"; - FILE *fA = fopen(nameA, "r"); - FILE *fB = fopen(nameB, "r"); - TEST_CHECK(fA != NULL); - TEST_CHECK(fB != NULL); - GrB_Matrix A, B; - OK(LAGraph_MMRead(&A, fA, msg)); - OK(LAGraph_MMRead(&A, fB, msg)); - OK(fclose(fA)); - OK(fclose(fB)); - RpqMatrixPlan graphA = { - .op = RPQ_MATRIX_OP_LABEL, - .lhs = NULL, - .rhs = NULL, - .mat = A, - .res_mat = NULL - }; - RpqMatrixPlan graphB = { - .op = RPQ_MATRIX_OP_LABEL, - .lhs = NULL, - .rhs = NULL, - .mat = B, - .res_mat = NULL - }; - RpqMatrixPlan graphLor = { - .op = RPQ_MATRIX_OP_LOR, - .lhs = &graphA, - .rhs = &graphB, - .mat = NULL, - .res_mat = NULL - }; - GrB_Info res = LAGraph_RpqMatrix(&graphLor,msg); - GrB_Matrix result_matrix = graphLor.res_mat; - GrB_Index result; - GrB_Matrix_nvals(&result,result_matrix); - LAGraph_Finalize(msg); -} +// void test_RPQMatrixLor(void) +// { +// LAGraph_Init(msg); +// const char *nameA = "rpq_data/a.mtx"; +// const char *nameB = "rpq_data/b.mtx"; +// snprintf (filename, LEN, LG_DATA_DIR "%s", name) ; + +// snprintf (filename, LEN, LG_DATA_DIR "%s", name) ; + +// FILE *fA = fopen(nameA, "r"); +// FILE *fB = fopen(nameB, "r"); +// TEST_CHECK(fA != NULL); +// TEST_CHECK(fB != NULL); +// GrB_Matrix A, B; +// OK(LAGraph_MMRead(&A, fA, msg)); +// OK(LAGraph_MMRead(&A, fB, msg)); +// OK(fclose(fA)); +// OK(fclose(fB)); +// RpqMatrixPlan graphA = { +// .op = RPQ_MATRIX_OP_LABEL, +// .lhs = NULL, +// .rhs = NULL, +// .mat = A, +// .res_mat = NULL +// }; +// RpqMatrixPlan graphB = { +// .op = RPQ_MATRIX_OP_LABEL, +// .lhs = NULL, +// .rhs = NULL, +// .mat = B, +// .res_mat = NULL +// }; +// RpqMatrixPlan graphLor = { +// .op = RPQ_MATRIX_OP_LOR, +// .lhs = &graphA, +// .rhs = &graphB, +// .mat = NULL, +// .res_mat = NULL +// }; +// GrB_Info res = LAGraph_RpqMatrix(&graphLor,msg); +// GrB_Matrix result_matrix = graphLor.res_mat; +// GrB_Index result; +// GrB_Matrix_nvals(&result,result_matrix); +// LAGraph_Finalize(msg); +// } TEST_LIST = { - {"RPQMatrixKleene", test_RPQMatrixKleene}, + // {"RPQMatrixKleene", test_RPQMatrixKleene}, {"RPQMatrixConc", test_RPQMatrixConc}, - {"RPQMatrixLor", test_RPQMatrixLor}, + // {"RPQMatrixLor", test_RPQMatrixLor}, {NULL, NULL}}; \ No newline at end of file From 9249d63724afe3e0452e16e60512eb852ae1be9d Mon Sep 17 00:00:00 2001 From: Rodion Suvorov Date: Sun, 27 Jul 2025 15:51:20 +0300 Subject: [PATCH 04/38] fix: garbage in answer for a b query --- experimental/algorithm/LAGraph_RPQMatrix.c | 47 ++++++++++++++++++---- experimental/test/test_RPQMatrix.c | 24 ++++++++--- include/LAGraphX.h | 28 ++----------- 3 files changed, 60 insertions(+), 39 deletions(-) diff --git a/experimental/algorithm/LAGraph_RPQMatrix.c b/experimental/algorithm/LAGraph_RPQMatrix.c index c38cb50fe3..44a70788fc 100644 --- a/experimental/algorithm/LAGraph_RPQMatrix.c +++ b/experimental/algorithm/LAGraph_RPQMatrix.c @@ -61,8 +61,8 @@ static GrB_Info LAGraph_RpqMatrixLor(RpqMatrixPlan *plan, char *msg) LG_ASSERT(lhs != NULL, GrB_NULL_POINTER); LG_ASSERT(rhs != NULL, GrB_NULL_POINTER); - OK(LAGraph_RpqMatrix(lhs, msg)); - OK(LAGraph_RpqMatrix(rhs, msg)); + OK(LAGraph_RPQMatrix(lhs, msg)); + OK(LAGraph_RPQMatrix(rhs, msg)); GrB_Matrix lhs_mat = lhs->res_mat; GrB_Matrix rhs_mat = rhs->res_mat; @@ -75,6 +75,7 @@ static GrB_Info LAGraph_RpqMatrixLor(RpqMatrixPlan *plan, char *msg) static GrB_Info LAGraph_RpqMatrixConcat(RpqMatrixPlan *plan, char *msg) { + LG_ASSERT(plan != NULL, GrB_NULL_POINTER); LG_ASSERT(plan->op == RPQ_MATRIX_OP_CONCAT, GrB_INVALID_VALUE); LG_ASSERT(plan->res_mat == NULL, GrB_INVALID_VALUE); @@ -82,17 +83,36 @@ static GrB_Info LAGraph_RpqMatrixConcat(RpqMatrixPlan *plan, char *msg) RpqMatrixPlan *lhs = plan->lhs; RpqMatrixPlan *rhs = plan->rhs; + GrB_Index nvalsA, nvalsB; + GrB_Matrix_nvals(&nvalsA, lhs->mat); + GrB_Matrix_nvals(&nvalsB, rhs->mat); + fprintf(stderr, "\nDEBUG: A:%lu and B:%lu in Concat\n", nvalsA, nvalsB); + LG_ASSERT(lhs != NULL, GrB_NULL_POINTER); LG_ASSERT(rhs != NULL, GrB_NULL_POINTER); - OK(LAGraph_RpqMatrix(lhs, msg)); - OK(LAGraph_RpqMatrix(rhs, msg)); + OK(LAGraph_RPQMatrix(lhs, msg)); + OK(LAGraph_RPQMatrix(rhs, msg)); GrB_Matrix lhs_mat = lhs->res_mat; GrB_Matrix rhs_mat = rhs->res_mat; - GRB_TRY(GrB_mxm(plan->res_mat, GrB_NULL, GrB_NULL, + GrB_Matrix_nvals(&nvalsA, lhs_mat); + GrB_Matrix_nvals(&nvalsB, rhs_mat); + fprintf(stderr, "\nDEBUG: A:%lu and B:%lu in Concat after traversal\n", nvalsA, nvalsB); + fprintf(stderr, "\nDEBUG: before mxm\n"); + + GrB_Index width, height; + GrB_Matrix_nrows(&height, rhs_mat); + GrB_Matrix_ncols(&width, lhs_mat); + GrB_Matrix res; + GrB_Matrix_new(&res, GrB_BOOL, height, width); + GRB_TRY(GrB_mxm(res, GrB_NULL, GrB_NULL, sr, lhs_mat, rhs_mat, GrB_DESC_R)); + // GrB_mxm(plan->res_mat, GrB_NULL, GrB_NULL, GrB_LOR_LAND_SEMIRING_BOOL, lhs_mat, rhs_mat, GrB_NULL); + plan->res_mat = res; + GrB_Matrix_nvals(&nvalsA, plan->res_mat); + fprintf(stderr, "\nDEBUG: A:%lu after mxm in Concat\n", nvalsA); return (GrB_SUCCESS); } @@ -110,7 +130,7 @@ static GrB_Info LAGraph_RpqMatrixKleene(RpqMatrixPlan *plan, char *msg) LG_ASSERT(lhs == NULL, GrB_NULL_POINTER); LG_ASSERT(rhs != NULL, GrB_NULL_POINTER); - OK(LAGraph_RpqMatrix(rhs, msg)); + OK(LAGraph_RPQMatrix(rhs, msg)); GrB_Matrix B = rhs->res_mat; @@ -144,7 +164,7 @@ static GrB_Info LAGraph_RpqMatrixKleene(RpqMatrixPlan *plan, char *msg) // T = S * (B + E) GRB_TRY(GrB_Matrix_new(&T, GrB_BOOL, n, n)); GRB_TRY(GrB_mxm(T, GrB_NULL, GrB_NULL, - sr, S, BPE, GrB_DESC_R)); + sr, S, BPE, GrB_DESC_R)); GRB_TRY(GrB_Matrix_nvals(&nnz_T, T)); if (nnz_T != nnz_S) @@ -167,15 +187,23 @@ static GrB_Info LAGraph_RpqMatrixKleene(RpqMatrixPlan *plan, char *msg) return (GrB_SUCCESS); } -GrB_Info LAGraph_RpqMatrix(RpqMatrixPlan *plan, char *msg) +GrB_Info LAGraph_RPQMatrix(RpqMatrixPlan *plan, char *msg) { if (plan->res_mat != NULL) + { + GrB_Index result; + GrB_Matrix_nvals(&result, plan->res_mat); + fprintf(stderr, "\nDEBUG: res_mat in LAGraph_RPQMatrix: %lu", result); return (GrB_SUCCESS); + } switch (plan->op) { case RPQ_MATRIX_OP_LABEL: LG_ASSERT(plan->lhs == NULL && plan->rhs == NULL, GrB_INVALID_VALUE); + GrB_Index result; + GrB_Matrix_nvals(&result, plan->mat); + fprintf(stderr, "\nDEBUG: res_mat in LAGraph_RPQMatrix switch: %lu", result); plan->res_mat = plan->mat; return (GrB_SUCCESS); case RPQ_MATRIX_OP_LOR: @@ -187,6 +215,9 @@ GrB_Info LAGraph_RpqMatrix(RpqMatrixPlan *plan, char *msg) default: LG_ASSERT(false, GrB_INVALID_VALUE); } + GrB_Index result; + GrB_Matrix_nvals(&result, plan->res_mat); + fprintf(stderr, "\nDEBUG: res_mat in LAGraph_RPQMatrix end: %lu", result); return (GrB_SUCCESS); } diff --git a/experimental/test/test_RPQMatrix.c b/experimental/test/test_RPQMatrix.c index 9555eb9dbd..2f616ed526 100644 --- a/experimental/test/test_RPQMatrix.c +++ b/experimental/test/test_RPQMatrix.c @@ -42,7 +42,7 @@ char msg[LAGRAPH_MSG_LEN]; void test_RPQMatrixConc(void) { LAGraph_Init(msg); - fprintf(stderr,"start\n"); + LAGraph_RpqMatrix_initialize(); const char *nameA = "rpq_data/a.mtx"; const char *nameB = "rpq_data/b.mtx"; char filenameA [LEN+1] ; @@ -52,13 +52,16 @@ void test_RPQMatrixConc(void) FILE *fA = fopen(filenameA, "r"); FILE *fB = fopen(filenameB, "r"); GrB_Matrix A, B; - fprintf(stderr,"before read\n"); - OK(LAGraph_MMRead(&A, fA, msg)); OK(LAGraph_MMRead(&B, fB, msg)); OK(fclose(fA)); OK(fclose(fB)); - fprintf(stderr,"before init\n"); + + GrB_Index nvalsA, nvalsB; + GrB_Matrix_nvals(&nvalsA,A); + GrB_Matrix_nvals(&nvalsB,B); + fprintf(stderr,"\nDEBUG: A:%lu and B:%lu\n",nvalsA,nvalsB); + RpqMatrixPlan graphA = { .op = RPQ_MATRIX_OP_LABEL, .lhs = NULL, @@ -80,11 +83,20 @@ void test_RPQMatrixConc(void) .mat = NULL, .res_mat = NULL }; - fprintf(stderr,"before run\n"); - GrB_Info res = LAGraph_RpqMatrix(&graphConcat,msg); + RpqMatrixPlan graphKleene = { + .op = RPQ_MATRIX_OP_KLEENE, + .lhs = NULL, + .rhs = &graphConcat, + .mat = NULL, + .res_mat = NULL + }; + GrB_Index expected_nvasl = 3; + GrB_Info res = LAGraph_RPQMatrix(&graphKleene,msg); GrB_Matrix result_matrix = graphConcat.res_mat; GrB_Index result; GrB_Matrix_nvals(&result,result_matrix); + fprintf(stderr,"\nDEBUG: result: %lu",result); + TEST_CHECK(result == expected_nvasl); LAGraph_Finalize(msg); } diff --git a/include/LAGraphX.h b/include/LAGraphX.h index 326fef7693..5d6ec1975f 100644 --- a/include/LAGraphX.h +++ b/include/LAGraphX.h @@ -163,11 +163,12 @@ typedef struct RpqMatrixPlan } RpqMatrixPlan; LAGRAPHX_PUBLIC -GrB_Info LAGraph_Rpq_Matrix( +GrB_Info LAGraph_RPQMatrix( RpqMatrixPlan *plan, char *msg ); - +LAGRAPHX_PUBLIC +GrB_Info LAGraph_RpqMatrix_initialize(); LAGRAPHX_PUBLIC int LAGraph_SWrite_HeaderStart // write the first part of the JSON header ( @@ -872,29 +873,6 @@ int LAGraph_RegularPathQuery // nodes reachable from the starting by the ); //**************************************************************************** LAGRAPHX_PUBLIC -int LAGraph_RPQMatrix // nodes reachable from the starting by the - // path satisfying regular expression -( - // output: - GrB_Vector *reachable, // reachable(i) = true if node i is reachable - // from one of the starting nodes by a path - // satisfying regular constraints - // input: - LAGraph_Graph *R, // input non-deterministic finite automaton - // adjacency matrix decomposition - size_t nl, // total label count, # of matrices graph and - // NFA adjacency matrix decomposition - const GrB_Index *QS, // starting states in NFA - size_t nqs, // number of starting states in NFA - const GrB_Index *QF, // final states in NFA - size_t nqf, // number of final states in NFA - LAGraph_Graph *G, // input graph adjacency matrix decomposition - const GrB_Index *S, // source vertices to start searching paths - size_t ns, // number of source vertices - char *msg // LAGraph output message -); -//**************************************************************************** -LAGRAPHX_PUBLIC int LAGraph_VertexCentrality_Triangle // vertex triangle-centrality ( // outputs: From 452c0de5b148a4ba07ac9d952bf5099c5b5b5036 Mon Sep 17 00:00:00 2001 From: Rodion Suvorov Date: Thu, 31 Jul 2025 18:19:46 +0300 Subject: [PATCH 05/38] fix: correct test cases --- experimental/algorithm/LAGraph_RPQMatrix.c | 42 +++---- experimental/test/test_RPQMatrix.c | 137 +++++++++------------ 2 files changed, 75 insertions(+), 104 deletions(-) diff --git a/experimental/algorithm/LAGraph_RPQMatrix.c b/experimental/algorithm/LAGraph_RPQMatrix.c index 44a70788fc..13adf4363c 100644 --- a/experimental/algorithm/LAGraph_RPQMatrix.c +++ b/experimental/algorithm/LAGraph_RPQMatrix.c @@ -67,8 +67,14 @@ static GrB_Info LAGraph_RpqMatrixLor(RpqMatrixPlan *plan, char *msg) GrB_Matrix lhs_mat = lhs->res_mat; GrB_Matrix rhs_mat = rhs->res_mat; - GRB_TRY(GrB_eWiseAdd(plan->res_mat, GrB_NULL, GrB_NULL, - op, lhs_mat, rhs_mat, GrB_DESC_R)); + GrB_Index width, height; + GrB_Matrix_nrows(&height, rhs_mat); + GrB_Matrix_ncols(&width, lhs_mat); + GrB_Matrix res; + GrB_Matrix_new(&res, GrB_BOOL, height, width); + GRB_TRY(GrB_eWiseAdd(res, GrB_NULL, GrB_NULL, + GrB_LOR, lhs_mat, rhs_mat, GrB_DESC_R)); + plan->res_mat = res; return (GrB_SUCCESS); } @@ -83,11 +89,6 @@ static GrB_Info LAGraph_RpqMatrixConcat(RpqMatrixPlan *plan, char *msg) RpqMatrixPlan *lhs = plan->lhs; RpqMatrixPlan *rhs = plan->rhs; - GrB_Index nvalsA, nvalsB; - GrB_Matrix_nvals(&nvalsA, lhs->mat); - GrB_Matrix_nvals(&nvalsB, rhs->mat); - fprintf(stderr, "\nDEBUG: A:%lu and B:%lu in Concat\n", nvalsA, nvalsB); - LG_ASSERT(lhs != NULL, GrB_NULL_POINTER); LG_ASSERT(rhs != NULL, GrB_NULL_POINTER); @@ -97,22 +98,15 @@ static GrB_Info LAGraph_RpqMatrixConcat(RpqMatrixPlan *plan, char *msg) GrB_Matrix lhs_mat = lhs->res_mat; GrB_Matrix rhs_mat = rhs->res_mat; - GrB_Matrix_nvals(&nvalsA, lhs_mat); - GrB_Matrix_nvals(&nvalsB, rhs_mat); - fprintf(stderr, "\nDEBUG: A:%lu and B:%lu in Concat after traversal\n", nvalsA, nvalsB); - fprintf(stderr, "\nDEBUG: before mxm\n"); - GrB_Index width, height; GrB_Matrix_nrows(&height, rhs_mat); GrB_Matrix_ncols(&width, lhs_mat); GrB_Matrix res; GrB_Matrix_new(&res, GrB_BOOL, height, width); GRB_TRY(GrB_mxm(res, GrB_NULL, GrB_NULL, - sr, lhs_mat, rhs_mat, GrB_DESC_R)); + GrB_LOR_LAND_SEMIRING_BOOL, lhs_mat, rhs_mat, GrB_DESC_R)); // GrB_mxm(plan->res_mat, GrB_NULL, GrB_NULL, GrB_LOR_LAND_SEMIRING_BOOL, lhs_mat, rhs_mat, GrB_NULL); plan->res_mat = res; - GrB_Matrix_nvals(&nvalsA, plan->res_mat); - fprintf(stderr, "\nDEBUG: A:%lu after mxm in Concat\n", nvalsA); return (GrB_SUCCESS); } @@ -152,19 +146,20 @@ static GrB_Info LAGraph_RpqMatrixKleene(RpqMatrixPlan *plan, char *msg) GrB_Matrix BPE; GRB_TRY(GrB_Matrix_new(&BPE, GrB_BOOL, n, n)); GRB_TRY(GrB_eWiseAdd(BPE, GrB_NULL, GrB_NULL, - op, B, E, GrB_DESC_R)); + GrB_LOR, B, E, GrB_DESC_R)); // S <- S x (B + E) GrB_Matrix S, T; GRB_TRY(GrB_Matrix_dup(&S, E)); bool changed = true; GrB_Index nnz_S = n, nnz_T = 0; + while (changed) { // T = S * (B + E) GRB_TRY(GrB_Matrix_new(&T, GrB_BOOL, n, n)); GRB_TRY(GrB_mxm(T, GrB_NULL, GrB_NULL, - sr, S, BPE, GrB_DESC_R)); + GrB_LOR_LAND_SEMIRING_BOOL, S, BPE, GrB_DESC_R)); GRB_TRY(GrB_Matrix_nvals(&nnz_T, T)); if (nnz_T != nnz_S) @@ -191,9 +186,6 @@ GrB_Info LAGraph_RPQMatrix(RpqMatrixPlan *plan, char *msg) { if (plan->res_mat != NULL) { - GrB_Index result; - GrB_Matrix_nvals(&result, plan->res_mat); - fprintf(stderr, "\nDEBUG: res_mat in LAGraph_RPQMatrix: %lu", result); return (GrB_SUCCESS); } @@ -201,9 +193,6 @@ GrB_Info LAGraph_RPQMatrix(RpqMatrixPlan *plan, char *msg) { case RPQ_MATRIX_OP_LABEL: LG_ASSERT(plan->lhs == NULL && plan->rhs == NULL, GrB_INVALID_VALUE); - GrB_Index result; - GrB_Matrix_nvals(&result, plan->mat); - fprintf(stderr, "\nDEBUG: res_mat in LAGraph_RPQMatrix switch: %lu", result); plan->res_mat = plan->mat; return (GrB_SUCCESS); case RPQ_MATRIX_OP_LOR: @@ -215,14 +204,11 @@ GrB_Info LAGraph_RPQMatrix(RpqMatrixPlan *plan, char *msg) default: LG_ASSERT(false, GrB_INVALID_VALUE); } - GrB_Index result; - GrB_Matrix_nvals(&result, plan->res_mat); - fprintf(stderr, "\nDEBUG: res_mat in LAGraph_RPQMatrix end: %lu", result); return (GrB_SUCCESS); } GrB_Info LAGraph_RpqMatrix_initialize() { - sr = LAGraph_any_one_bool; - op = GxB_ANY_BOOL_MONOID; + sr = GrB_LOR_LAND_SEMIRING_BOOL; + op = GrB_LOR; } \ No newline at end of file diff --git a/experimental/test/test_RPQMatrix.c b/experimental/test/test_RPQMatrix.c index 2f616ed526..0aa422629d 100644 --- a/experimental/test/test_RPQMatrix.c +++ b/experimental/test/test_RPQMatrix.c @@ -9,35 +9,6 @@ char msg[LAGRAPH_MSG_LEN]; #define LEN 512 //**************************************************************************** -// void test_RPQMatrixKleene(void) -// { -// LAGraph_Init(msg); -// const char *nameA = "rpq_data/a.mtx"; -// FILE *fA = fopen(nameA, "r"); -// TEST_CHECK(fA != NULL); -// GrB_Matrix A; -// OK(LAGraph_MMRead(&A, fA, msg)); -// OK(fclose(fA)); -// RpqMatrixPlan graphA = { -// .op = RPQ_MATRIX_OP_LABEL, -// .lhs = NULL, -// .rhs = NULL, -// .mat = A, -// .res_mat = NULL -// }; -// RpqMatrixPlan graphKleene = { -// .op = RPQ_MATRIX_OP_KLEENE, -// .lhs = NULL, -// .rhs = &graphA, -// .mat = NULL, -// .res_mat = NULL -// }; -// GrB_Info res = LAGraph_RpqMatrix(&graphKleene,msg); -// GrB_Matrix result_matrix = graphKleene.res_mat; -// GrB_Index result; -// GrB_Matrix_nvals(&result,result_matrix); -// LAGraph_Finalize(msg); -// } void test_RPQMatrixConc(void) { @@ -90,9 +61,9 @@ void test_RPQMatrixConc(void) .mat = NULL, .res_mat = NULL }; - GrB_Index expected_nvasl = 3; + GrB_Index expected_nvasl = 14; GrB_Info res = LAGraph_RPQMatrix(&graphKleene,msg); - GrB_Matrix result_matrix = graphConcat.res_mat; + GrB_Matrix result_matrix = graphKleene.res_mat; GrB_Index result; GrB_Matrix_nvals(&result,result_matrix); fprintf(stderr,"\nDEBUG: result: %lu",result); @@ -100,54 +71,68 @@ void test_RPQMatrixConc(void) LAGraph_Finalize(msg); } -// void test_RPQMatrixLor(void) -// { -// LAGraph_Init(msg); -// const char *nameA = "rpq_data/a.mtx"; -// const char *nameB = "rpq_data/b.mtx"; -// snprintf (filename, LEN, LG_DATA_DIR "%s", name) ; - -// snprintf (filename, LEN, LG_DATA_DIR "%s", name) ; +void test_RPQMatrixLor(void) +{ + LAGraph_Init(msg); + LAGraph_RpqMatrix_initialize(); + const char *nameA = "rpq_data/a.mtx"; + const char *nameB = "rpq_data/b.mtx"; + char filenameA [LEN+1] ; + char filenameB [LEN+1] ; + snprintf (filenameA, LEN, LG_DATA_DIR "%s", nameA) ; + snprintf (filenameB, LEN, LG_DATA_DIR "%s", nameB) ; + FILE *fA = fopen(filenameA, "r"); + FILE *fB = fopen(filenameB, "r"); + GrB_Matrix A, B; + OK(LAGraph_MMRead(&A, fA, msg)); + OK(LAGraph_MMRead(&B, fB, msg)); + OK(fclose(fA)); + OK(fclose(fB)); -// FILE *fA = fopen(nameA, "r"); -// FILE *fB = fopen(nameB, "r"); -// TEST_CHECK(fA != NULL); -// TEST_CHECK(fB != NULL); -// GrB_Matrix A, B; -// OK(LAGraph_MMRead(&A, fA, msg)); -// OK(LAGraph_MMRead(&A, fB, msg)); -// OK(fclose(fA)); -// OK(fclose(fB)); -// RpqMatrixPlan graphA = { -// .op = RPQ_MATRIX_OP_LABEL, -// .lhs = NULL, -// .rhs = NULL, -// .mat = A, -// .res_mat = NULL -// }; -// RpqMatrixPlan graphB = { -// .op = RPQ_MATRIX_OP_LABEL, -// .lhs = NULL, -// .rhs = NULL, -// .mat = B, -// .res_mat = NULL -// }; -// RpqMatrixPlan graphLor = { -// .op = RPQ_MATRIX_OP_LOR, -// .lhs = &graphA, -// .rhs = &graphB, -// .mat = NULL, -// .res_mat = NULL -// }; -// GrB_Info res = LAGraph_RpqMatrix(&graphLor,msg); -// GrB_Matrix result_matrix = graphLor.res_mat; -// GrB_Index result; -// GrB_Matrix_nvals(&result,result_matrix); -// LAGraph_Finalize(msg); -// } + GrB_Index nvalsA, nvalsB; + GrB_Matrix_nvals(&nvalsA,A); + GrB_Matrix_nvals(&nvalsB,B); + fprintf(stderr,"\nDEBUG: A:%lu and B:%lu\n",nvalsA,nvalsB); + RpqMatrixPlan graphA = { + .op = RPQ_MATRIX_OP_LABEL, + .lhs = NULL, + .rhs = NULL, + .mat = A, + .res_mat = NULL + }; + RpqMatrixPlan graphB = { + .op = RPQ_MATRIX_OP_LABEL, + .lhs = NULL, + .rhs = NULL, + .mat = B, + .res_mat = NULL + }; + RpqMatrixPlan graphLor = { + .op = RPQ_MATRIX_OP_LOR, + .lhs = &graphA, + .rhs = &graphB, + .mat = NULL, + .res_mat = NULL + }; + RpqMatrixPlan graphKleene = { + .op = RPQ_MATRIX_OP_KLEENE, + .lhs = NULL, + .rhs = &graphLor, + .mat = NULL, + .res_mat = NULL + }; + GrB_Index expected_nvasl = 35; + GrB_Info res = LAGraph_RPQMatrix(&graphKleene,msg); + GrB_Matrix result_matrix = graphKleene.res_mat; + GrB_Index result; + GrB_Matrix_nvals(&result,result_matrix); + fprintf(stderr,"\nDEBUG: result: %lu",result); + TEST_CHECK(result == expected_nvasl); + LAGraph_Finalize(msg); +} TEST_LIST = { // {"RPQMatrixKleene", test_RPQMatrixKleene}, {"RPQMatrixConc", test_RPQMatrixConc}, - // {"RPQMatrixLor", test_RPQMatrixLor}, + {"RPQMatrixLor", test_RPQMatrixLor}, {NULL, NULL}}; \ No newline at end of file From 049ac6d3255a45f6792f10389e58f83b1f97e9d6 Mon Sep 17 00:00:00 2001 From: Rodion Suvorov Date: Sat, 2 Aug 2025 18:09:50 +0300 Subject: [PATCH 06/38] feat: label handler function --- experimental/algorithm/LAGraph_RPQMatrix.c | 171 ++++++++++++++++++--- 1 file changed, 152 insertions(+), 19 deletions(-) diff --git a/experimental/algorithm/LAGraph_RPQMatrix.c b/experimental/algorithm/LAGraph_RPQMatrix.c index 13adf4363c..b1ae479e30 100644 --- a/experimental/algorithm/LAGraph_RPQMatrix.c +++ b/experimental/algorithm/LAGraph_RPQMatrix.c @@ -25,30 +25,18 @@ } \ } -// typedef enum RpqMatrixOp -// { -// RPQ_MATRIX_OP_LABEL, -// RPQ_MATRIX_OP_LOR, -// RPQ_MATRIX_OP_CONCAT, -// RPQ_MATRIX_OP_KLEENE, -// RPQ_MATRIX_OP_KLEENE_L, -// RPQ_MATRIX_OP_KLEENE_R, -// } RpqMatrixOp; - -// typedef struct RpqMatrixPlan -// { -// RpqMatrixOp op; -// struct RpqMatrixPlan *lhs; -// struct RpqMatrixPlan *rhs; -// GrB_Matrix mat; -// GrB_Matrix res_mat; -// } RpqMatrixPlan; - static GrB_Semiring sr; static GrB_Monoid op; GrB_Info LAGraph_RpqMatrix(RpqMatrixPlan *plan, char *msg); +GrB_Info LAGraph_RPQMatrix_label(GrB_Matrix *mat, GrB_Index x, GrB_Index i, GrB_Index j) { + GrB_Matrix_new(mat, GrB_BOOL, i, j); + GrB_Matrix_setElement(*mat, true, x, x); + return (GrB_SUCCESS); +} + + static GrB_Info LAGraph_RpqMatrixLor(RpqMatrixPlan *plan, char *msg) { LG_ASSERT(plan != NULL, GrB_NULL_POINTER); @@ -181,6 +169,147 @@ static GrB_Info LAGraph_RpqMatrixKleene(RpqMatrixPlan *plan, char *msg) GRB_TRY(GrB_Matrix_free(&BPE)); return (GrB_SUCCESS); } +static GrB_Info LAGraph_RpqMatrixKleene_L(RpqMatrixPlan *plan, char *msg) +{ +LG_ASSERT(plan != NULL, GrB_NULL_POINTER); + LG_ASSERT(plan->op == RPQ_MATRIX_OP_KLEENE, GrB_INVALID_VALUE); + LG_ASSERT(plan->res_mat == NULL, GrB_INVALID_VALUE); + + RpqMatrixPlan *lhs = plan->lhs; + RpqMatrixPlan *rhs = plan->rhs; + + // Kleene star should have one child. Always right. + LG_ASSERT(lhs == NULL, GrB_NULL_POINTER); + LG_ASSERT(rhs == NULL, GrB_NULL_POINTER); + + OK(LAGraph_RPQMatrix(rhs, msg)); + + GrB_Matrix B = rhs->res_mat; + + // Creating identity matrix. + GrB_Index n; + GRB_TRY(GrB_Matrix_nrows(&n, B)); + GrB_Matrix E; + GRB_TRY(GrB_Matrix_new(&E, GrB_BOOL, n, n)); + + GrB_Vector v; + GRB_TRY(GrB_Vector_new(&v, GrB_BOOL, n)); + GRB_TRY(GrB_Vector_assign_BOOL(v, NULL, NULL, true, GrB_ALL, n, NULL)); + + GRB_TRY(GrB_Matrix_diag(&E, v, 0)); + + GRB_TRY(GrB_Vector_free(&v)); + + // B + E + GrB_Matrix BPE; + GRB_TRY(GrB_Matrix_new(&BPE, GrB_BOOL, n, n)); + GRB_TRY(GrB_eWiseAdd(BPE, GrB_NULL, GrB_NULL, + GrB_LOR, B, E, GrB_DESC_R)); + // S <- S x (B + E) + GrB_Matrix S, T; + GRB_TRY(GrB_Matrix_dup(&S, E)); + + bool changed = true; + GrB_Index nnz_S = n, nnz_T = 0; + + while (changed) + { + // T = S * (B + E) + GRB_TRY(GrB_Matrix_new(&T, GrB_BOOL, n, n)); + GRB_TRY(GrB_mxm(T, GrB_NULL, GrB_NULL, + GrB_LOR_LAND_SEMIRING_BOOL, S, BPE, GrB_DESC_R)); + + GRB_TRY(GrB_Matrix_nvals(&nnz_T, T)); + if (nnz_T != nnz_S) + { + changed = true; + nnz_S = nnz_T; + GRB_TRY(GrB_Matrix_free(&S)); + S = T; + } + else + { + changed = false; + GRB_TRY(GrB_Matrix_free(&T)); + } + } + plan->res_mat = S; + + GRB_TRY(GrB_Matrix_free(&E)); + GRB_TRY(GrB_Matrix_free(&BPE)); + return (GrB_SUCCESS); +} + +static GrB_Info LAGraph_RpqMatrixKleene_R(RpqMatrixPlan *plan, char *msg) +{ + LG_ASSERT(plan != NULL, GrB_NULL_POINTER); + LG_ASSERT(plan->op == RPQ_MATRIX_OP_KLEENE, GrB_INVALID_VALUE); + LG_ASSERT(plan->res_mat == NULL, GrB_INVALID_VALUE); + + RpqMatrixPlan *lhs = plan->lhs; + RpqMatrixPlan *rhs = plan->rhs; + + LG_ASSERT(lhs != NULL, GrB_NULL_POINTER); + LG_ASSERT(rhs != NULL, GrB_NULL_POINTER); + + OK(LAGraph_RPQMatrix(rhs, msg)); + + GrB_Matrix B = rhs->res_mat; + + // Creating identity matrix. + GrB_Index n; + GRB_TRY(GrB_Matrix_nrows(&n, B)); + GrB_Matrix E; + GRB_TRY(GrB_Matrix_new(&E, GrB_BOOL, n, n)); + + GrB_Vector v; + GRB_TRY(GrB_Vector_new(&v, GrB_BOOL, n)); + GRB_TRY(GrB_Vector_assign_BOOL(v, NULL, NULL, true, GrB_ALL, n, NULL)); + + GRB_TRY(GrB_Matrix_diag(&E, v, 0)); + + GRB_TRY(GrB_Vector_free(&v)); + + // B + E + GrB_Matrix BPE; + GRB_TRY(GrB_Matrix_new(&BPE, GrB_BOOL, n, n)); + GRB_TRY(GrB_eWiseAdd(BPE, GrB_NULL, GrB_NULL, + GrB_LOR, B, E, GrB_DESC_R)); + // S <- S x (B + E) + GrB_Matrix S, T; + GRB_TRY(GrB_Matrix_dup(&S, E)); + + bool changed = true; + GrB_Index nnz_S = n, nnz_T = 0; + + while (changed) + { + // T = S * (B + E) + GRB_TRY(GrB_Matrix_new(&T, GrB_BOOL, n, n)); + GRB_TRY(GrB_mxm(T, GrB_NULL, GrB_NULL, + GrB_LOR_LAND_SEMIRING_BOOL, S, BPE, GrB_DESC_R)); + + GRB_TRY(GrB_Matrix_nvals(&nnz_T, T)); + if (nnz_T != nnz_S) + { + changed = true; + nnz_S = nnz_T; + GRB_TRY(GrB_Matrix_free(&S)); + S = T; + } + else + { + changed = false; + GRB_TRY(GrB_Matrix_free(&T)); + } + } + plan->res_mat = S; + + GRB_TRY(GrB_Matrix_free(&E)); + GRB_TRY(GrB_Matrix_free(&BPE)); + return (GrB_SUCCESS); +} + GrB_Info LAGraph_RPQMatrix(RpqMatrixPlan *plan, char *msg) { @@ -201,6 +330,10 @@ GrB_Info LAGraph_RPQMatrix(RpqMatrixPlan *plan, char *msg) return LAGraph_RpqMatrixConcat(plan, msg); case RPQ_MATRIX_OP_KLEENE: return LAGraph_RpqMatrixKleene(plan, msg); + case RPQ_MATRIX_OP_KLEENE_L: + return LAGraph_RpqMatrixKleene_L(plan,msg); + case RPQ_MATRIX_OP_KLEENE_R: + return LAGraph_RPQMatrixKleene_R(plan,msg); default: LG_ASSERT(false, GrB_INVALID_VALUE); } From 8fd265f2b96ab6805ff690940bfbb9e8cfe7bd59 Mon Sep 17 00:00:00 2001 From: Rodion Suvorov Date: Sat, 2 Aug 2025 18:18:08 +0300 Subject: [PATCH 07/38] feat: implement L and R kleene stars --- experimental/algorithm/LAGraph_RPQMatrix.c | 28 ++++++++++++---------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/experimental/algorithm/LAGraph_RPQMatrix.c b/experimental/algorithm/LAGraph_RPQMatrix.c index b1ae479e30..41d04d1ef5 100644 --- a/experimental/algorithm/LAGraph_RPQMatrix.c +++ b/experimental/algorithm/LAGraph_RPQMatrix.c @@ -30,13 +30,13 @@ static GrB_Monoid op; GrB_Info LAGraph_RpqMatrix(RpqMatrixPlan *plan, char *msg); -GrB_Info LAGraph_RPQMatrix_label(GrB_Matrix *mat, GrB_Index x, GrB_Index i, GrB_Index j) { +GrB_Info LAGraph_RPQMatrix_label(GrB_Matrix *mat, GrB_Index x, GrB_Index i, GrB_Index j) +{ GrB_Matrix_new(mat, GrB_BOOL, i, j); GrB_Matrix_setElement(*mat, true, x, x); return (GrB_SUCCESS); } - static GrB_Info LAGraph_RpqMatrixLor(RpqMatrixPlan *plan, char *msg) { LG_ASSERT(plan != NULL, GrB_NULL_POINTER); @@ -171,20 +171,21 @@ static GrB_Info LAGraph_RpqMatrixKleene(RpqMatrixPlan *plan, char *msg) } static GrB_Info LAGraph_RpqMatrixKleene_L(RpqMatrixPlan *plan, char *msg) { -LG_ASSERT(plan != NULL, GrB_NULL_POINTER); + LG_ASSERT(plan != NULL, GrB_NULL_POINTER); LG_ASSERT(plan->op == RPQ_MATRIX_OP_KLEENE, GrB_INVALID_VALUE); LG_ASSERT(plan->res_mat == NULL, GrB_INVALID_VALUE); RpqMatrixPlan *lhs = plan->lhs; RpqMatrixPlan *rhs = plan->rhs; - // Kleene star should have one child. Always right. LG_ASSERT(lhs == NULL, GrB_NULL_POINTER); LG_ASSERT(rhs == NULL, GrB_NULL_POINTER); OK(LAGraph_RPQMatrix(rhs, msg)); + OK(LAGraph_RPQMatrix(lhs, msg)); GrB_Matrix B = rhs->res_mat; + GrB_Matrix A = lhs->res_mat; // Creating identity matrix. GrB_Index n; @@ -207,7 +208,7 @@ LG_ASSERT(plan != NULL, GrB_NULL_POINTER); GrB_LOR, B, E, GrB_DESC_R)); // S <- S x (B + E) GrB_Matrix S, T; - GRB_TRY(GrB_Matrix_dup(&S, E)); + GRB_TRY(GrB_Matrix_dup(&S, A)); bool changed = true; GrB_Index nnz_S = n, nnz_T = 0; @@ -253,11 +254,13 @@ static GrB_Info LAGraph_RpqMatrixKleene_R(RpqMatrixPlan *plan, char *msg) LG_ASSERT(rhs != NULL, GrB_NULL_POINTER); OK(LAGraph_RPQMatrix(rhs, msg)); + OK(LAGraph_RPQMatrix(lhs, msg)); - GrB_Matrix B = rhs->res_mat; + GrB_Matrix B = lhs->res_mat; + GrB_Matrix A = rhs->res_mat - // Creating identity matrix. - GrB_Index n; + // Creating identity matrix. + GrB_Index n; GRB_TRY(GrB_Matrix_nrows(&n, B)); GrB_Matrix E; GRB_TRY(GrB_Matrix_new(&E, GrB_BOOL, n, n)); @@ -277,7 +280,7 @@ static GrB_Info LAGraph_RpqMatrixKleene_R(RpqMatrixPlan *plan, char *msg) GrB_LOR, B, E, GrB_DESC_R)); // S <- S x (B + E) GrB_Matrix S, T; - GRB_TRY(GrB_Matrix_dup(&S, E)); + GRB_TRY(GrB_Matrix_dup(&S, A)); bool changed = true; GrB_Index nnz_S = n, nnz_T = 0; @@ -287,7 +290,7 @@ static GrB_Info LAGraph_RpqMatrixKleene_R(RpqMatrixPlan *plan, char *msg) // T = S * (B + E) GRB_TRY(GrB_Matrix_new(&T, GrB_BOOL, n, n)); GRB_TRY(GrB_mxm(T, GrB_NULL, GrB_NULL, - GrB_LOR_LAND_SEMIRING_BOOL, S, BPE, GrB_DESC_R)); + GrB_LOR_LAND_SEMIRING_BOOL, BPE, S, GrB_DESC_R)); GRB_TRY(GrB_Matrix_nvals(&nnz_T, T)); if (nnz_T != nnz_S) @@ -310,7 +313,6 @@ static GrB_Info LAGraph_RpqMatrixKleene_R(RpqMatrixPlan *plan, char *msg) return (GrB_SUCCESS); } - GrB_Info LAGraph_RPQMatrix(RpqMatrixPlan *plan, char *msg) { if (plan->res_mat != NULL) @@ -331,9 +333,9 @@ GrB_Info LAGraph_RPQMatrix(RpqMatrixPlan *plan, char *msg) case RPQ_MATRIX_OP_KLEENE: return LAGraph_RpqMatrixKleene(plan, msg); case RPQ_MATRIX_OP_KLEENE_L: - return LAGraph_RpqMatrixKleene_L(plan,msg); + return LAGraph_RpqMatrixKleene_L(plan, msg); case RPQ_MATRIX_OP_KLEENE_R: - return LAGraph_RPQMatrixKleene_R(plan,msg); + return LAGraph_RPQMatrixKleene_R(plan, msg); default: LG_ASSERT(false, GrB_INVALID_VALUE); } From 912b1bf371b5cc4f3dff9c7e8dc609277de34e30 Mon Sep 17 00:00:00 2001 From: Rodion Suvorov Date: Sat, 2 Aug 2025 18:21:20 +0300 Subject: [PATCH 08/38] feat: add rpq label into include --- include/LAGraphX.h | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/include/LAGraphX.h b/include/LAGraphX.h index 5d6ec1975f..3defd245e9 100644 --- a/include/LAGraphX.h +++ b/include/LAGraphX.h @@ -167,8 +167,20 @@ GrB_Info LAGraph_RPQMatrix( RpqMatrixPlan *plan, char *msg ); + LAGRAPHX_PUBLIC GrB_Info LAGraph_RpqMatrix_initialize(); + +LAGRAPHX_PUBLIC +GrB_Info LAGraph_RPQMatrix_label +( + GrB_Matrix *mat, + GrB_Index x, + GrB_Index i, + GrB_Index j +) ; + + LAGRAPHX_PUBLIC int LAGraph_SWrite_HeaderStart // write the first part of the JSON header ( From f734ee8157eb5e2f79456a71d9c2497a63779327 Mon Sep 17 00:00:00 2001 From: Rodion Suvorov Date: Sat, 2 Aug 2025 18:43:13 +0300 Subject: [PATCH 09/38] fix: typos --- experimental/algorithm/LAGraph_RPQMatrix.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/experimental/algorithm/LAGraph_RPQMatrix.c b/experimental/algorithm/LAGraph_RPQMatrix.c index 41d04d1ef5..9037abc6f6 100644 --- a/experimental/algorithm/LAGraph_RPQMatrix.c +++ b/experimental/algorithm/LAGraph_RPQMatrix.c @@ -257,7 +257,7 @@ static GrB_Info LAGraph_RpqMatrixKleene_R(RpqMatrixPlan *plan, char *msg) OK(LAGraph_RPQMatrix(lhs, msg)); GrB_Matrix B = lhs->res_mat; - GrB_Matrix A = rhs->res_mat + GrB_Matrix A = rhs->res_mat; // Creating identity matrix. GrB_Index n; @@ -335,7 +335,7 @@ GrB_Info LAGraph_RPQMatrix(RpqMatrixPlan *plan, char *msg) case RPQ_MATRIX_OP_KLEENE_L: return LAGraph_RpqMatrixKleene_L(plan, msg); case RPQ_MATRIX_OP_KLEENE_R: - return LAGraph_RPQMatrixKleene_R(plan, msg); + return LAGraph_RpqMatrixKleene_R(plan, msg); default: LG_ASSERT(false, GrB_INVALID_VALUE); } @@ -345,5 +345,5 @@ GrB_Info LAGraph_RPQMatrix(RpqMatrixPlan *plan, char *msg) GrB_Info LAGraph_RpqMatrix_initialize() { sr = GrB_LOR_LAND_SEMIRING_BOOL; - op = GrB_LOR; + op = GxB_LOR_BOOL_MONOID; } \ No newline at end of file From 59837255dd615876199a379a2b1e0bd93a206b94 Mon Sep 17 00:00:00 2001 From: Rodion Suvorov Date: Sun, 5 Oct 2025 20:56:51 +0300 Subject: [PATCH 10/38] feat: update public interface Solver logic was moved out main public function. Also this patch adds input validation. Signed-off-by: Rodion Suvorov --- experimental/algorithm/LAGraph_RPQMatrix.c | 168 +++++++++++++++------ include/LAGraphX.h | 69 ++++----- 2 files changed, 155 insertions(+), 82 deletions(-) diff --git a/experimental/algorithm/LAGraph_RPQMatrix.c b/experimental/algorithm/LAGraph_RPQMatrix.c index 9037abc6f6..d349b4cdaf 100644 --- a/experimental/algorithm/LAGraph_RPQMatrix.c +++ b/experimental/algorithm/LAGraph_RPQMatrix.c @@ -25,11 +25,50 @@ } \ } +#include "LAGraphX.h" +#include +#include + +GrB_Info LAGraph_RPQMatrix_check(RPQMatrixPlan *plan, GrB_Index *dimension, char *msg) +{ + if (plan == NULL) + { + return GrB_SUCCESS; + } + if (plan->op == RPQ_MATRIX_OP_LABEL) + { + GrB_Index nrows, ncols; + OK(GrB_Matrix_nrows(&nrows, plan->mat)); + OK(GrB_Matrix_ncols(&ncols, plan->mat)); + GrB_Index nvals; + GrB_Matrix_nvals(&nvals, plan->mat); + if (*dimension == -1) + { + *dimension = nrows; + *dimension = ncols; + } + else + { + LG_ASSERT_MSG(nrows != *dimension || ncols != *dimension, GrB_INVALID_VALUE, + "all the matrices in the graph adjacency matrix decomposition " + "should have the same dimensions and be square"); + } + return true; + + return GrB_SUCCESS; + } + GrB_Info lstatus = LAGraph_RPQMatrix_check(plan->lhs, dimension, msg); + GrB_Info rstatus = LAGraph_RPQMatrix_check(plan->rhs, dimension, msg); + if (rstatus || lstatus) + { + return GrB_INVALID_VALUE; + } + return GrB_SUCCESS; +} + static GrB_Semiring sr; static GrB_Monoid op; -GrB_Info LAGraph_RpqMatrix(RpqMatrixPlan *plan, char *msg); - GrB_Info LAGraph_RPQMatrix_label(GrB_Matrix *mat, GrB_Index x, GrB_Index i, GrB_Index j) { GrB_Matrix_new(mat, GrB_BOOL, i, j); @@ -37,20 +76,22 @@ GrB_Info LAGraph_RPQMatrix_label(GrB_Matrix *mat, GrB_Index x, GrB_Index i, GrB_ return (GrB_SUCCESS); } -static GrB_Info LAGraph_RpqMatrixLor(RpqMatrixPlan *plan, char *msg) +GrB_Info LAGraph_RPQMatrix_solver(RPQMatrixPlan *plan, char *msg); + +static GrB_Info LAGraph_RPQMatrixLor(RPQMatrixPlan *plan, char *msg) { LG_ASSERT(plan != NULL, GrB_NULL_POINTER); LG_ASSERT(plan->op == RPQ_MATRIX_OP_LOR, GrB_INVALID_VALUE); LG_ASSERT(plan->res_mat == NULL, GrB_INVALID_VALUE); - RpqMatrixPlan *lhs = plan->lhs; - RpqMatrixPlan *rhs = plan->rhs; + RPQMatrixPlan *lhs = plan->lhs; + RPQMatrixPlan *rhs = plan->rhs; LG_ASSERT(lhs != NULL, GrB_NULL_POINTER); LG_ASSERT(rhs != NULL, GrB_NULL_POINTER); - OK(LAGraph_RPQMatrix(lhs, msg)); - OK(LAGraph_RPQMatrix(rhs, msg)); + OK(LAGraph_RPQMatrix_solver(lhs, msg)); + OK(LAGraph_RPQMatrix_solver(rhs, msg)); GrB_Matrix lhs_mat = lhs->res_mat; GrB_Matrix rhs_mat = rhs->res_mat; @@ -61,27 +102,27 @@ static GrB_Info LAGraph_RpqMatrixLor(RpqMatrixPlan *plan, char *msg) GrB_Matrix res; GrB_Matrix_new(&res, GrB_BOOL, height, width); GRB_TRY(GrB_eWiseAdd(res, GrB_NULL, GrB_NULL, - GrB_LOR, lhs_mat, rhs_mat, GrB_DESC_R)); + op, lhs_mat, rhs_mat, GrB_DESC_R)); plan->res_mat = res; return (GrB_SUCCESS); } -static GrB_Info LAGraph_RpqMatrixConcat(RpqMatrixPlan *plan, char *msg) +static GrB_Info LAGraph_RPQMatrixConcat(RPQMatrixPlan *plan, char *msg) { LG_ASSERT(plan != NULL, GrB_NULL_POINTER); LG_ASSERT(plan->op == RPQ_MATRIX_OP_CONCAT, GrB_INVALID_VALUE); LG_ASSERT(plan->res_mat == NULL, GrB_INVALID_VALUE); - RpqMatrixPlan *lhs = plan->lhs; - RpqMatrixPlan *rhs = plan->rhs; + RPQMatrixPlan *lhs = plan->lhs; + RPQMatrixPlan *rhs = plan->rhs; LG_ASSERT(lhs != NULL, GrB_NULL_POINTER); LG_ASSERT(rhs != NULL, GrB_NULL_POINTER); - OK(LAGraph_RPQMatrix(lhs, msg)); - OK(LAGraph_RPQMatrix(rhs, msg)); + OK(LAGraph_RPQMatrix_solver(lhs, msg)); + OK(LAGraph_RPQMatrix_solver(rhs, msg)); GrB_Matrix lhs_mat = lhs->res_mat; GrB_Matrix rhs_mat = rhs->res_mat; @@ -92,27 +133,27 @@ static GrB_Info LAGraph_RpqMatrixConcat(RpqMatrixPlan *plan, char *msg) GrB_Matrix res; GrB_Matrix_new(&res, GrB_BOOL, height, width); GRB_TRY(GrB_mxm(res, GrB_NULL, GrB_NULL, - GrB_LOR_LAND_SEMIRING_BOOL, lhs_mat, rhs_mat, GrB_DESC_R)); + sr, lhs_mat, rhs_mat, GrB_DESC_R)); // GrB_mxm(plan->res_mat, GrB_NULL, GrB_NULL, GrB_LOR_LAND_SEMIRING_BOOL, lhs_mat, rhs_mat, GrB_NULL); plan->res_mat = res; return (GrB_SUCCESS); } -static GrB_Info LAGraph_RpqMatrixKleene(RpqMatrixPlan *plan, char *msg) +static GrB_Info LAGraph_RPQMatrixKleene(RPQMatrixPlan *plan, char *msg) { LG_ASSERT(plan != NULL, GrB_NULL_POINTER); LG_ASSERT(plan->op == RPQ_MATRIX_OP_KLEENE, GrB_INVALID_VALUE); LG_ASSERT(plan->res_mat == NULL, GrB_INVALID_VALUE); - RpqMatrixPlan *lhs = plan->lhs; - RpqMatrixPlan *rhs = plan->rhs; + RPQMatrixPlan *lhs = plan->lhs; + RPQMatrixPlan *rhs = plan->rhs; // Kleene star should have one child. Always right. LG_ASSERT(lhs == NULL, GrB_NULL_POINTER); LG_ASSERT(rhs != NULL, GrB_NULL_POINTER); - OK(LAGraph_RPQMatrix(rhs, msg)); + OK(LAGraph_RPQMatrix_solver(rhs, msg)); GrB_Matrix B = rhs->res_mat; @@ -134,7 +175,7 @@ static GrB_Info LAGraph_RpqMatrixKleene(RpqMatrixPlan *plan, char *msg) GrB_Matrix BPE; GRB_TRY(GrB_Matrix_new(&BPE, GrB_BOOL, n, n)); GRB_TRY(GrB_eWiseAdd(BPE, GrB_NULL, GrB_NULL, - GrB_LOR, B, E, GrB_DESC_R)); + op, B, E, GrB_DESC_R)); // S <- S x (B + E) GrB_Matrix S, T; GRB_TRY(GrB_Matrix_dup(&S, E)); @@ -147,7 +188,7 @@ static GrB_Info LAGraph_RpqMatrixKleene(RpqMatrixPlan *plan, char *msg) // T = S * (B + E) GRB_TRY(GrB_Matrix_new(&T, GrB_BOOL, n, n)); GRB_TRY(GrB_mxm(T, GrB_NULL, GrB_NULL, - GrB_LOR_LAND_SEMIRING_BOOL, S, BPE, GrB_DESC_R)); + sr, S, BPE, GrB_DESC_R)); GRB_TRY(GrB_Matrix_nvals(&nnz_T, T)); if (nnz_T != nnz_S) @@ -169,20 +210,20 @@ static GrB_Info LAGraph_RpqMatrixKleene(RpqMatrixPlan *plan, char *msg) GRB_TRY(GrB_Matrix_free(&BPE)); return (GrB_SUCCESS); } -static GrB_Info LAGraph_RpqMatrixKleene_L(RpqMatrixPlan *plan, char *msg) +static GrB_Info LAGraph_RPQMatrixKleene_L(RPQMatrixPlan *plan, char *msg) { LG_ASSERT(plan != NULL, GrB_NULL_POINTER); LG_ASSERT(plan->op == RPQ_MATRIX_OP_KLEENE, GrB_INVALID_VALUE); LG_ASSERT(plan->res_mat == NULL, GrB_INVALID_VALUE); - RpqMatrixPlan *lhs = plan->lhs; - RpqMatrixPlan *rhs = plan->rhs; + RPQMatrixPlan *lhs = plan->lhs; + RPQMatrixPlan *rhs = plan->rhs; LG_ASSERT(lhs == NULL, GrB_NULL_POINTER); LG_ASSERT(rhs == NULL, GrB_NULL_POINTER); - OK(LAGraph_RPQMatrix(rhs, msg)); - OK(LAGraph_RPQMatrix(lhs, msg)); + OK(LAGraph_RPQMatrix_solver(rhs, msg)); + OK(LAGraph_RPQMatrix_solver(lhs, msg)); GrB_Matrix B = rhs->res_mat; GrB_Matrix A = lhs->res_mat; @@ -205,7 +246,7 @@ static GrB_Info LAGraph_RpqMatrixKleene_L(RpqMatrixPlan *plan, char *msg) GrB_Matrix BPE; GRB_TRY(GrB_Matrix_new(&BPE, GrB_BOOL, n, n)); GRB_TRY(GrB_eWiseAdd(BPE, GrB_NULL, GrB_NULL, - GrB_LOR, B, E, GrB_DESC_R)); + op, B, E, GrB_DESC_R)); // S <- S x (B + E) GrB_Matrix S, T; GRB_TRY(GrB_Matrix_dup(&S, A)); @@ -218,7 +259,7 @@ static GrB_Info LAGraph_RpqMatrixKleene_L(RpqMatrixPlan *plan, char *msg) // T = S * (B + E) GRB_TRY(GrB_Matrix_new(&T, GrB_BOOL, n, n)); GRB_TRY(GrB_mxm(T, GrB_NULL, GrB_NULL, - GrB_LOR_LAND_SEMIRING_BOOL, S, BPE, GrB_DESC_R)); + sr, S, BPE, GrB_DESC_R)); GRB_TRY(GrB_Matrix_nvals(&nnz_T, T)); if (nnz_T != nnz_S) @@ -241,26 +282,26 @@ static GrB_Info LAGraph_RpqMatrixKleene_L(RpqMatrixPlan *plan, char *msg) return (GrB_SUCCESS); } -static GrB_Info LAGraph_RpqMatrixKleene_R(RpqMatrixPlan *plan, char *msg) +static GrB_Info LAGraph_RPQMatrixKleene_R(RPQMatrixPlan *plan, char *msg) { LG_ASSERT(plan != NULL, GrB_NULL_POINTER); LG_ASSERT(plan->op == RPQ_MATRIX_OP_KLEENE, GrB_INVALID_VALUE); LG_ASSERT(plan->res_mat == NULL, GrB_INVALID_VALUE); - RpqMatrixPlan *lhs = plan->lhs; - RpqMatrixPlan *rhs = plan->rhs; + RPQMatrixPlan *lhs = plan->lhs; + RPQMatrixPlan *rhs = plan->rhs; LG_ASSERT(lhs != NULL, GrB_NULL_POINTER); LG_ASSERT(rhs != NULL, GrB_NULL_POINTER); - OK(LAGraph_RPQMatrix(rhs, msg)); - OK(LAGraph_RPQMatrix(lhs, msg)); + OK(LAGraph_RPQMatrix_solver(rhs, msg)); + OK(LAGraph_RPQMatrix_solver(lhs, msg)); GrB_Matrix B = lhs->res_mat; GrB_Matrix A = rhs->res_mat; - // Creating identity matrix. - GrB_Index n; + // Creating identity matrix. + GrB_Index n; GRB_TRY(GrB_Matrix_nrows(&n, B)); GrB_Matrix E; GRB_TRY(GrB_Matrix_new(&E, GrB_BOOL, n, n)); @@ -290,7 +331,7 @@ static GrB_Info LAGraph_RpqMatrixKleene_R(RpqMatrixPlan *plan, char *msg) // T = S * (B + E) GRB_TRY(GrB_Matrix_new(&T, GrB_BOOL, n, n)); GRB_TRY(GrB_mxm(T, GrB_NULL, GrB_NULL, - GrB_LOR_LAND_SEMIRING_BOOL, BPE, S, GrB_DESC_R)); + sr, BPE, S, GrB_DESC_R)); GRB_TRY(GrB_Matrix_nvals(&nnz_T, T)); if (nnz_T != nnz_S) @@ -313,7 +354,7 @@ static GrB_Info LAGraph_RpqMatrixKleene_R(RpqMatrixPlan *plan, char *msg) return (GrB_SUCCESS); } -GrB_Info LAGraph_RPQMatrix(RpqMatrixPlan *plan, char *msg) +GrB_Info LAGraph_RPQMatrix_solver(RPQMatrixPlan *plan, char *msg) { if (plan->res_mat != NULL) { @@ -323,27 +364,66 @@ GrB_Info LAGraph_RPQMatrix(RpqMatrixPlan *plan, char *msg) switch (plan->op) { case RPQ_MATRIX_OP_LABEL: - LG_ASSERT(plan->lhs == NULL && plan->rhs == NULL, GrB_INVALID_VALUE); + LG_ASSERT_MSG(plan->lhs == NULL && plan->rhs == NULL, + GrB_INVALID_VALUE, "label node should not have any children nodes"); plan->res_mat = plan->mat; return (GrB_SUCCESS); case RPQ_MATRIX_OP_LOR: - return LAGraph_RpqMatrixLor(plan, msg); + return LAGraph_RPQMatrixLor(plan, msg); case RPQ_MATRIX_OP_CONCAT: - return LAGraph_RpqMatrixConcat(plan, msg); + return LAGraph_RPQMatrixConcat(plan, msg); case RPQ_MATRIX_OP_KLEENE: - return LAGraph_RpqMatrixKleene(plan, msg); + return LAGraph_RPQMatrixKleene(plan, msg); case RPQ_MATRIX_OP_KLEENE_L: - return LAGraph_RpqMatrixKleene_L(plan, msg); + return LAGraph_RPQMatrixKleene_L(plan, msg); case RPQ_MATRIX_OP_KLEENE_R: - return LAGraph_RpqMatrixKleene_R(plan, msg); + return LAGraph_RPQMatrixKleene_R(plan, msg); default: - LG_ASSERT(false, GrB_INVALID_VALUE); + LG_ASSERT_MSG(false, GrB_INVALID_VALUE, "invalid graph node type"); } return (GrB_SUCCESS); } -GrB_Info LAGraph_RpqMatrix_initialize() +GrB_Info LAGraph_RPQMatrix_initialize() { sr = GrB_LOR_LAND_SEMIRING_BOOL; op = GxB_LOR_BOOL_MONOID; +} + +GrB_Info LAGrah_RPQMatrix( + // output: + GrB_Index *nnz, // number of nonzero values in + // result reachability matrix + + // input: + RPQMatrixPlan *plan, // root of abstarct syntax tree of + // regular expression + char *msg // LAGraph output message +) +{ + + //-------------------------------------------------------------------------- + // check inputs + //-------------------------------------------------------------------------- + + LG_CLEAR_MSG; + LG_ASSERT_MSG(plan != NULL, GrB_NULL_POINTER, "empty graph"); + GrB_Index dimension = -1; + GrB_Info info = LAGraph_RPQMatrix_check(plan, dimension, msg); + LG_ASSERT_MSG(info == GrB_SUCCESS, info, msg); + + //-------------------------------------------------------------------------- + // initialize + //-------------------------------------------------------------------------- + + LAGraph_RPQMatrix_initialize(); + + //-------------------------------------------------------------------------- + // run solver + //-------------------------------------------------------------------------- + + info = LAGraph_RPQMatrix_solver(plan, msg); + LG_ASSERT_MSG(info = GrB_SUCCESS, info, msg); + GrB_Matrinx_nvals(nnz, plan->res_mat); + return GrB_SUCCESS; } \ No newline at end of file diff --git a/include/LAGraphX.h b/include/LAGraphX.h index 3defd245e9..d22e9d5715 100644 --- a/include/LAGraphX.h +++ b/include/LAGraphX.h @@ -143,44 +143,6 @@ typedef struct } LAGraph_Contents ; -typedef enum RpqMatrixOp -{ - RPQ_MATRIX_OP_LABEL, - RPQ_MATRIX_OP_LOR, - RPQ_MATRIX_OP_CONCAT, - RPQ_MATRIX_OP_KLEENE, - RPQ_MATRIX_OP_KLEENE_L, - RPQ_MATRIX_OP_KLEENE_R, -} RpqMatrixOp; - -typedef struct RpqMatrixPlan -{ - RpqMatrixOp op; - struct RpqMatrixPlan *lhs; - struct RpqMatrixPlan *rhs; - GrB_Matrix mat; - GrB_Matrix res_mat; -} RpqMatrixPlan; - -LAGRAPHX_PUBLIC -GrB_Info LAGraph_RPQMatrix( - RpqMatrixPlan *plan, - char *msg - ); - -LAGRAPHX_PUBLIC -GrB_Info LAGraph_RpqMatrix_initialize(); - -LAGRAPHX_PUBLIC -GrB_Info LAGraph_RPQMatrix_label -( - GrB_Matrix *mat, - GrB_Index x, - GrB_Index i, - GrB_Index j -) ; - - LAGRAPHX_PUBLIC int LAGraph_SWrite_HeaderStart // write the first part of the JSON header ( @@ -883,6 +845,37 @@ int LAGraph_RegularPathQuery // nodes reachable from the starting by the size_t ns, // number of source vertices char *msg // LAGraph output message ); +//**************************************************************************** +typedef enum RPQMatrixOp +{ + RPQ_MATRIX_OP_LABEL, + RPQ_MATRIX_OP_LOR, + RPQ_MATRIX_OP_CONCAT, + RPQ_MATRIX_OP_KLEENE, //reflexive-transitive closure + RPQ_MATRIX_OP_KLEENE_L, + RPQ_MATRIX_OP_KLEENE_R, +} RPQMatrixOp; + +typedef struct RPQMatrixPlan +{ + RPQMatrixOp op; + struct RPQMatrixPlan *lhs; + struct RPQMatrixPlan *rhs; + GrB_Matrix mat; + GrB_Matrix res_mat; +} RPQMatrixPlan; + +GrB_Info LAGrah_RPQMatrix( + // output: + GrB_Index *nnz, // number of nonzero values in + // result reachability matrix + + // input: + RPQMatrixPlan *plan, // root of abstarct syntax tree of + // regular expression + char *msg // LAGraph output message +) ; + //**************************************************************************** LAGRAPHX_PUBLIC int LAGraph_VertexCentrality_Triangle // vertex triangle-centrality From 0d288e61d1e05fa6dce50c70ac42810db5b75b22 Mon Sep 17 00:00:00 2001 From: Rodion Suvorov Date: Sun, 5 Oct 2025 20:58:09 +0300 Subject: [PATCH 11/38] feat: add documentation This patch add documentation with explaining of RPQ-matrix algorithm work. Signed-off-by: Rodion Suvorov --- experimental/algorithm/LAGraph_RPQMatrix.c | 101 ++++++++++++++++++++- include/LAGraphX.h | 81 +++++++++++++++++ 2 files changed, 181 insertions(+), 1 deletion(-) diff --git a/experimental/algorithm/LAGraph_RPQMatrix.c b/experimental/algorithm/LAGraph_RPQMatrix.c index d349b4cdaf..e24917c4bf 100644 --- a/experimental/algorithm/LAGraph_RPQMatrix.c +++ b/experimental/algorithm/LAGraph_RPQMatrix.c @@ -1,6 +1,105 @@ //------------------------------------------------------------------------------ -// LAGraph_RpqMatrix: regular path query algortithm +// LAGraph_RPQMatrix_solver: regular path query algortithm //------------------------------------------------------------------------------ +// +// LAGraph, (c) 2019-2024 by The LAGraph Contributors, All Rights Reserved. +// SPDX-License-Identifier: BSD-2-Clause +// +// Contributed by Rodion Suvorov, Semyon Grigoriev, St. Petersburg State +// University. +// +//------------------------------------------------------------------------------ + +// Code is based on the algorithm described in the following paper: +// * Diego Arroyuelo, Adrián Gómez-Brandón & Gonzalo Navarro "Evaluating +// regular path queries on compressed adjacency matrices" +// * URL: https://link.springer.com/article/10.1007/s00778-024-00885-6 + +//------------------------------------------------------------------------------ +// LAGraph_RPQMatrix_solver: regular path query algortithm +// +// For an edge-labelled directed graph the algorithm computes the nubmer of +// nonzero elements in its reachability matrix. +// The reachability matrix created by following rules: +// * A[i,j] = True if node with index j is reachable from node with index i +// and concatenation of labels over path between these two labels is a word +// from specified regular language. +// * A[i,j] = False in other cases. +// +// The algorithm is based on the idea of ​​considering a regular constraint as +// an abstract syntax tree, the leaves of which are matrices of adjacency matrix +// decomposition of the graph, and the internal nodes are the operations of +// conjunction, concatenation, etc. +// +// Example of adjacency matrix decomposition: +// +// Graph: +// (0) --[a]-> (1) +// | ^ +// [b] [c]--/ +// | --/ +// v / +// (2) --[b]-> (3) +// +// Adjacency matrix decomposition of this graph consists of: +// * Adjacency matrix for the label a: +// 0 1 2 3 +// 0 | | T | | | +// 1 | | | | | +// 2 | | | | | +// 3 | | | | | +// * Adjacency matrix for the label b: +// 0 1 2 3 +// 0 | | | T | | +// 1 | | | | | +// 2 | | | | T | +// 3 | | | | | +// * Adjacency matrix for the label c: +// 0 1 2 3 +// 0 | | | | | +// 1 | | | | | +// 2 | | T | | | +// 3 | | | | | +// +// The algorithm recursively starts from the root of the given tree and +// performs the operations corresponding to each node on the children of that +// node. As a result of the algorithm's execution, the reachability +// matrix will be stored at the root. +// +// +// Example of regular expression and its corresponding AST: +// +// Regular expression: +// a/(b|c)* +// +// Abstract syntax tree: +// ┌─┐ +// │/| (3) +// └┬┘ +// ┌─┬─┴─┬─┐ +// │a│ │*│ (2) +// └─┘ └┬┘ +// ┌┴┐ +// │|│ (1) +// └┬┘ +// ┌─┬─┴─┬─┐ +// │b│ │c│ +// └─┘ └─┘ +// The numbers next to the graph nodes show the order in which operations are +// executed. For the decomposition and AST specified above, the resulting +// matrix will have the following structure (Note, that * represents the +// reflexive-transitive closure): +// +// 0 1 2 3 +// 0 | | T | | | +// 1 | | | | | +// 2 | | | | | +// 3 | | | | | +// +// So for this example LAGraph_RPQMatrix will return 1. +// +// Full description available at: +// https://arxiv.org/pdf/2307.14930 #define LG_FREE_WORK \ { \ diff --git a/include/LAGraphX.h b/include/LAGraphX.h index d22e9d5715..f50fb58e02 100644 --- a/include/LAGraphX.h +++ b/include/LAGraphX.h @@ -865,6 +865,87 @@ typedef struct RPQMatrixPlan GrB_Matrix res_mat; } RPQMatrixPlan; +// LAGraph_RPQMatrix_solver: regular path query algortithm +// +// For an edge-labelled directed graph the algorithm computes the nubmer of +// nonzero elements in its reachability matrix. +// The reachability matrix created by following rules: +// * A[i,j] = True if node with index j is reachable from node with index i +// and concatenation of labels over path between these two labels is a word +// from specified regular language. +// * A[i,j] = False in other cases. +// +// The algorithm is based on the idea of ​​considering a regular constraint as +// an abstract syntax tree, the leaves of which are matrices of adjacency matrix +// decomposition of the graph, and the internal nodes are the operations of +// conjunction, concatenation, etc. +// +// Example of adjacency matrix decomposition: +// +// Graph: +// (0) --[a]-> (1) +// | ^ +// [b] [c]--/ +// | --/ +// v / +// (2) --[b]-> (3) +// +// Adjacency matrix decomposition of this graph consists of: +// * Adjacency matrix for the label a: +// 0 1 2 3 +// 0 | | T | | | +// 1 | | | | | +// 2 | | | | | +// 3 | | | | | +// * Adjacency matrix for the label b: +// 0 1 2 3 +// 0 | | | T | | +// 1 | | | | | +// 2 | | | | T | +// 3 | | | | | +// * Adjacency matrix for the label c: +// 0 1 2 3 +// 0 | | | | | +// 1 | | | | | +// 2 | | T | | | +// 3 | | | | | +// +// The algorithm recursively starts from the root of the given tree and +// performs the operations corresponding to each node on the children of that +// node. As a result of the algorithm's execution, the reachability +// matrix will be stored at the root. +// +// +// Example of regular expression and its corresponding AST: +// +// Regular expression: +// a/(b|c)* +// +// Abstract syntax tree: +// ┌─┐ +// │/| (3) +// └┬┘ +// ┌─┬─┴─┬─┐ +// │a│ │*│ (2) +// └─┘ └┬┘ +// ┌┴┐ +// │|│ (1) +// └┬┘ +// ┌─┬─┴─┬─┐ +// │b│ │c│ +// └─┘ └─┘ +// The numbers next to the graph nodes show the order in which operations are +// executed. For the decomposition and AST specified above, the resulting +// matrix will have the following structure: +// +// 0 1 2 3 +// 0 | | T | | | +// 1 | | | | | +// 2 | | | | | +// 3 | | | | | +// +// So for this example LAGraph_RPQMatrix will return 1. + GrB_Info LAGrah_RPQMatrix( // output: GrB_Index *nnz, // number of nonzero values in From 0bb1e67e1516af50b3112e36fcb9a143b3dba56c Mon Sep 17 00:00:00 2001 From: Rodion Suvorov Date: Sun, 5 Oct 2025 21:11:06 +0300 Subject: [PATCH 12/38] fix: remove copy paste code Remove unused label function and old logic from check function. Signed-off-by: Rodion Suvorov --- experimental/algorithm/LAGraph_RPQMatrix.c | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/experimental/algorithm/LAGraph_RPQMatrix.c b/experimental/algorithm/LAGraph_RPQMatrix.c index e24917c4bf..c09819c1e9 100644 --- a/experimental/algorithm/LAGraph_RPQMatrix.c +++ b/experimental/algorithm/LAGraph_RPQMatrix.c @@ -139,8 +139,6 @@ GrB_Info LAGraph_RPQMatrix_check(RPQMatrixPlan *plan, GrB_Index *dimension, char GrB_Index nrows, ncols; OK(GrB_Matrix_nrows(&nrows, plan->mat)); OK(GrB_Matrix_ncols(&ncols, plan->mat)); - GrB_Index nvals; - GrB_Matrix_nvals(&nvals, plan->mat); if (*dimension == -1) { *dimension = nrows; @@ -152,7 +150,6 @@ GrB_Info LAGraph_RPQMatrix_check(RPQMatrixPlan *plan, GrB_Index *dimension, char "all the matrices in the graph adjacency matrix decomposition " "should have the same dimensions and be square"); } - return true; return GrB_SUCCESS; } @@ -168,13 +165,6 @@ GrB_Info LAGraph_RPQMatrix_check(RPQMatrixPlan *plan, GrB_Index *dimension, char static GrB_Semiring sr; static GrB_Monoid op; -GrB_Info LAGraph_RPQMatrix_label(GrB_Matrix *mat, GrB_Index x, GrB_Index i, GrB_Index j) -{ - GrB_Matrix_new(mat, GrB_BOOL, i, j); - GrB_Matrix_setElement(*mat, true, x, x); - return (GrB_SUCCESS); -} - GrB_Info LAGraph_RPQMatrix_solver(RPQMatrixPlan *plan, char *msg); static GrB_Info LAGraph_RPQMatrixLor(RPQMatrixPlan *plan, char *msg) From 0921d2c8eb0c8e3f689ffcd102969696f559dfab Mon Sep 17 00:00:00 2001 From: Rodion Suvorov Date: Sun, 5 Oct 2025 21:19:48 +0300 Subject: [PATCH 13/38] fix: docs typos Signed-off-by: Rodion Suvorov --- experimental/algorithm/LAGraph_RPQMatrix.c | 5 ++--- include/LAGraphX.h | 3 +-- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/experimental/algorithm/LAGraph_RPQMatrix.c b/experimental/algorithm/LAGraph_RPQMatrix.c index c09819c1e9..24e7fc1743 100644 --- a/experimental/algorithm/LAGraph_RPQMatrix.c +++ b/experimental/algorithm/LAGraph_RPQMatrix.c @@ -1,5 +1,5 @@ //------------------------------------------------------------------------------ -// LAGraph_RPQMatrix_solver: regular path query algortithm +// LAGraph_RPQMatrix: regular path query algortithm //------------------------------------------------------------------------------ // // LAGraph, (c) 2019-2024 by The LAGraph Contributors, All Rights Reserved. @@ -16,7 +16,7 @@ // * URL: https://link.springer.com/article/10.1007/s00778-024-00885-6 //------------------------------------------------------------------------------ -// LAGraph_RPQMatrix_solver: regular path query algortithm +// LAGraph_RPQMatrix: regular path query algortithm // // For an edge-labelled directed graph the algorithm computes the nubmer of // nonzero elements in its reachability matrix. @@ -66,7 +66,6 @@ // node. As a result of the algorithm's execution, the reachability // matrix will be stored at the root. // -// // Example of regular expression and its corresponding AST: // // Regular expression: diff --git a/include/LAGraphX.h b/include/LAGraphX.h index f50fb58e02..e3ac55777f 100644 --- a/include/LAGraphX.h +++ b/include/LAGraphX.h @@ -865,7 +865,7 @@ typedef struct RPQMatrixPlan GrB_Matrix res_mat; } RPQMatrixPlan; -// LAGraph_RPQMatrix_solver: regular path query algortithm +// LAGraph_RPQMatrix: regular path query algortithm // // For an edge-labelled directed graph the algorithm computes the nubmer of // nonzero elements in its reachability matrix. @@ -915,7 +915,6 @@ typedef struct RPQMatrixPlan // node. As a result of the algorithm's execution, the reachability // matrix will be stored at the root. // -// // Example of regular expression and its corresponding AST: // // Regular expression: From 27a2d8a2bfefc6cd2011cff0ba8d3e20aa3f69eb Mon Sep 17 00:00:00 2001 From: Rodion Suvorov Date: Sun, 5 Oct 2025 22:02:16 +0300 Subject: [PATCH 14/38] fix: correct assertion Signed-off-by: Rodion Suvorov --- experimental/algorithm/LAGraph_RPQMatrix.c | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/experimental/algorithm/LAGraph_RPQMatrix.c b/experimental/algorithm/LAGraph_RPQMatrix.c index 24e7fc1743..6d03a806da 100644 --- a/experimental/algorithm/LAGraph_RPQMatrix.c +++ b/experimental/algorithm/LAGraph_RPQMatrix.c @@ -123,7 +123,6 @@ } \ } -#include "LAGraphX.h" #include #include @@ -140,12 +139,14 @@ GrB_Info LAGraph_RPQMatrix_check(RPQMatrixPlan *plan, GrB_Index *dimension, char OK(GrB_Matrix_ncols(&ncols, plan->mat)); if (*dimension == -1) { - *dimension = nrows; + LG_ASSERT_MSG(nrows == ncols, GrB_INVALID_VALUE, + "all the matrices in the graph adjacency matrix decomposition " + "should have the same dimensions and be square"); *dimension = ncols; } else { - LG_ASSERT_MSG(nrows != *dimension || ncols != *dimension, GrB_INVALID_VALUE, + LG_ASSERT_MSG(nrows == *dimension || ncols == *dimension, GrB_INVALID_VALUE, "all the matrices in the graph adjacency matrix decomposition " "should have the same dimensions and be square"); } @@ -298,6 +299,7 @@ static GrB_Info LAGraph_RPQMatrixKleene(RPQMatrixPlan *plan, char *msg) GRB_TRY(GrB_Matrix_free(&BPE)); return (GrB_SUCCESS); } + static GrB_Info LAGraph_RPQMatrixKleene_L(RPQMatrixPlan *plan, char *msg) { LG_ASSERT(plan != NULL, GrB_NULL_POINTER); @@ -330,12 +332,10 @@ static GrB_Info LAGraph_RPQMatrixKleene_L(RPQMatrixPlan *plan, char *msg) GRB_TRY(GrB_Vector_free(&v)); - // B + E GrB_Matrix BPE; GRB_TRY(GrB_Matrix_new(&BPE, GrB_BOOL, n, n)); GRB_TRY(GrB_eWiseAdd(BPE, GrB_NULL, GrB_NULL, op, B, E, GrB_DESC_R)); - // S <- S x (B + E) GrB_Matrix S, T; GRB_TRY(GrB_Matrix_dup(&S, A)); @@ -344,7 +344,6 @@ static GrB_Info LAGraph_RPQMatrixKleene_L(RPQMatrixPlan *plan, char *msg) while (changed) { - // T = S * (B + E) GRB_TRY(GrB_Matrix_new(&T, GrB_BOOL, n, n)); GRB_TRY(GrB_mxm(T, GrB_NULL, GrB_NULL, sr, S, BPE, GrB_DESC_R)); @@ -402,12 +401,10 @@ static GrB_Info LAGraph_RPQMatrixKleene_R(RPQMatrixPlan *plan, char *msg) GRB_TRY(GrB_Vector_free(&v)); - // B + E GrB_Matrix BPE; GRB_TRY(GrB_Matrix_new(&BPE, GrB_BOOL, n, n)); GRB_TRY(GrB_eWiseAdd(BPE, GrB_NULL, GrB_NULL, GrB_LOR, B, E, GrB_DESC_R)); - // S <- S x (B + E) GrB_Matrix S, T; GRB_TRY(GrB_Matrix_dup(&S, A)); @@ -416,7 +413,6 @@ static GrB_Info LAGraph_RPQMatrixKleene_R(RPQMatrixPlan *plan, char *msg) while (changed) { - // T = S * (B + E) GRB_TRY(GrB_Matrix_new(&T, GrB_BOOL, n, n)); GRB_TRY(GrB_mxm(T, GrB_NULL, GrB_NULL, sr, BPE, S, GrB_DESC_R)); @@ -495,9 +491,9 @@ GrB_Info LAGrah_RPQMatrix( //-------------------------------------------------------------------------- LG_CLEAR_MSG; - LG_ASSERT_MSG(plan != NULL, GrB_NULL_POINTER, "empty graph"); + LG_ASSERT(plan == NULL, GrB_NULL_POINTER); GrB_Index dimension = -1; - GrB_Info info = LAGraph_RPQMatrix_check(plan, dimension, msg); + GrB_Info info = LAGraph_RPQMatrix_check(plan, &dimension, msg); LG_ASSERT_MSG(info == GrB_SUCCESS, info, msg); //-------------------------------------------------------------------------- @@ -511,7 +507,7 @@ GrB_Info LAGrah_RPQMatrix( //-------------------------------------------------------------------------- info = LAGraph_RPQMatrix_solver(plan, msg); - LG_ASSERT_MSG(info = GrB_SUCCESS, info, msg); + LG_ASSERT_MSG(info == GrB_SUCCESS, info, msg); GrB_Matrinx_nvals(nnz, plan->res_mat); return GrB_SUCCESS; } \ No newline at end of file From ef81062c0328838a0550cdd1a1177acbbfaf17de Mon Sep 17 00:00:00 2001 From: Rodion Suvorov Date: Sun, 5 Oct 2025 22:43:41 +0300 Subject: [PATCH 15/38] fix: correct L and R kleene stars In previous versions there was a logic mistakes in processing of L and R kleene stars. Now they are correct. Also provide a docs. Signed-off-by: Rodion Suvorov --- experimental/algorithm/LAGraph_RPQMatrix.c | 182 ++++++++++++--------- 1 file changed, 106 insertions(+), 76 deletions(-) diff --git a/experimental/algorithm/LAGraph_RPQMatrix.c b/experimental/algorithm/LAGraph_RPQMatrix.c index 6d03a806da..72124c9811 100644 --- a/experimental/algorithm/LAGraph_RPQMatrix.c +++ b/experimental/algorithm/LAGraph_RPQMatrix.c @@ -300,142 +300,172 @@ static GrB_Info LAGraph_RPQMatrixKleene(RPQMatrixPlan *plan, char *msg) return (GrB_SUCCESS); } +// this function need to handle special case where some optimization +// are available. +// +// consider following AST: +// ┌─┐ +// │/| +// └┬┘ +// ┌─┬─┴─┬─┐ +// │*│ │b│ +// └┬┘ └─┘ +// ┌┴┐ +// │a│ +// └─┘ +// If matrix B is sparse and A is dense, then instead of naive +// way: +// +// (I + A + A x A + ...) x B +// +// we can do: +// +// (B + A x B + A x A x B + ...) +// +// and AST should be rewritten in the following way: +// ┌───┐ +// │L^*│ +// └─┬─┘ +// ┌─┬─┴─┬─┐ +// │a│ │b│ +// └─┘ └─┘ static GrB_Info LAGraph_RPQMatrixKleene_L(RPQMatrixPlan *plan, char *msg) { LG_ASSERT(plan != NULL, GrB_NULL_POINTER); LG_ASSERT(plan->op == RPQ_MATRIX_OP_KLEENE, GrB_INVALID_VALUE); LG_ASSERT(plan->res_mat == NULL, GrB_INVALID_VALUE); - RPQMatrixPlan *lhs = plan->lhs; - RPQMatrixPlan *rhs = plan->rhs; + RPQMatrixPlan *lhs = plan->lhs; // A + RPQMatrixPlan *rhs = plan->rhs; // B - LG_ASSERT(lhs == NULL, GrB_NULL_POINTER); - LG_ASSERT(rhs == NULL, GrB_NULL_POINTER); + LG_ASSERT(lhs != NULL, GrB_NULL_POINTER); + LG_ASSERT(rhs != NULL, GrB_NULL_POINTER); - OK(LAGraph_RPQMatrix_solver(rhs, msg)); OK(LAGraph_RPQMatrix_solver(lhs, msg)); + OK(LAGraph_RPQMatrix_solver(rhs, msg)); - GrB_Matrix B = rhs->res_mat; GrB_Matrix A = lhs->res_mat; + GrB_Matrix B = rhs->res_mat; - // Creating identity matrix. GrB_Index n; - GRB_TRY(GrB_Matrix_nrows(&n, B)); - GrB_Matrix E; - GRB_TRY(GrB_Matrix_new(&E, GrB_BOOL, n, n)); - - GrB_Vector v; - GRB_TRY(GrB_Vector_new(&v, GrB_BOOL, n)); - GRB_TRY(GrB_Vector_assign_BOOL(v, NULL, NULL, true, GrB_ALL, n, NULL)); - - GRB_TRY(GrB_Matrix_diag(&E, v, 0)); + GRB_TRY(GrB_Matrix_nrows(&n, A)); - GRB_TRY(GrB_Vector_free(&v)); - - GrB_Matrix BPE; - GRB_TRY(GrB_Matrix_new(&BPE, GrB_BOOL, n, n)); - GRB_TRY(GrB_eWiseAdd(BPE, GrB_NULL, GrB_NULL, - op, B, E, GrB_DESC_R)); + // S <- B GrB_Matrix S, T; - GRB_TRY(GrB_Matrix_dup(&S, A)); + GRB_TRY(GrB_Matrix_dup(&S, B)); + GRB_TRY(GrB_Matrix_new(&T, GrB_BOOL, n, n)); bool changed = true; - GrB_Index nnz_S = n, nnz_T = 0; + GrB_Index nnz_S = 0, nnz_T = 0; while (changed) { - GRB_TRY(GrB_Matrix_new(&T, GrB_BOOL, n, n)); - GRB_TRY(GrB_mxm(T, GrB_NULL, GrB_NULL, - sr, S, BPE, GrB_DESC_R)); + // T <- A x S + GRB_TRY(GrB_mxm(T, NULL, NULL, sr, A, S, NULL)); - GRB_TRY(GrB_Matrix_nvals(&nnz_T, T)); - if (nnz_T != nnz_S) + // S <- S + T + GRB_TRY(GrB_eWiseAdd(S, NULL, NULL, op, S, T, NULL)); + + GRB_TRY(GrB_Matrix_nvals(&nnz_S, S)); + if (nnz_S == nnz_T) { - changed = true; - nnz_S = nnz_T; - GRB_TRY(GrB_Matrix_free(&S)); - S = T; + changed = false; } else { - changed = false; - GRB_TRY(GrB_Matrix_free(&T)); + changed = true; + nnz_T = nnz_S; + } } - plan->res_mat = S; - GRB_TRY(GrB_Matrix_free(&E)); - GRB_TRY(GrB_Matrix_free(&BPE)); - return (GrB_SUCCESS); + plan->res_mat = S; + GRB_TRY(GrB_Matrix_free(&T)); + return GrB_SUCCESS; } + +// this function need to handle special case where some optimization +// are available. +// consider following AST: +// ┌─┐ +// │/| +// └┬┘ +// ┌─┬─┴─┬─┐ +// │a│ │*│ +// └─┘ └┬┘ +// ┌┴┐ +// │b│ +// └─┘ +// If matrix A is sparse and B is dense, then instead of naive +// way: +// +// A x (I + B + B x B + ...) +// +// we can do: +// +// (A + A x B + A x B x B + ...) +// +// and AST should be rewritten in the following way: +// ┌───┐ +// │R^*│ +// └─┬─┘ +// ┌─┬─┴─┬─┐ +// │a│ │b│ +// └─┘ └─┘ + static GrB_Info LAGraph_RPQMatrixKleene_R(RPQMatrixPlan *plan, char *msg) { LG_ASSERT(plan != NULL, GrB_NULL_POINTER); LG_ASSERT(plan->op == RPQ_MATRIX_OP_KLEENE, GrB_INVALID_VALUE); LG_ASSERT(plan->res_mat == NULL, GrB_INVALID_VALUE); - RPQMatrixPlan *lhs = plan->lhs; - RPQMatrixPlan *rhs = plan->rhs; + RPQMatrixPlan *lhs = plan->lhs; // A + RPQMatrixPlan *rhs = plan->rhs; // B LG_ASSERT(lhs != NULL, GrB_NULL_POINTER); LG_ASSERT(rhs != NULL, GrB_NULL_POINTER); - OK(LAGraph_RPQMatrix_solver(rhs, msg)); OK(LAGraph_RPQMatrix_solver(lhs, msg)); + OK(LAGraph_RPQMatrix_solver(rhs, msg)); - GrB_Matrix B = lhs->res_mat; - GrB_Matrix A = rhs->res_mat; + GrB_Matrix A = lhs->res_mat; + GrB_Matrix B = rhs->res_mat; - // Creating identity matrix. GrB_Index n; - GRB_TRY(GrB_Matrix_nrows(&n, B)); - GrB_Matrix E; - GRB_TRY(GrB_Matrix_new(&E, GrB_BOOL, n, n)); - - GrB_Vector v; - GRB_TRY(GrB_Vector_new(&v, GrB_BOOL, n)); - GRB_TRY(GrB_Vector_assign_BOOL(v, NULL, NULL, true, GrB_ALL, n, NULL)); + GRB_TRY(GrB_Matrix_nrows(&n, A)); - GRB_TRY(GrB_Matrix_diag(&E, v, 0)); - - GRB_TRY(GrB_Vector_free(&v)); - - GrB_Matrix BPE; - GRB_TRY(GrB_Matrix_new(&BPE, GrB_BOOL, n, n)); - GRB_TRY(GrB_eWiseAdd(BPE, GrB_NULL, GrB_NULL, - GrB_LOR, B, E, GrB_DESC_R)); + // S <- A GrB_Matrix S, T; GRB_TRY(GrB_Matrix_dup(&S, A)); + GRB_TRY(GrB_Matrix_new(&T, GrB_BOOL, n, n)); bool changed = true; - GrB_Index nnz_S = n, nnz_T = 0; + GrB_Index nnz_S = 0, nnz_T = 0; while (changed) { - GRB_TRY(GrB_Matrix_new(&T, GrB_BOOL, n, n)); - GRB_TRY(GrB_mxm(T, GrB_NULL, GrB_NULL, - sr, BPE, S, GrB_DESC_R)); + // T <- S × B + GRB_TRY(GrB_mxm(T, NULL, NULL, sr, S, B, NULL)); - GRB_TRY(GrB_Matrix_nvals(&nnz_T, T)); - if (nnz_T != nnz_S) + // S <- S + T + GRB_TRY(GrB_eWiseAdd(S, NULL, NULL, op, S, T, NULL)); + + GRB_TRY(GrB_Matrix_nvals(&nnz_S, S)); + if (nnz_S == nnz_T) { - changed = true; - nnz_S = nnz_T; - GRB_TRY(GrB_Matrix_free(&S)); - S = T; + changed = false; } else { - changed = false; - GRB_TRY(GrB_Matrix_free(&T)); + changed = true; + nnz_T = nnz_S; } } - plan->res_mat = S; - GRB_TRY(GrB_Matrix_free(&E)); - GRB_TRY(GrB_Matrix_free(&BPE)); - return (GrB_SUCCESS); + plan->res_mat = S; + GRB_TRY(GrB_Matrix_free(&T)); + return GrB_SUCCESS; } GrB_Info LAGraph_RPQMatrix_solver(RPQMatrixPlan *plan, char *msg) From 5e7825b9ab652d1c0cb253b2eae2111d82cf35da Mon Sep 17 00:00:00 2001 From: Rodion Suvorov Date: Sun, 5 Oct 2025 23:20:44 +0300 Subject: [PATCH 16/38] fix: kleene rework In this patch all kleene stars was slightly changed - Identity matrix name changes from E to I - All tmp matrices T was demolished - R kleene logic changed from S <- A T <- S x B S <- S + T to S <- A S <- S x (B + I) - L kleene logic changed in the same way Signed-off-by: Rodion Suvorov --- experimental/algorithm/LAGraph_RPQMatrix.c | 138 ++++++++++++--------- 1 file changed, 80 insertions(+), 58 deletions(-) diff --git a/experimental/algorithm/LAGraph_RPQMatrix.c b/experimental/algorithm/LAGraph_RPQMatrix.c index 72124c9811..6b7dc0e94f 100644 --- a/experimental/algorithm/LAGraph_RPQMatrix.c +++ b/experimental/algorithm/LAGraph_RPQMatrix.c @@ -249,54 +249,50 @@ static GrB_Info LAGraph_RPQMatrixKleene(RPQMatrixPlan *plan, char *msg) // Creating identity matrix. GrB_Index n; GRB_TRY(GrB_Matrix_nrows(&n, B)); - GrB_Matrix E; - GRB_TRY(GrB_Matrix_new(&E, GrB_BOOL, n, n)); + GrB_Matrix I; + GRB_TRY(GrB_Matrix_new(&I, GrB_BOOL, n, n)); GrB_Vector v; GRB_TRY(GrB_Vector_new(&v, GrB_BOOL, n)); GRB_TRY(GrB_Vector_assign_BOOL(v, NULL, NULL, true, GrB_ALL, n, NULL)); - GRB_TRY(GrB_Matrix_diag(&E, v, 0)); + GRB_TRY(GrB_Matrix_diag(&I, v, 0)); GRB_TRY(GrB_Vector_free(&v)); - // B + E - GrB_Matrix BPE; - GRB_TRY(GrB_Matrix_new(&BPE, GrB_BOOL, n, n)); - GRB_TRY(GrB_eWiseAdd(BPE, GrB_NULL, GrB_NULL, - op, B, E, GrB_DESC_R)); - // S <- S x (B + E) - GrB_Matrix S, T; - GRB_TRY(GrB_Matrix_dup(&S, E)); + // B + I + GrB_Matrix BPI; + GRB_TRY(GrB_Matrix_new(&BPI, GrB_BOOL, n, n)); + GRB_TRY(GrB_eWiseAdd(BPI, GrB_NULL, GrB_NULL, + op, B, I, GrB_DESC_R)); + // S <- I + GrB_Matrix S; + GRB_TRY(GrB_Matrix_dup(&S, I)); bool changed = true; - GrB_Index nnz_S = n, nnz_T = 0; + GrB_Index nnz_S = n, nnz_Sold = 0; while (changed) { - // T = S * (B + E) - GRB_TRY(GrB_Matrix_new(&T, GrB_BOOL, n, n)); - GRB_TRY(GrB_mxm(T, GrB_NULL, GrB_NULL, - sr, S, BPE, GrB_DESC_R)); + // S <- S x (B + I) + GRB_TRY(GrB_mxm(S, GrB_NULL, GrB_NULL, + sr, S, BPI, GrB_DESC_R)); - GRB_TRY(GrB_Matrix_nvals(&nnz_T, T)); - if (nnz_T != nnz_S) + GRB_TRY(GrB_Matrix_nvals(&nnz_S, S)); + if (nnz_S != nnz_Sold) { changed = true; - nnz_S = nnz_T; - GRB_TRY(GrB_Matrix_free(&S)); - S = T; + nnz_Sold = nnz_S; } else { changed = false; - GRB_TRY(GrB_Matrix_free(&T)); } } plan->res_mat = S; - GRB_TRY(GrB_Matrix_free(&E)); - GRB_TRY(GrB_Matrix_free(&BPE)); + GRB_TRY(GrB_Matrix_free(&I)); + GRB_TRY(GrB_Matrix_free(&BPI)); return (GrB_SUCCESS); } @@ -310,8 +306,8 @@ static GrB_Info LAGraph_RPQMatrixKleene(RPQMatrixPlan *plan, char *msg) // ┌─┬─┴─┬─┐ // │*│ │b│ // └┬┘ └─┘ -// ┌┴┐ -// │a│ +// ┌┴┐ +// │a│ // └─┘ // If matrix B is sparse and A is dense, then instead of naive // way: @@ -328,7 +324,7 @@ static GrB_Info LAGraph_RPQMatrixKleene(RPQMatrixPlan *plan, char *msg) // └─┬─┘ // ┌─┬─┴─┬─┐ // │a│ │b│ -// └─┘ └─┘ +// └─┘ └─┘ static GrB_Info LAGraph_RPQMatrixKleene_L(RPQMatrixPlan *plan, char *msg) { LG_ASSERT(plan != NULL, GrB_NULL_POINTER); @@ -347,44 +343,56 @@ static GrB_Info LAGraph_RPQMatrixKleene_L(RPQMatrixPlan *plan, char *msg) GrB_Matrix A = lhs->res_mat; GrB_Matrix B = rhs->res_mat; + // Creating identity matrix. GrB_Index n; GRB_TRY(GrB_Matrix_nrows(&n, A)); + GrB_Matrix I; + GRB_TRY(GrB_Matrix_new(&I, GrB_BOOL, n, n)); + + GrB_Vector v; + GRB_TRY(GrB_Vector_new(&v, GrB_BOOL, n)); + GRB_TRY(GrB_Vector_assign_BOOL(v, NULL, NULL, true, GrB_ALL, n, NULL)); + + GRB_TRY(GrB_Matrix_diag(&I, v, 0)); + + GRB_TRY(GrB_Vector_free(&v)); + + // B + I + GrB_Matrix API; + GRB_TRY(GrB_Matrix_new(&API, GrB_BOOL, n, n)); + GRB_TRY(GrB_eWiseAdd(API, GrB_NULL, GrB_NULL, + op, A, I, GrB_DESC_R)); // S <- B - GrB_Matrix S, T; + GrB_Matrix S; GRB_TRY(GrB_Matrix_dup(&S, B)); - GRB_TRY(GrB_Matrix_new(&T, GrB_BOOL, n, n)); bool changed = true; - GrB_Index nnz_S = 0, nnz_T = 0; + GrB_Index nnz_S = 0, nnz_Sold = 0; while (changed) { - // T <- A x S - GRB_TRY(GrB_mxm(T, NULL, NULL, sr, A, S, NULL)); - - // S <- S + T - GRB_TRY(GrB_eWiseAdd(S, NULL, NULL, op, S, T, NULL)); + // T <- (A + I) x S + GRB_TRY(GrB_mxm(S, NULL, NULL, sr, API, S, NULL)); GRB_TRY(GrB_Matrix_nvals(&nnz_S, S)); - if (nnz_S == nnz_T) + if (nnz_S != nnz_Sold) { - changed = false; + changed = true; + nnz_Sold = nnz_S; } else { - changed = true; - nnz_T = nnz_S; - + changed = false; } } plan->res_mat = S; - GRB_TRY(GrB_Matrix_free(&T)); + GRB_TRY(GrB_Matrix_free(&I)); + GRB_TRY(GrB_Matrix_free(&API)); return GrB_SUCCESS; } - // this function need to handle special case where some optimization // are available. // consider following AST: @@ -412,7 +420,7 @@ static GrB_Info LAGraph_RPQMatrixKleene_L(RPQMatrixPlan *plan, char *msg) // └─┬─┘ // ┌─┬─┴─┬─┐ // │a│ │b│ -// └─┘ └─┘ +// └─┘ └─┘ static GrB_Info LAGraph_RPQMatrixKleene_R(RPQMatrixPlan *plan, char *msg) { @@ -432,39 +440,53 @@ static GrB_Info LAGraph_RPQMatrixKleene_R(RPQMatrixPlan *plan, char *msg) GrB_Matrix A = lhs->res_mat; GrB_Matrix B = rhs->res_mat; + // Creating identity matrix. GrB_Index n; - GRB_TRY(GrB_Matrix_nrows(&n, A)); + GRB_TRY(GrB_Matrix_nrows(&n, B)); + GrB_Matrix I; + GRB_TRY(GrB_Matrix_new(&I, GrB_BOOL, n, n)); + + GrB_Vector v; + GRB_TRY(GrB_Vector_new(&v, GrB_BOOL, n)); + GRB_TRY(GrB_Vector_assign_BOOL(v, NULL, NULL, true, GrB_ALL, n, NULL)); + + GRB_TRY(GrB_Matrix_diag(&I, v, 0)); + + GRB_TRY(GrB_Vector_free(&v)); + + // B + I + GrB_Matrix BPI; + GRB_TRY(GrB_Matrix_new(&BPI, GrB_BOOL, n, n)); + GRB_TRY(GrB_eWiseAdd(BPI, GrB_NULL, GrB_NULL, + op, B, I, GrB_DESC_R)); // S <- A - GrB_Matrix S, T; + GrB_Matrix S; GRB_TRY(GrB_Matrix_dup(&S, A)); - GRB_TRY(GrB_Matrix_new(&T, GrB_BOOL, n, n)); bool changed = true; - GrB_Index nnz_S = 0, nnz_T = 0; + GrB_Index nnz_S = 0, nnz_Sold = 0; while (changed) { - // T <- S × B - GRB_TRY(GrB_mxm(T, NULL, NULL, sr, S, B, NULL)); - - // S <- S + T - GRB_TRY(GrB_eWiseAdd(S, NULL, NULL, op, S, T, NULL)); + // S <- S x (B + I) + GRB_TRY(GrB_mxm(S, NULL, NULL, sr, S, BPI, NULL)); GRB_TRY(GrB_Matrix_nvals(&nnz_S, S)); - if (nnz_S == nnz_T) + if (nnz_S != nnz_Sold) { - changed = false; + changed = true; + nnz_Sold = nnz_S; } else { - changed = true; - nnz_T = nnz_S; + changed = false; } } plan->res_mat = S; - GRB_TRY(GrB_Matrix_free(&T)); + GRB_TRY(GrB_Matrix_free(&I)); + GRB_TRY(GrB_Matrix_free(&BPI)); return GrB_SUCCESS; } @@ -479,7 +501,7 @@ GrB_Info LAGraph_RPQMatrix_solver(RPQMatrixPlan *plan, char *msg) { case RPQ_MATRIX_OP_LABEL: LG_ASSERT_MSG(plan->lhs == NULL && plan->rhs == NULL, - GrB_INVALID_VALUE, "label node should not have any children nodes"); + GrB_INVALID_VALUE, "label node should not have any children nodes"); plan->res_mat = plan->mat; return (GrB_SUCCESS); case RPQ_MATRIX_OP_LOR: From 89daf4fb274280840197d80606efd71d2c8290d5 Mon Sep 17 00:00:00 2001 From: Rodion Suvorov Date: Mon, 6 Oct 2025 00:18:46 +0300 Subject: [PATCH 17/38] refactor: docs and format Add spaces before ; and add docs for struct in include. Signed-off-by: Rodion Suvorov --- experimental/algorithm/LAGraph_RPQMatrix.c | 386 ++++++++++----------- include/LAGraphX.h | 31 +- 2 files changed, 209 insertions(+), 208 deletions(-) diff --git a/experimental/algorithm/LAGraph_RPQMatrix.c b/experimental/algorithm/LAGraph_RPQMatrix.c index 6b7dc0e94f..4305145518 100644 --- a/experimental/algorithm/LAGraph_RPQMatrix.c +++ b/experimental/algorithm/LAGraph_RPQMatrix.c @@ -113,14 +113,14 @@ #include "LAGraphX.h" #include -#define OK(s) \ - { \ - GrB_Info info = s; \ - if (!(info == GrB_SUCCESS)) \ - { \ - printf("GraphBLAS error: %d\n", info); \ - fprintf(stderr, "GraphBLAS error: %d\n", info); \ - } \ +#define OK(s) \ + { \ + GrB_Info info = s ; \ + if (!(info == GrB_SUCCESS)) \ + { \ + printf("GraphBLAS error: %d\n", info) ; \ + fprintf(stderr, "GraphBLAS error: %d\n", info) ; \ + } \ } #include @@ -130,169 +130,168 @@ GrB_Info LAGraph_RPQMatrix_check(RPQMatrixPlan *plan, GrB_Index *dimension, char { if (plan == NULL) { - return GrB_SUCCESS; + return GrB_SUCCESS ; } if (plan->op == RPQ_MATRIX_OP_LABEL) { - GrB_Index nrows, ncols; - OK(GrB_Matrix_nrows(&nrows, plan->mat)); - OK(GrB_Matrix_ncols(&ncols, plan->mat)); + GrB_Index nrows, ncols ; + OK(GrB_Matrix_nrows(&nrows, plan->mat)) ; + OK(GrB_Matrix_ncols(&ncols, plan->mat)) ; if (*dimension == -1) { LG_ASSERT_MSG(nrows == ncols, GrB_INVALID_VALUE, "all the matrices in the graph adjacency matrix decomposition " - "should have the same dimensions and be square"); - *dimension = ncols; + "should have the same dimensions and be square") ; + *dimension = ncols ; } else { LG_ASSERT_MSG(nrows == *dimension || ncols == *dimension, GrB_INVALID_VALUE, "all the matrices in the graph adjacency matrix decomposition " - "should have the same dimensions and be square"); + "should have the same dimensions and be square") ; } - return GrB_SUCCESS; + return GrB_SUCCESS ; } - GrB_Info lstatus = LAGraph_RPQMatrix_check(plan->lhs, dimension, msg); - GrB_Info rstatus = LAGraph_RPQMatrix_check(plan->rhs, dimension, msg); + GrB_Info lstatus = LAGraph_RPQMatrix_check(plan->lhs, dimension, msg) ; + GrB_Info rstatus = LAGraph_RPQMatrix_check(plan->rhs, dimension, msg) ; if (rstatus || lstatus) { - return GrB_INVALID_VALUE; + return GrB_INVALID_VALUE ; } - return GrB_SUCCESS; + return GrB_SUCCESS ; } -static GrB_Semiring sr; -static GrB_Monoid op; +static GrB_Semiring sr ; +static GrB_Monoid op ; -GrB_Info LAGraph_RPQMatrix_solver(RPQMatrixPlan *plan, char *msg); +GrB_Info LAGraph_RPQMatrix_solver(RPQMatrixPlan *plan, char *msg) ; static GrB_Info LAGraph_RPQMatrixLor(RPQMatrixPlan *plan, char *msg) { - LG_ASSERT(plan != NULL, GrB_NULL_POINTER); - LG_ASSERT(plan->op == RPQ_MATRIX_OP_LOR, GrB_INVALID_VALUE); - LG_ASSERT(plan->res_mat == NULL, GrB_INVALID_VALUE); + LG_ASSERT(plan != NULL, GrB_NULL_POINTER) ; + LG_ASSERT(plan->op == RPQ_MATRIX_OP_LOR, GrB_INVALID_VALUE) ; + LG_ASSERT(plan->res_mat == NULL, GrB_INVALID_VALUE) ; - RPQMatrixPlan *lhs = plan->lhs; - RPQMatrixPlan *rhs = plan->rhs; + RPQMatrixPlan *lhs = plan->lhs ; + RPQMatrixPlan *rhs = plan->rhs ; - LG_ASSERT(lhs != NULL, GrB_NULL_POINTER); - LG_ASSERT(rhs != NULL, GrB_NULL_POINTER); + LG_ASSERT(lhs != NULL, GrB_NULL_POINTER) ; + LG_ASSERT(rhs != NULL, GrB_NULL_POINTER) ; - OK(LAGraph_RPQMatrix_solver(lhs, msg)); - OK(LAGraph_RPQMatrix_solver(rhs, msg)); + OK(LAGraph_RPQMatrix_solver(lhs, msg)) ; + OK(LAGraph_RPQMatrix_solver(rhs, msg)) ; - GrB_Matrix lhs_mat = lhs->res_mat; - GrB_Matrix rhs_mat = rhs->res_mat; + GrB_Matrix lhs_mat = lhs->res_mat ; + GrB_Matrix rhs_mat = rhs->res_mat ; - GrB_Index width, height; - GrB_Matrix_nrows(&height, rhs_mat); - GrB_Matrix_ncols(&width, lhs_mat); - GrB_Matrix res; - GrB_Matrix_new(&res, GrB_BOOL, height, width); + GrB_Index width, height ; + GrB_Matrix_nrows(&height, rhs_mat) ; + GrB_Matrix_ncols(&width, lhs_mat) ; + GrB_Matrix res ; + GrB_Matrix_new(&res, GrB_BOOL, height, width) ; GRB_TRY(GrB_eWiseAdd(res, GrB_NULL, GrB_NULL, - op, lhs_mat, rhs_mat, GrB_DESC_R)); - plan->res_mat = res; + op, lhs_mat, rhs_mat, GrB_DESC_R)) ; + plan->res_mat = res ; - return (GrB_SUCCESS); + return (GrB_SUCCESS) ; } static GrB_Info LAGraph_RPQMatrixConcat(RPQMatrixPlan *plan, char *msg) { - LG_ASSERT(plan != NULL, GrB_NULL_POINTER); - LG_ASSERT(plan->op == RPQ_MATRIX_OP_CONCAT, GrB_INVALID_VALUE); - LG_ASSERT(plan->res_mat == NULL, GrB_INVALID_VALUE); + LG_ASSERT(plan != NULL, GrB_NULL_POINTER) ; + LG_ASSERT(plan->op == RPQ_MATRIX_OP_CONCAT, GrB_INVALID_VALUE) ; + LG_ASSERT(plan->res_mat == NULL, GrB_INVALID_VALUE) ; - RPQMatrixPlan *lhs = plan->lhs; - RPQMatrixPlan *rhs = plan->rhs; + RPQMatrixPlan *lhs = plan->lhs ; + RPQMatrixPlan *rhs = plan->rhs ; - LG_ASSERT(lhs != NULL, GrB_NULL_POINTER); - LG_ASSERT(rhs != NULL, GrB_NULL_POINTER); + LG_ASSERT(lhs != NULL, GrB_NULL_POINTER) ; + LG_ASSERT(rhs != NULL, GrB_NULL_POINTER) ; - OK(LAGraph_RPQMatrix_solver(lhs, msg)); - OK(LAGraph_RPQMatrix_solver(rhs, msg)); + OK(LAGraph_RPQMatrix_solver(lhs, msg)) ; + OK(LAGraph_RPQMatrix_solver(rhs, msg)) ; - GrB_Matrix lhs_mat = lhs->res_mat; - GrB_Matrix rhs_mat = rhs->res_mat; + GrB_Matrix lhs_mat = lhs->res_mat ; + GrB_Matrix rhs_mat = rhs->res_mat ; - GrB_Index width, height; - GrB_Matrix_nrows(&height, rhs_mat); - GrB_Matrix_ncols(&width, lhs_mat); - GrB_Matrix res; - GrB_Matrix_new(&res, GrB_BOOL, height, width); + GrB_Index width, height ; + GrB_Matrix_nrows(&height, rhs_mat) ; + GrB_Matrix_ncols(&width, lhs_mat) ; + GrB_Matrix res ; + GrB_Matrix_new(&res, GrB_BOOL, height, width) ; GRB_TRY(GrB_mxm(res, GrB_NULL, GrB_NULL, - sr, lhs_mat, rhs_mat, GrB_DESC_R)); - // GrB_mxm(plan->res_mat, GrB_NULL, GrB_NULL, GrB_LOR_LAND_SEMIRING_BOOL, lhs_mat, rhs_mat, GrB_NULL); - plan->res_mat = res; + sr, lhs_mat, rhs_mat, GrB_DESC_R)) ; + plan->res_mat = res ; - return (GrB_SUCCESS); + return (GrB_SUCCESS) ; } static GrB_Info LAGraph_RPQMatrixKleene(RPQMatrixPlan *plan, char *msg) { - LG_ASSERT(plan != NULL, GrB_NULL_POINTER); - LG_ASSERT(plan->op == RPQ_MATRIX_OP_KLEENE, GrB_INVALID_VALUE); - LG_ASSERT(plan->res_mat == NULL, GrB_INVALID_VALUE); + LG_ASSERT(plan != NULL, GrB_NULL_POINTER) ; + LG_ASSERT(plan->op == RPQ_MATRIX_OP_KLEENE, GrB_INVALID_VALUE) ; + LG_ASSERT(plan->res_mat == NULL, GrB_INVALID_VALUE) ; - RPQMatrixPlan *lhs = plan->lhs; - RPQMatrixPlan *rhs = plan->rhs; + RPQMatrixPlan *lhs = plan->lhs ; + RPQMatrixPlan *rhs = plan->rhs ; // Kleene star should have one child. Always right. - LG_ASSERT(lhs == NULL, GrB_NULL_POINTER); - LG_ASSERT(rhs != NULL, GrB_NULL_POINTER); + LG_ASSERT(lhs == NULL, GrB_NULL_POINTER) ; + LG_ASSERT(rhs != NULL, GrB_NULL_POINTER) ; - OK(LAGraph_RPQMatrix_solver(rhs, msg)); + OK(LAGraph_RPQMatrix_solver(rhs, msg)) ; - GrB_Matrix B = rhs->res_mat; + GrB_Matrix B = rhs->res_mat ; // Creating identity matrix. - GrB_Index n; - GRB_TRY(GrB_Matrix_nrows(&n, B)); - GrB_Matrix I; - GRB_TRY(GrB_Matrix_new(&I, GrB_BOOL, n, n)); + GrB_Index n ; + GRB_TRY(GrB_Matrix_nrows(&n, B)) ; + GrB_Matrix I ; + GRB_TRY(GrB_Matrix_new(&I, GrB_BOOL, n, n)) ; - GrB_Vector v; - GRB_TRY(GrB_Vector_new(&v, GrB_BOOL, n)); - GRB_TRY(GrB_Vector_assign_BOOL(v, NULL, NULL, true, GrB_ALL, n, NULL)); + GrB_Vector v ; + GRB_TRY(GrB_Vector_new(&v, GrB_BOOL, n)) ; + GRB_TRY(GrB_Vector_assign_BOOL(v, NULL, NULL, true, GrB_ALL, n, NULL)) ; - GRB_TRY(GrB_Matrix_diag(&I, v, 0)); + GRB_TRY(GrB_Matrix_diag(&I, v, 0)) ; - GRB_TRY(GrB_Vector_free(&v)); + GRB_TRY(GrB_Vector_free(&v)) ; // B + I - GrB_Matrix BPI; - GRB_TRY(GrB_Matrix_new(&BPI, GrB_BOOL, n, n)); + GrB_Matrix BPI ; + GRB_TRY(GrB_Matrix_new(&BPI, GrB_BOOL, n, n)) ; GRB_TRY(GrB_eWiseAdd(BPI, GrB_NULL, GrB_NULL, - op, B, I, GrB_DESC_R)); + op, B, I, GrB_DESC_R)) ; // S <- I - GrB_Matrix S; - GRB_TRY(GrB_Matrix_dup(&S, I)); + GrB_Matrix S ; + GRB_TRY(GrB_Matrix_dup(&S, I)) ; - bool changed = true; - GrB_Index nnz_S = n, nnz_Sold = 0; + bool changed = true ; + GrB_Index nnz_S = n, nnz_Sold = 0 ; while (changed) { // S <- S x (B + I) GRB_TRY(GrB_mxm(S, GrB_NULL, GrB_NULL, - sr, S, BPI, GrB_DESC_R)); + sr, S, BPI, GrB_DESC_R)) ; - GRB_TRY(GrB_Matrix_nvals(&nnz_S, S)); + GRB_TRY(GrB_Matrix_nvals(&nnz_S, S)) ; if (nnz_S != nnz_Sold) { - changed = true; - nnz_Sold = nnz_S; + changed = true ; + nnz_Sold = nnz_S ; } else { - changed = false; + changed = false ; } } - plan->res_mat = S; + plan->res_mat = S ; - GRB_TRY(GrB_Matrix_free(&I)); - GRB_TRY(GrB_Matrix_free(&BPI)); + GRB_TRY(GrB_Matrix_free(&I)) ; + GRB_TRY(GrB_Matrix_free(&BPI)) ; return (GrB_SUCCESS); } @@ -327,70 +326,70 @@ static GrB_Info LAGraph_RPQMatrixKleene(RPQMatrixPlan *plan, char *msg) // └─┘ └─┘ static GrB_Info LAGraph_RPQMatrixKleene_L(RPQMatrixPlan *plan, char *msg) { - LG_ASSERT(plan != NULL, GrB_NULL_POINTER); - LG_ASSERT(plan->op == RPQ_MATRIX_OP_KLEENE, GrB_INVALID_VALUE); - LG_ASSERT(plan->res_mat == NULL, GrB_INVALID_VALUE); + LG_ASSERT(plan != NULL, GrB_NULL_POINTER) ; + LG_ASSERT(plan->op == RPQ_MATRIX_OP_KLEENE, GrB_INVALID_VALUE) ; + LG_ASSERT(plan->res_mat == NULL, GrB_INVALID_VALUE) ; - RPQMatrixPlan *lhs = plan->lhs; // A - RPQMatrixPlan *rhs = plan->rhs; // B + RPQMatrixPlan *lhs = plan->lhs ; // A + RPQMatrixPlan *rhs = plan->rhs ; // B - LG_ASSERT(lhs != NULL, GrB_NULL_POINTER); - LG_ASSERT(rhs != NULL, GrB_NULL_POINTER); + LG_ASSERT(lhs != NULL, GrB_NULL_POINTER) ; + LG_ASSERT(rhs != NULL, GrB_NULL_POINTER) ; - OK(LAGraph_RPQMatrix_solver(lhs, msg)); - OK(LAGraph_RPQMatrix_solver(rhs, msg)); + OK(LAGraph_RPQMatrix_solver(lhs, msg)) ; + OK(LAGraph_RPQMatrix_solver(rhs, msg)) ; - GrB_Matrix A = lhs->res_mat; - GrB_Matrix B = rhs->res_mat; + GrB_Matrix A = lhs->res_mat ; + GrB_Matrix B = rhs->res_mat ; // Creating identity matrix. - GrB_Index n; - GRB_TRY(GrB_Matrix_nrows(&n, A)); - GrB_Matrix I; - GRB_TRY(GrB_Matrix_new(&I, GrB_BOOL, n, n)); + GrB_Index n ; + GRB_TRY(GrB_Matrix_nrows(&n, A)) ; + GrB_Matrix I ; + GRB_TRY(GrB_Matrix_new(&I, GrB_BOOL, n, n)) ; - GrB_Vector v; - GRB_TRY(GrB_Vector_new(&v, GrB_BOOL, n)); - GRB_TRY(GrB_Vector_assign_BOOL(v, NULL, NULL, true, GrB_ALL, n, NULL)); + GrB_Vector v ; + GRB_TRY(GrB_Vector_new(&v, GrB_BOOL, n)) ; + GRB_TRY(GrB_Vector_assign_BOOL(v, NULL, NULL, true, GrB_ALL, n, NULL)) ; - GRB_TRY(GrB_Matrix_diag(&I, v, 0)); + GRB_TRY(GrB_Matrix_diag(&I, v, 0)) ; - GRB_TRY(GrB_Vector_free(&v)); + GRB_TRY(GrB_Vector_free(&v)) ; // B + I - GrB_Matrix API; - GRB_TRY(GrB_Matrix_new(&API, GrB_BOOL, n, n)); + GrB_Matrix API ; + GRB_TRY(GrB_Matrix_new(&API, GrB_BOOL, n, n)) ; GRB_TRY(GrB_eWiseAdd(API, GrB_NULL, GrB_NULL, - op, A, I, GrB_DESC_R)); + op, A, I, GrB_DESC_R)) ; // S <- B - GrB_Matrix S; - GRB_TRY(GrB_Matrix_dup(&S, B)); + GrB_Matrix S ; + GRB_TRY(GrB_Matrix_dup(&S, B)) ; - bool changed = true; - GrB_Index nnz_S = 0, nnz_Sold = 0; + bool changed = true ; + GrB_Index nnz_S = 0, nnz_Sold = 0 ; while (changed) { // T <- (A + I) x S - GRB_TRY(GrB_mxm(S, NULL, NULL, sr, API, S, NULL)); + GRB_TRY(GrB_mxm(S, NULL, NULL, sr, API, S, NULL)) ; - GRB_TRY(GrB_Matrix_nvals(&nnz_S, S)); + GRB_TRY(GrB_Matrix_nvals(&nnz_S, S)) ; if (nnz_S != nnz_Sold) { - changed = true; - nnz_Sold = nnz_S; + changed = true ; + nnz_Sold = nnz_S ; } else { - changed = false; + changed = false ; } } - plan->res_mat = S; - GRB_TRY(GrB_Matrix_free(&I)); - GRB_TRY(GrB_Matrix_free(&API)); - return GrB_SUCCESS; + plan->res_mat = S ; + GRB_TRY(GrB_Matrix_free(&I)) ; + GRB_TRY(GrB_Matrix_free(&API)) ; + return GrB_SUCCESS ; } // this function need to handle special case where some optimization @@ -424,106 +423,103 @@ static GrB_Info LAGraph_RPQMatrixKleene_L(RPQMatrixPlan *plan, char *msg) static GrB_Info LAGraph_RPQMatrixKleene_R(RPQMatrixPlan *plan, char *msg) { - LG_ASSERT(plan != NULL, GrB_NULL_POINTER); - LG_ASSERT(plan->op == RPQ_MATRIX_OP_KLEENE, GrB_INVALID_VALUE); - LG_ASSERT(plan->res_mat == NULL, GrB_INVALID_VALUE); + LG_ASSERT(plan != NULL, GrB_NULL_POINTER) ; + LG_ASSERT(plan->op == RPQ_MATRIX_OP_KLEENE, GrB_INVALID_VALUE) ; + LG_ASSERT(plan->res_mat == NULL, GrB_INVALID_VALUE) ; - RPQMatrixPlan *lhs = plan->lhs; // A - RPQMatrixPlan *rhs = plan->rhs; // B + RPQMatrixPlan *lhs = plan->lhs ; // A + RPQMatrixPlan *rhs = plan->rhs ; // B - LG_ASSERT(lhs != NULL, GrB_NULL_POINTER); - LG_ASSERT(rhs != NULL, GrB_NULL_POINTER); + LG_ASSERT(lhs != NULL, GrB_NULL_POINTER) ; + LG_ASSERT(rhs != NULL, GrB_NULL_POINTER) ; - OK(LAGraph_RPQMatrix_solver(lhs, msg)); - OK(LAGraph_RPQMatrix_solver(rhs, msg)); + OK(LAGraph_RPQMatrix_solver(lhs, msg)) ; + OK(LAGraph_RPQMatrix_solver(rhs, msg)) ; - GrB_Matrix A = lhs->res_mat; - GrB_Matrix B = rhs->res_mat; + GrB_Matrix A = lhs->res_mat ; + GrB_Matrix B = rhs->res_mat ; // Creating identity matrix. - GrB_Index n; - GRB_TRY(GrB_Matrix_nrows(&n, B)); - GrB_Matrix I; - GRB_TRY(GrB_Matrix_new(&I, GrB_BOOL, n, n)); + GrB_Index n ; + GRB_TRY(GrB_Matrix_nrows(&n, B)) ; + GrB_Matrix I ; + GRB_TRY(GrB_Matrix_new(&I, GrB_BOOL, n, n)) ; - GrB_Vector v; - GRB_TRY(GrB_Vector_new(&v, GrB_BOOL, n)); - GRB_TRY(GrB_Vector_assign_BOOL(v, NULL, NULL, true, GrB_ALL, n, NULL)); + GrB_Vector v ; + GRB_TRY(GrB_Vector_new(&v, GrB_BOOL, n)) ; + GRB_TRY(GrB_Vector_assign_BOOL(v, NULL, NULL, true, GrB_ALL, n, NULL)) ; - GRB_TRY(GrB_Matrix_diag(&I, v, 0)); + GRB_TRY(GrB_Matrix_diag(&I, v, 0)) ; - GRB_TRY(GrB_Vector_free(&v)); + GRB_TRY(GrB_Vector_free(&v)) ; // B + I - GrB_Matrix BPI; - GRB_TRY(GrB_Matrix_new(&BPI, GrB_BOOL, n, n)); + GrB_Matrix BPI ; + GRB_TRY(GrB_Matrix_new(&BPI, GrB_BOOL, n, n)) ; GRB_TRY(GrB_eWiseAdd(BPI, GrB_NULL, GrB_NULL, - op, B, I, GrB_DESC_R)); + op, B, I, GrB_DESC_R)) ; // S <- A - GrB_Matrix S; - GRB_TRY(GrB_Matrix_dup(&S, A)); + GrB_Matrix S ; + GRB_TRY(GrB_Matrix_dup(&S, A)) ; - bool changed = true; - GrB_Index nnz_S = 0, nnz_Sold = 0; + bool changed = true ; + GrB_Index nnz_S = 0, nnz_Sold = 0 ; while (changed) { // S <- S x (B + I) - GRB_TRY(GrB_mxm(S, NULL, NULL, sr, S, BPI, NULL)); + GRB_TRY(GrB_mxm(S, NULL, NULL, sr, S, BPI, NULL)) ; - GRB_TRY(GrB_Matrix_nvals(&nnz_S, S)); + GRB_TRY(GrB_Matrix_nvals(&nnz_S, S)) ; if (nnz_S != nnz_Sold) { - changed = true; - nnz_Sold = nnz_S; + changed = true ; + nnz_Sold = nnz_S ; } else { - changed = false; + changed = false ; } } - plan->res_mat = S; - GRB_TRY(GrB_Matrix_free(&I)); - GRB_TRY(GrB_Matrix_free(&BPI)); - return GrB_SUCCESS; + plan->res_mat = S ; + GRB_TRY(GrB_Matrix_free(&I)) ; + GRB_TRY(GrB_Matrix_free(&BPI)) ; + return GrB_SUCCESS ; } GrB_Info LAGraph_RPQMatrix_solver(RPQMatrixPlan *plan, char *msg) { - if (plan->res_mat != NULL) - { - return (GrB_SUCCESS); - } + LG_ASSERT(plan->res_mat == NULL, GrB_INVALID_VALUE) ; switch (plan->op) { - case RPQ_MATRIX_OP_LABEL: + case RPQ_MATRIX_OP_LABEL : LG_ASSERT_MSG(plan->lhs == NULL && plan->rhs == NULL, - GrB_INVALID_VALUE, "label node should not have any children nodes"); - plan->res_mat = plan->mat; - return (GrB_SUCCESS); + GrB_INVALID_VALUE, "label node should not have any children nodes") ; + plan->res_mat = plan->mat ; + return (GrB_SUCCESS) ; case RPQ_MATRIX_OP_LOR: - return LAGraph_RPQMatrixLor(plan, msg); + return LAGraph_RPQMatrixLor(plan, msg) ; case RPQ_MATRIX_OP_CONCAT: - return LAGraph_RPQMatrixConcat(plan, msg); + return LAGraph_RPQMatrixConcat(plan, msg) ; case RPQ_MATRIX_OP_KLEENE: - return LAGraph_RPQMatrixKleene(plan, msg); + return LAGraph_RPQMatrixKleene(plan, msg) ; case RPQ_MATRIX_OP_KLEENE_L: - return LAGraph_RPQMatrixKleene_L(plan, msg); + return LAGraph_RPQMatrixKleene_L(plan, msg) ; case RPQ_MATRIX_OP_KLEENE_R: - return LAGraph_RPQMatrixKleene_R(plan, msg); + return LAGraph_RPQMatrixKleene_R(plan, msg) ; default: - LG_ASSERT_MSG(false, GrB_INVALID_VALUE, "invalid graph node type"); + LG_ASSERT_MSG(false, GrB_INVALID_VALUE, "invalid graph node type") ; } - return (GrB_SUCCESS); + return (GrB_SUCCESS) ; } GrB_Info LAGraph_RPQMatrix_initialize() { - sr = GrB_LOR_LAND_SEMIRING_BOOL; - op = GxB_LOR_BOOL_MONOID; + sr = GrB_LOR_LAND_SEMIRING_BOOL ; + op = GxB_LOR_BOOL_MONOID ; } GrB_Info LAGrah_RPQMatrix( @@ -542,24 +538,24 @@ GrB_Info LAGrah_RPQMatrix( // check inputs //-------------------------------------------------------------------------- - LG_CLEAR_MSG; - LG_ASSERT(plan == NULL, GrB_NULL_POINTER); - GrB_Index dimension = -1; - GrB_Info info = LAGraph_RPQMatrix_check(plan, &dimension, msg); - LG_ASSERT_MSG(info == GrB_SUCCESS, info, msg); + LG_CLEAR_MSG ; + LG_ASSERT(plan == NULL, GrB_NULL_POINTER) ; + GrB_Index dimension = -1 ; + GrB_Info info = LAGraph_RPQMatrix_check(plan, &dimension, msg) ; + LG_ASSERT_MSG(info == GrB_SUCCESS, info, msg) ; //-------------------------------------------------------------------------- // initialize //-------------------------------------------------------------------------- - LAGraph_RPQMatrix_initialize(); + LAGraph_RPQMatrix_initialize() ; //-------------------------------------------------------------------------- // run solver //-------------------------------------------------------------------------- - info = LAGraph_RPQMatrix_solver(plan, msg); - LG_ASSERT_MSG(info == GrB_SUCCESS, info, msg); - GrB_Matrinx_nvals(nnz, plan->res_mat); - return GrB_SUCCESS; -} \ No newline at end of file + info = LAGraph_RPQMatrix_solver(plan, msg) ; + LG_ASSERT_MSG(info == GrB_SUCCESS, info, msg) ; + GrB_Matrinx_nvals(nnz, plan->res_mat) ; + return GrB_SUCCESS ; +} diff --git a/include/LAGraphX.h b/include/LAGraphX.h index e3ac55777f..3ed8ea4ea3 100644 --- a/include/LAGraphX.h +++ b/include/LAGraphX.h @@ -848,22 +848,27 @@ int LAGraph_RegularPathQuery // nodes reachable from the starting by the //**************************************************************************** typedef enum RPQMatrixOp { - RPQ_MATRIX_OP_LABEL, - RPQ_MATRIX_OP_LOR, - RPQ_MATRIX_OP_CONCAT, - RPQ_MATRIX_OP_KLEENE, //reflexive-transitive closure - RPQ_MATRIX_OP_KLEENE_L, - RPQ_MATRIX_OP_KLEENE_R, -} RPQMatrixOp; + RPQ_MATRIX_OP_LABEL, // edge label of input graph + RPQ_MATRIX_OP_LOR, // alternation + RPQ_MATRIX_OP_CONCAT, // concatenation + RPQ_MATRIX_OP_KLEENE, // reflexive-transitive closure + RPQ_MATRIX_OP_KLEENE_L, // optimization for (A)*/B case, + // when B is sparse and A is dense + RPQ_MATRIX_OP_KLEENE_R, // optimization for A/(B)* case, + // when A is sparse and B is dense +} RPQMatrixOp ; typedef struct RPQMatrixPlan { - RPQMatrixOp op; - struct RPQMatrixPlan *lhs; - struct RPQMatrixPlan *rhs; - GrB_Matrix mat; - GrB_Matrix res_mat; -} RPQMatrixPlan; + RPQMatrixOp op ; // type of tree node + struct RPQMatrixPlan *lhs ; // left subtree + struct RPQMatrixPlan *rhs ; // right subtree + GrB_Matrix mat ; // adjacency matrix of label. + // Only for leafes. Should be NULL + // in other cases + GrB_Matrix res_mat ; // result of subtree execution. + // Should be NULL +} RPQMatrixPlan ; // LAGraph_RPQMatrix: regular path query algortithm // From 4ba672020299286b4bddfdd02a14466377095baa Mon Sep 17 00:00:00 2001 From: Rodion Suvorov Date: Mon, 6 Oct 2025 03:32:33 +0300 Subject: [PATCH 18/38] fix: typo in function name This patch fixes typo in the name of RPQ-matrix main function. Correct in include and algorithm directories. Signed-off-by: Rodion Suvorov --- experimental/algorithm/LAGraph_RPQMatrix.c | 5 ++- include/LAGraphX.h | 49 +++++++++++----------- 2 files changed, 28 insertions(+), 26 deletions(-) diff --git a/experimental/algorithm/LAGraph_RPQMatrix.c b/experimental/algorithm/LAGraph_RPQMatrix.c index 4305145518..0d2cba0d37 100644 --- a/experimental/algorithm/LAGraph_RPQMatrix.c +++ b/experimental/algorithm/LAGraph_RPQMatrix.c @@ -516,13 +516,14 @@ GrB_Info LAGraph_RPQMatrix_solver(RPQMatrixPlan *plan, char *msg) return (GrB_SUCCESS) ; } -GrB_Info LAGraph_RPQMatrix_initialize() +GrB_Info LAGraph_RPQMatrix_initialize(void) { sr = GrB_LOR_LAND_SEMIRING_BOOL ; op = GxB_LOR_BOOL_MONOID ; + return GrB_SUCCESS; } -GrB_Info LAGrah_RPQMatrix( +GrB_Info LAGraph_RPQMatrix( // output: GrB_Index *nnz, // number of nonzero values in // result reachability matrix diff --git a/include/LAGraphX.h b/include/LAGraphX.h index 3ed8ea4ea3..132f875b11 100644 --- a/include/LAGraphX.h +++ b/include/LAGraphX.h @@ -846,29 +846,6 @@ int LAGraph_RegularPathQuery // nodes reachable from the starting by the char *msg // LAGraph output message ); //**************************************************************************** -typedef enum RPQMatrixOp -{ - RPQ_MATRIX_OP_LABEL, // edge label of input graph - RPQ_MATRIX_OP_LOR, // alternation - RPQ_MATRIX_OP_CONCAT, // concatenation - RPQ_MATRIX_OP_KLEENE, // reflexive-transitive closure - RPQ_MATRIX_OP_KLEENE_L, // optimization for (A)*/B case, - // when B is sparse and A is dense - RPQ_MATRIX_OP_KLEENE_R, // optimization for A/(B)* case, - // when A is sparse and B is dense -} RPQMatrixOp ; - -typedef struct RPQMatrixPlan -{ - RPQMatrixOp op ; // type of tree node - struct RPQMatrixPlan *lhs ; // left subtree - struct RPQMatrixPlan *rhs ; // right subtree - GrB_Matrix mat ; // adjacency matrix of label. - // Only for leafes. Should be NULL - // in other cases - GrB_Matrix res_mat ; // result of subtree execution. - // Should be NULL -} RPQMatrixPlan ; // LAGraph_RPQMatrix: regular path query algortithm // @@ -949,8 +926,32 @@ typedef struct RPQMatrixPlan // 3 | | | | | // // So for this example LAGraph_RPQMatrix will return 1. +typedef enum RPQMatrixOp +{ + RPQ_MATRIX_OP_LABEL, // edge label of input graph + RPQ_MATRIX_OP_LOR, // alternation + RPQ_MATRIX_OP_CONCAT, // concatenation + RPQ_MATRIX_OP_KLEENE, // reflexive-transitive closure + RPQ_MATRIX_OP_KLEENE_L, // optimization for (A)*/B case, + // when B is sparse and A is dense + RPQ_MATRIX_OP_KLEENE_R, // optimization for A/(B)* case, + // when A is sparse and B is dense +} RPQMatrixOp ; -GrB_Info LAGrah_RPQMatrix( +typedef struct RPQMatrixPlan +{ + RPQMatrixOp op ; // type of tree node + struct RPQMatrixPlan *lhs ; // left subtree + struct RPQMatrixPlan *rhs ; // right subtree + GrB_Matrix mat ; // adjacency matrix of label. + // Only for leafes. Should be NULL + // in other cases + GrB_Matrix res_mat ; // result of subtree execution. + // Should be NULL +} RPQMatrixPlan ; + +LAGRAPHX_PUBLIC +GrB_Info LAGraph_RPQMatrix( // output: GrB_Index *nnz, // number of nonzero values in // result reachability matrix From 291b9b27c1ad1c4f0a0a4c2051dfbed404009037 Mon Sep 17 00:00:00 2001 From: Rodion Suvorov Date: Mon, 6 Oct 2025 03:34:25 +0300 Subject: [PATCH 19/38] fix: incorrect assertions This patch fixes incorrect assertions in check and in main functions. Also some refactor Signed-off-by: Rodion Suvorov --- experimental/algorithm/LAGraph_RPQMatrix.c | 46 +++++++++++----------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/experimental/algorithm/LAGraph_RPQMatrix.c b/experimental/algorithm/LAGraph_RPQMatrix.c index 0d2cba0d37..c616150e25 100644 --- a/experimental/algorithm/LAGraph_RPQMatrix.c +++ b/experimental/algorithm/LAGraph_RPQMatrix.c @@ -4,10 +4,10 @@ // // LAGraph, (c) 2019-2024 by The LAGraph Contributors, All Rights Reserved. // SPDX-License-Identifier: BSD-2-Clause -// + // Contributed by Rodion Suvorov, Semyon Grigoriev, St. Petersburg State // University. -// + //------------------------------------------------------------------------------ // Code is based on the algorithm described in the following paper: @@ -106,22 +106,23 @@ #define LG_FREE_ALL \ { \ - LG_FREE_WORK; \ + LG_FREE_WORK ; \ } #include "LG_internal.h" #include "LAGraphX.h" #include -#define OK(s) \ - { \ - GrB_Info info = s ; \ - if (!(info == GrB_SUCCESS)) \ - { \ - printf("GraphBLAS error: %d\n", info) ; \ - fprintf(stderr, "GraphBLAS error: %d\n", info) ; \ - } \ - } +#define OK(s) \ +{ \ + GrB_Info info = (s); \ + if (info != GrB_SUCCESS) \ + { \ + fprintf(stderr, "GraphBLAS error: %d\n", info); \ + return info; \ + } \ +} + #include #include @@ -134,6 +135,7 @@ GrB_Info LAGraph_RPQMatrix_check(RPQMatrixPlan *plan, GrB_Index *dimension, char } if (plan->op == RPQ_MATRIX_OP_LABEL) { + LG_ASSERT(plan->mat != NULL, GrB_NULL_POINTER); GrB_Index nrows, ncols ; OK(GrB_Matrix_nrows(&nrows, plan->mat)) ; OK(GrB_Matrix_ncols(&ncols, plan->mat)) ; @@ -146,7 +148,7 @@ GrB_Info LAGraph_RPQMatrix_check(RPQMatrixPlan *plan, GrB_Index *dimension, char } else { - LG_ASSERT_MSG(nrows == *dimension || ncols == *dimension, GrB_INVALID_VALUE, + LG_ASSERT_MSG(nrows == *dimension && ncols == *dimension, GrB_INVALID_VALUE, "all the matrices in the graph adjacency matrix decomposition " "should have the same dimensions and be square") ; } @@ -185,11 +187,10 @@ static GrB_Info LAGraph_RPQMatrixLor(RPQMatrixPlan *plan, char *msg) GrB_Matrix lhs_mat = lhs->res_mat ; GrB_Matrix rhs_mat = rhs->res_mat ; - GrB_Index width, height ; - GrB_Matrix_nrows(&height, rhs_mat) ; - GrB_Matrix_ncols(&width, lhs_mat) ; + GrB_Index dimension ; + GrB_Matrix_ncols(&dimension, lhs_mat) ; GrB_Matrix res ; - GrB_Matrix_new(&res, GrB_BOOL, height, width) ; + GrB_Matrix_new(&res, GrB_BOOL, dimension, dimension) ; GRB_TRY(GrB_eWiseAdd(res, GrB_NULL, GrB_NULL, op, lhs_mat, rhs_mat, GrB_DESC_R)) ; plan->res_mat = res ; @@ -216,11 +217,10 @@ static GrB_Info LAGraph_RPQMatrixConcat(RPQMatrixPlan *plan, char *msg) GrB_Matrix lhs_mat = lhs->res_mat ; GrB_Matrix rhs_mat = rhs->res_mat ; - GrB_Index width, height ; - GrB_Matrix_nrows(&height, rhs_mat) ; - GrB_Matrix_ncols(&width, lhs_mat) ; + GrB_Index dimension ; + GrB_Matrix_ncols(&dimension, lhs_mat) ; GrB_Matrix res ; - GrB_Matrix_new(&res, GrB_BOOL, height, width) ; + GrB_Matrix_new(&res, GrB_BOOL, dimension, dimension) ; GRB_TRY(GrB_mxm(res, GrB_NULL, GrB_NULL, sr, lhs_mat, rhs_mat, GrB_DESC_R)) ; plan->res_mat = res ; @@ -540,7 +540,7 @@ GrB_Info LAGraph_RPQMatrix( //-------------------------------------------------------------------------- LG_CLEAR_MSG ; - LG_ASSERT(plan == NULL, GrB_NULL_POINTER) ; + LG_ASSERT(plan != NULL, GrB_NULL_POINTER) ; GrB_Index dimension = -1 ; GrB_Info info = LAGraph_RPQMatrix_check(plan, &dimension, msg) ; LG_ASSERT_MSG(info == GrB_SUCCESS, info, msg) ; @@ -557,6 +557,6 @@ GrB_Info LAGraph_RPQMatrix( info = LAGraph_RPQMatrix_solver(plan, msg) ; LG_ASSERT_MSG(info == GrB_SUCCESS, info, msg) ; - GrB_Matrinx_nvals(nnz, plan->res_mat) ; + GrB_Matrix_nvals(nnz, plan->res_mat) ; return GrB_SUCCESS ; } From 16bafb37740c5ab74a6c7319ca46a07b3cdb8fe2 Mon Sep 17 00:00:00 2001 From: Rodion Suvorov Date: Mon, 6 Oct 2025 03:35:28 +0300 Subject: [PATCH 20/38] fix: change kleene logic again In previous commit about kleene logic I start use result matrix S as input and output. I guess this leads to UB. So i come back to tmp matrices. Signed-off-by: Rodion Suvorov --- experimental/algorithm/LAGraph_RPQMatrix.c | 170 +++++++++++---------- 1 file changed, 89 insertions(+), 81 deletions(-) diff --git a/experimental/algorithm/LAGraph_RPQMatrix.c b/experimental/algorithm/LAGraph_RPQMatrix.c index c616150e25..06a7d6d6d3 100644 --- a/experimental/algorithm/LAGraph_RPQMatrix.c +++ b/experimental/algorithm/LAGraph_RPQMatrix.c @@ -234,67 +234,67 @@ static GrB_Info LAGraph_RPQMatrixKleene(RPQMatrixPlan *plan, char *msg) LG_ASSERT(plan->op == RPQ_MATRIX_OP_KLEENE, GrB_INVALID_VALUE) ; LG_ASSERT(plan->res_mat == NULL, GrB_INVALID_VALUE) ; - RPQMatrixPlan *lhs = plan->lhs ; - RPQMatrixPlan *rhs = plan->rhs ; - - // Kleene star should have one child. Always right. - LG_ASSERT(lhs == NULL, GrB_NULL_POINTER) ; + RPQMatrixPlan *rhs = plan->rhs; // B + // KLEENE should have only right child LG_ASSERT(rhs != NULL, GrB_NULL_POINTER) ; + LG_ASSERT(plan->lhs == NULL, GrB_INVALID_VALUE) ; OK(LAGraph_RPQMatrix_solver(rhs, msg)) ; - GrB_Matrix B = rhs->res_mat ; - // Creating identity matrix. GrB_Index n ; GRB_TRY(GrB_Matrix_nrows(&n, B)) ; + + // create identity matrix I GrB_Matrix I ; GRB_TRY(GrB_Matrix_new(&I, GrB_BOOL, n, n)) ; - GrB_Vector v ; GRB_TRY(GrB_Vector_new(&v, GrB_BOOL, n)) ; GRB_TRY(GrB_Vector_assign_BOOL(v, NULL, NULL, true, GrB_ALL, n, NULL)) ; - GRB_TRY(GrB_Matrix_diag(&I, v, 0)) ; - GRB_TRY(GrB_Vector_free(&v)) ; - // B + I + // BPI = B + I GrB_Matrix BPI ; GRB_TRY(GrB_Matrix_new(&BPI, GrB_BOOL, n, n)) ; - GRB_TRY(GrB_eWiseAdd(BPI, GrB_NULL, GrB_NULL, - op, B, I, GrB_DESC_R)) ; + GRB_TRY(GrB_eWiseAdd(BPI, NULL, NULL, op, B, I, NULL)) ; + // S <- I GrB_Matrix S ; GRB_TRY(GrB_Matrix_dup(&S, I)) ; + GrB_Index nnz_S ; + GRB_TRY(GrB_Matrix_nvals(&nnz_S, S)) ; - bool changed = true ; - GrB_Index nnz_S = n, nnz_Sold = 0 ; + // temp T + GrB_Matrix T ; + GRB_TRY(GrB_Matrix_new(&T, GrB_BOOL, n, n)) ; - while (changed) + for (;;) { - // S <- S x (B + I) - GRB_TRY(GrB_mxm(S, GrB_NULL, GrB_NULL, - sr, S, BPI, GrB_DESC_R)) ; - - GRB_TRY(GrB_Matrix_nvals(&nnz_S, S)) ; - if (nnz_S != nnz_Sold) - { - changed = true ; - nnz_Sold = nnz_S ; - } - else - { - changed = false ; - } + // T = S x (B + I) + GRB_TRY(GrB_mxm(T, NULL, NULL, sr, S, BPI, NULL)) ; + + GrB_Index nnz_T ; + GRB_TRY(GrB_Matrix_nvals(&nnz_T, T)) ; + if (nnz_T == nnz_S) break ; + + nnz_S = nnz_T ; + // swap(S, T) + GrB_Matrix tmp = S ; + S = T ; + T = tmp ; + GRB_TRY(GrB_Matrix_clear(T)) ; } + plan->res_mat = S ; + GRB_TRY(GrB_Matrix_free(&T)) ; GRB_TRY(GrB_Matrix_free(&I)) ; GRB_TRY(GrB_Matrix_free(&BPI)) ; - return (GrB_SUCCESS); + return GrB_SUCCESS ; } + // this function need to handle special case where some optimization // are available. // @@ -324,72 +324,76 @@ static GrB_Info LAGraph_RPQMatrixKleene(RPQMatrixPlan *plan, char *msg) // ┌─┬─┴─┬─┐ // │a│ │b│ // └─┘ └─┘ + static GrB_Info LAGraph_RPQMatrixKleene_L(RPQMatrixPlan *plan, char *msg) { LG_ASSERT(plan != NULL, GrB_NULL_POINTER) ; - LG_ASSERT(plan->op == RPQ_MATRIX_OP_KLEENE, GrB_INVALID_VALUE) ; + LG_ASSERT(plan->op == RPQ_MATRIX_OP_KLEENE_L, GrB_INVALID_VALUE) ; LG_ASSERT(plan->res_mat == NULL, GrB_INVALID_VALUE) ; RPQMatrixPlan *lhs = plan->lhs ; // A RPQMatrixPlan *rhs = plan->rhs ; // B - LG_ASSERT(lhs != NULL, GrB_NULL_POINTER) ; LG_ASSERT(rhs != NULL, GrB_NULL_POINTER) ; OK(LAGraph_RPQMatrix_solver(lhs, msg)) ; OK(LAGraph_RPQMatrix_solver(rhs, msg)) ; - GrB_Matrix A = lhs->res_mat ; GrB_Matrix B = rhs->res_mat ; - // Creating identity matrix. GrB_Index n ; - GRB_TRY(GrB_Matrix_nrows(&n, A)) ; + GRB_TRY(GrB_Matrix_nrows(&n, B)) ; + + // creating identity matrix I GrB_Matrix I ; GRB_TRY(GrB_Matrix_new(&I, GrB_BOOL, n, n)) ; - GrB_Vector v ; GRB_TRY(GrB_Vector_new(&v, GrB_BOOL, n)) ; GRB_TRY(GrB_Vector_assign_BOOL(v, NULL, NULL, true, GrB_ALL, n, NULL)) ; - GRB_TRY(GrB_Matrix_diag(&I, v, 0)) ; - GRB_TRY(GrB_Vector_free(&v)) ; - // B + I + // API = A + I GrB_Matrix API ; GRB_TRY(GrB_Matrix_new(&API, GrB_BOOL, n, n)) ; - GRB_TRY(GrB_eWiseAdd(API, GrB_NULL, GrB_NULL, - op, A, I, GrB_DESC_R)) ; + GRB_TRY(GrB_eWiseAdd(API, NULL, NULL, op, A, I, NULL)) ; // S <- B GrB_Matrix S ; GRB_TRY(GrB_Matrix_dup(&S, B)) ; + GrB_Index nnz_S ; + GRB_TRY(GrB_Matrix_nvals(&nnz_S, S)) ; - bool changed = true ; - GrB_Index nnz_S = 0, nnz_Sold = 0 ; + // temp T + GrB_Matrix T ; + GRB_TRY(GrB_Matrix_new(&T, GrB_BOOL, n, n)) ; - while (changed) + for (;;) { - // T <- (A + I) x S - GRB_TRY(GrB_mxm(S, NULL, NULL, sr, API, S, NULL)) ; + // T = S x (A + I) + GRB_TRY(GrB_mxm(T, NULL, NULL, sr, API, S, NULL)) ; - GRB_TRY(GrB_Matrix_nvals(&nnz_S, S)) ; - if (nnz_S != nnz_Sold) - { - changed = true ; - nnz_Sold = nnz_S ; - } - else + GrB_Index nnz_T ; + GRB_TRY(GrB_Matrix_nvals(&nnz_T, T)) ; + if (nnz_T == nnz_S) { - changed = false ; + break ; } + + nnz_S = nnz_T ; + // swap(S, T) + GrB_Matrix tmp = S ; + S = T ; + T = tmp ; + GRB_TRY(GrB_Matrix_clear(T)) ; } plan->res_mat = S ; + + GRB_TRY(GrB_Matrix_free(&T)) ; GRB_TRY(GrB_Matrix_free(&I)) ; GRB_TRY(GrB_Matrix_free(&API)) ; - return GrB_SUCCESS ; + return GrB_SUCCESS; } // this function need to handle special case where some optimization @@ -424,78 +428,82 @@ static GrB_Info LAGraph_RPQMatrixKleene_L(RPQMatrixPlan *plan, char *msg) static GrB_Info LAGraph_RPQMatrixKleene_R(RPQMatrixPlan *plan, char *msg) { LG_ASSERT(plan != NULL, GrB_NULL_POINTER) ; - LG_ASSERT(plan->op == RPQ_MATRIX_OP_KLEENE, GrB_INVALID_VALUE) ; + LG_ASSERT(plan->op == RPQ_MATRIX_OP_KLEENE_R, GrB_INVALID_VALUE) ; LG_ASSERT(plan->res_mat == NULL, GrB_INVALID_VALUE) ; RPQMatrixPlan *lhs = plan->lhs ; // A RPQMatrixPlan *rhs = plan->rhs ; // B - LG_ASSERT(lhs != NULL, GrB_NULL_POINTER) ; LG_ASSERT(rhs != NULL, GrB_NULL_POINTER) ; OK(LAGraph_RPQMatrix_solver(lhs, msg)) ; OK(LAGraph_RPQMatrix_solver(rhs, msg)) ; - GrB_Matrix A = lhs->res_mat ; GrB_Matrix B = rhs->res_mat ; - // Creating identity matrix. GrB_Index n ; GRB_TRY(GrB_Matrix_nrows(&n, B)) ; + + // creating identity matrix I GrB_Matrix I ; GRB_TRY(GrB_Matrix_new(&I, GrB_BOOL, n, n)) ; - GrB_Vector v ; GRB_TRY(GrB_Vector_new(&v, GrB_BOOL, n)) ; GRB_TRY(GrB_Vector_assign_BOOL(v, NULL, NULL, true, GrB_ALL, n, NULL)) ; - GRB_TRY(GrB_Matrix_diag(&I, v, 0)) ; - GRB_TRY(GrB_Vector_free(&v)) ; - // B + I + // BPI = B + I GrB_Matrix BPI ; GRB_TRY(GrB_Matrix_new(&BPI, GrB_BOOL, n, n)) ; - GRB_TRY(GrB_eWiseAdd(BPI, GrB_NULL, GrB_NULL, - op, B, I, GrB_DESC_R)) ; + GRB_TRY(GrB_eWiseAdd(BPI, NULL, NULL, op, B, I, NULL)) ; // S <- A GrB_Matrix S ; GRB_TRY(GrB_Matrix_dup(&S, A)) ; + GrB_Index nnz_S ; + GRB_TRY(GrB_Matrix_nvals(&nnz_S, S)) ; - bool changed = true ; - GrB_Index nnz_S = 0, nnz_Sold = 0 ; + // temp T + GrB_Matrix T ; + GRB_TRY(GrB_Matrix_new(&T, GrB_BOOL, n, n)) ; - while (changed) + for (;;) { - // S <- S x (B + I) - GRB_TRY(GrB_mxm(S, NULL, NULL, sr, S, BPI, NULL)) ; + // T = S x (B + I) + GRB_TRY(GrB_mxm(T, NULL, NULL, sr, S, BPI, NULL)) ; - GRB_TRY(GrB_Matrix_nvals(&nnz_S, S)) ; - if (nnz_S != nnz_Sold) - { - changed = true ; - nnz_Sold = nnz_S ; - } - else + GrB_Index nnz_T ; + GRB_TRY(GrB_Matrix_nvals(&nnz_T, T)) ; + if (nnz_T == nnz_S) { - changed = false ; + break ; } + + nnz_S = nnz_T ; + // swap(S, T) + GrB_Matrix tmp = S ; + S = T ; + T = tmp ; + GRB_TRY(GrB_Matrix_clear(T)) ; } plan->res_mat = S ; + + GRB_TRY(GrB_Matrix_free(&T)) ; GRB_TRY(GrB_Matrix_free(&I)) ; GRB_TRY(GrB_Matrix_free(&BPI)) ; - return GrB_SUCCESS ; + return GrB_SUCCESS; } + GrB_Info LAGraph_RPQMatrix_solver(RPQMatrixPlan *plan, char *msg) { LG_ASSERT(plan->res_mat == NULL, GrB_INVALID_VALUE) ; switch (plan->op) { - case RPQ_MATRIX_OP_LABEL : + case RPQ_MATRIX_OP_LABEL: LG_ASSERT_MSG(plan->lhs == NULL && plan->rhs == NULL, GrB_INVALID_VALUE, "label node should not have any children nodes") ; plan->res_mat = plan->mat ; From e860b978b99c4586ebc5f1acd75aee6432736f14 Mon Sep 17 00:00:00 2001 From: Rodion Suvorov Date: Mon, 6 Oct 2025 03:36:48 +0300 Subject: [PATCH 21/38] feat: provide tests for RPQ-matrix This patch adds tests for valid and invalid input. Signed-off-by: Rodion Suvorov --- experimental/test/test_RPQMatrix.c | 583 ++++++++++++++++++++++------- 1 file changed, 456 insertions(+), 127 deletions(-) diff --git a/experimental/test/test_RPQMatrix.c b/experimental/test/test_RPQMatrix.c index 0aa422629d..71f5d4f923 100644 --- a/experimental/test/test_RPQMatrix.c +++ b/experimental/test/test_RPQMatrix.c @@ -1,138 +1,467 @@ -#include -#include -#include -#include +//------------------------------------------------------------------------------ +// LAGraph/experimental/test/test_RPQMatrix.c: test cases for RPQ-matrix +// reachability algorithm +//------------------------------------------------------------------------------ +// +// LAGraph, (c) 2019-2024 by The LAGraph Contributors, All Rights Reserved. +// SPDX-License-Identifier: BSD-2-Clause + +// Contributed by Rodion Suvorov, Semyon Grigoriev, St. Petersburg State +// University. + +//------------------------------------------------------------------------------ + #include #include +#include +#include +#include +#include +#include +#include -char msg[LAGRAPH_MSG_LEN]; #define LEN 512 +char msg[LAGRAPH_MSG_LEN] ; + +static void load_matrix(GrB_Matrix *M, const char *name) +{ + char filename[LEN + 1] ; + snprintf(filename, LEN, LG_DATA_DIR "%s", name) ; + FILE *f = fopen(filename, "r") ; + TEST_CHECK(f != NULL) ; + OK(LAGraph_MMRead(M, f, msg)) ; + fclose(f) ; +} + +static char *matrix_to_str(GrB_Matrix M) +{ + GrB_Index nnz = 0 ; + OK(GrB_Matrix_nvals(&nnz, M)) ; + + GrB_Index *I = NULL ; + GrB_Index *J = NULL ; + bool *X = NULL ; + + OK(LAGraph_Malloc((void **)&I, nnz, sizeof(GrB_Index), msg)) ; + OK(LAGraph_Malloc((void **)&J, nnz, sizeof(GrB_Index), msg)) ; + OK(LAGraph_Malloc((void **)&X, nnz, sizeof(bool), msg)) ; + + OK(GrB_Matrix_extractTuples_BOOL(I, J, X, &nnz, M)) ; -//**************************************************************************** - -void test_RPQMatrixConc(void) -{ - LAGraph_Init(msg); - LAGraph_RpqMatrix_initialize(); - const char *nameA = "rpq_data/a.mtx"; - const char *nameB = "rpq_data/b.mtx"; - char filenameA [LEN+1] ; - char filenameB [LEN+1] ; - snprintf (filenameA, LEN, LG_DATA_DIR "%s", nameA) ; - snprintf (filenameB, LEN, LG_DATA_DIR "%s", nameB) ; - FILE *fA = fopen(filenameA, "r"); - FILE *fB = fopen(filenameB, "r"); - GrB_Matrix A, B; - OK(LAGraph_MMRead(&A, fA, msg)); - OK(LAGraph_MMRead(&B, fB, msg)); - OK(fclose(fA)); - OK(fclose(fB)); - - GrB_Index nvalsA, nvalsB; - GrB_Matrix_nvals(&nvalsA,A); - GrB_Matrix_nvals(&nvalsB,B); - fprintf(stderr,"\nDEBUG: A:%lu and B:%lu\n",nvalsA,nvalsB); - - RpqMatrixPlan graphA = { - .op = RPQ_MATRIX_OP_LABEL, - .lhs = NULL, - .rhs = NULL, - .mat = A, - .res_mat = NULL - }; - RpqMatrixPlan graphB = { - .op = RPQ_MATRIX_OP_LABEL, - .lhs = NULL, - .rhs = NULL, - .mat = B, - .res_mat = NULL - }; - RpqMatrixPlan graphConcat = { + size_t bufsize = 11 * nnz + 1 ; + char *buf = NULL ; + OK(LAGraph_Malloc((void **)&buf, bufsize, sizeof(char), msg)) ; + buf[0] = '\0' ; + + for (size_t k = 0; k < nnz; k++) + { + char tmp[64] ; + snprintf(tmp, sizeof(tmp), k == 0 ? "(%" PRIu64 ", %" PRIu64 ")" : " (%" PRIu64 ", %" PRIu64 ")", I[k] + 1, J[k] + 1) ; + strcat(buf, tmp) ; + } + + LAGraph_Free((void **)&I, msg) ; + LAGraph_Free((void **)&J, msg) ; + LAGraph_Free((void **)&X, msg) ; + + return buf ; +} + +static void check_result_matrix(GrB_Matrix result, const char *expected) +{ + char *actual = matrix_to_str(result) ; + TEST_CHECK(strcmp(actual, expected) == 0) ; + if (strcmp(actual, expected) != 0) + { + TEST_MSG("Expected: %s\nActual: %s", expected, actual) ; + } + LAGraph_Free((void **)&actual, msg) ; +} + +//======================== +// Tests with valid result +//======================== + +// a/b +void test_RPQMatrix_CONCAT(void) +{ + LAGraph_Init(msg) ; + + GrB_Matrix A, B ; + load_matrix(&A, "rpq_data/a.mtx") ; + load_matrix(&B, "rpq_data/b.mtx") ; + + RPQMatrixPlan planA = {.op = RPQ_MATRIX_OP_LABEL, .mat = A} ; + RPQMatrixPlan planB = {.op = RPQ_MATRIX_OP_LABEL, .mat = B} ; + RPQMatrixPlan concat = { .op = RPQ_MATRIX_OP_CONCAT, - .lhs = &graphA, - .rhs = &graphB, - .mat = NULL, - .res_mat = NULL - }; - RpqMatrixPlan graphKleene = { - .op = RPQ_MATRIX_OP_KLEENE, - .lhs = NULL, - .rhs = &graphConcat, - .mat = NULL, - .res_mat = NULL - }; - GrB_Index expected_nvasl = 14; - GrB_Info res = LAGraph_RPQMatrix(&graphKleene,msg); - GrB_Matrix result_matrix = graphKleene.res_mat; - GrB_Index result; - GrB_Matrix_nvals(&result,result_matrix); - fprintf(stderr,"\nDEBUG: result: %lu",result); - TEST_CHECK(result == expected_nvasl); - LAGraph_Finalize(msg); -} - -void test_RPQMatrixLor(void) -{ - LAGraph_Init(msg); - LAGraph_RpqMatrix_initialize(); - const char *nameA = "rpq_data/a.mtx"; - const char *nameB = "rpq_data/b.mtx"; - char filenameA [LEN+1] ; - char filenameB [LEN+1] ; - snprintf (filenameA, LEN, LG_DATA_DIR "%s", nameA) ; - snprintf (filenameB, LEN, LG_DATA_DIR "%s", nameB) ; - FILE *fA = fopen(filenameA, "r"); - FILE *fB = fopen(filenameB, "r"); - GrB_Matrix A, B; - OK(LAGraph_MMRead(&A, fA, msg)); - OK(LAGraph_MMRead(&B, fB, msg)); - OK(fclose(fA)); - OK(fclose(fB)); - - GrB_Index nvalsA, nvalsB; - GrB_Matrix_nvals(&nvalsA,A); - GrB_Matrix_nvals(&nvalsB,B); - fprintf(stderr,"\nDEBUG: A:%lu and B:%lu\n",nvalsA,nvalsB); - RpqMatrixPlan graphA = { - .op = RPQ_MATRIX_OP_LABEL, - .lhs = NULL, - .rhs = NULL, - .mat = A, - .res_mat = NULL - }; - RpqMatrixPlan graphB = { - .op = RPQ_MATRIX_OP_LABEL, - .lhs = NULL, - .rhs = NULL, - .mat = B, - .res_mat = NULL - }; - RpqMatrixPlan graphLor = { + .lhs = &planA, + .rhs = &planB} ; + GrB_Index result_nnz ; + OK(LAGraph_RPQMatrix(&result_nnz, &concat, msg)) ; + + const char *expected = "(1, 5) (1, 7) (2, 4) (2, 6) (3, 3) (7, 3)" ; + check_result_matrix(concat.res_mat, expected) ; + TEST_CHECK(result_nnz == 6) ; + + LAGraph_Finalize(msg) ; +} + +// a|b +void test_RPQMatrix_LOR(void) +{ + LAGraph_Init(msg) ; + + GrB_Matrix A, B ; + load_matrix(&A, "rpq_data/a.mtx") ; + load_matrix(&B, "rpq_data/b.mtx") ; + + RPQMatrixPlan planA = {.op = RPQ_MATRIX_OP_LABEL, .mat = A} ; + RPQMatrixPlan planB = {.op = RPQ_MATRIX_OP_LABEL, .mat = B} ; + RPQMatrixPlan lor = { .op = RPQ_MATRIX_OP_LOR, - .lhs = &graphA, - .rhs = &graphB, - .mat = NULL, - .res_mat = NULL - }; - RpqMatrixPlan graphKleene = { + .lhs = &planA, + .rhs = &planB} ; + GrB_Index result_nnz ; + OK(LAGraph_RPQMatrix(&result_nnz, &lor, msg)) ; + + const char *expected = "(1, 2) (1, 3) (1, 7) (2, 4) (2, 5) (2, 7) (3, 6) (4, 4) (4, 6) " + "(5, 1) (5, 8) (6, 3) (7, 6)" ; + check_result_matrix(lor.res_mat, expected) ; + TEST_CHECK(result_nnz == 13) ; + + LAGraph_Finalize(msg) ; +} + +// a* +void test_RPQMatrix_KLEENE(void) +{ + LAGraph_Init(msg) ; + + GrB_Matrix A ; + load_matrix(&A, "rpq_data/a.mtx") ; + + RPQMatrixPlan planA = {.op = RPQ_MATRIX_OP_LABEL, .mat = A} ; + RPQMatrixPlan kleene = {.op = RPQ_MATRIX_OP_KLEENE, .rhs = &planA} ; + GrB_Index result_nnz ; + OK(LAGraph_RPQMatrix(&result_nnz, &kleene, msg)) ; + + const char *expected = + "(1, 1) (1, 2) (1, 4) (1, 6) (1, 7) (2, 2) (2, 4) (3, 3) " + "(3, 6) (4, 4) (5, 5) (5, 8) (6, 6) (7, 6) (7, 7) (8, 8)" ; + check_result_matrix(kleene.res_mat, expected) ; + TEST_CHECK(result_nnz == 16) ; + + LAGraph_Finalize(msg) ; +} + +// (a)*/b +void test_RPQMatrix_KLEENE_L(void) +{ + LAGraph_Init(msg) ; + + GrB_Matrix A, B ; + load_matrix(&A, "rpq_data/a.mtx") ; + load_matrix(&B, "rpq_data/b.mtx") ; + + RPQMatrixPlan planA = {.op = RPQ_MATRIX_OP_LABEL, .mat = A} ; + RPQMatrixPlan planB = {.op = RPQ_MATRIX_OP_LABEL, .mat = B} ; + RPQMatrixPlan kleene = { + .op = RPQ_MATRIX_OP_KLEENE, + .rhs = &planA} ; + RPQMatrixPlan concat = { + .op = RPQ_MATRIX_OP_CONCAT, + .lhs = &kleene, + .rhs = &planB} ; + + GrB_Index result_nnz ; + OK(LAGraph_RPQMatrix(&result_nnz, &concat, msg)) ; + const char *expected = "(1, 3) (1, 4) (1, 5) (1, 6) (1, 7) " + "(2, 4) (2, 5) (2, 6) (2, 7) (3, 3) " + "(4, 4) (4, 6) (5, 1) (6, 3) (7, 3)" ; + check_result_matrix(concat.res_mat, expected) ; + TEST_CHECK(result_nnz == 15) ; + GrB_Info expected_nnz = result_nnz ; + RPQMatrixPlan planA2 = {.op = RPQ_MATRIX_OP_LABEL, .mat = A} ; + RPQMatrixPlan planB2 = {.op = RPQ_MATRIX_OP_LABEL, .mat = B} ; + RPQMatrixPlan kleeneL = { + .op = RPQ_MATRIX_OP_KLEENE_L, + .lhs = &planA2, + .rhs = &planB2} ; + + OK(LAGraph_RPQMatrix(&result_nnz, &kleeneL, msg)) ; + + expected = matrix_to_str(concat.res_mat) ; + + check_result_matrix(kleeneL.res_mat, expected) ; + TEST_CHECK(result_nnz == expected_nnz) ; + + LAGraph_Finalize(msg) ; +} + +// b/(a)* +void test_RPQMatrix_KLEENE_R(void) +{ + LAGraph_Init(msg) ; + + GrB_Matrix A, B ; + load_matrix(&A, "rpq_data/a.mtx") ; + load_matrix(&B, "rpq_data/b.mtx") ; + + RPQMatrixPlan planA = {.op = RPQ_MATRIX_OP_LABEL, .mat = A} ; + RPQMatrixPlan planB = {.op = RPQ_MATRIX_OP_LABEL, .mat = B} ; + RPQMatrixPlan kleene = { .op = RPQ_MATRIX_OP_KLEENE, - .lhs = NULL, - .rhs = &graphLor, - .mat = NULL, - .res_mat = NULL - }; - GrB_Index expected_nvasl = 35; - GrB_Info res = LAGraph_RPQMatrix(&graphKleene,msg); - GrB_Matrix result_matrix = graphKleene.res_mat; - GrB_Index result; - GrB_Matrix_nvals(&result,result_matrix); - fprintf(stderr,"\nDEBUG: result: %lu",result); - TEST_CHECK(result == expected_nvasl); - LAGraph_Finalize(msg); + .rhs = &planB} ; + RPQMatrixPlan concat = { + .op = RPQ_MATRIX_OP_CONCAT, + .lhs = &planA, + .rhs = &kleene} ; + + GrB_Index result_nnz; + OK(LAGraph_RPQMatrix(&result_nnz, &concat, msg)) ; + const char *expected = "(1, 1) (1, 2) (1, 3) (1, 5) (1, 7) " + "(2, 3) (2, 4) (2, 6) (3, 3) (3, 6) " + "(5, 8) (7, 3) (7, 6)" ; + check_result_matrix(concat.res_mat, expected) ; + TEST_CHECK(result_nnz == 13) ; + GrB_Info expected_nnz = result_nnz ; + RPQMatrixPlan planA2 = {.op = RPQ_MATRIX_OP_LABEL, .mat = A} ; + RPQMatrixPlan planB2 = {.op = RPQ_MATRIX_OP_LABEL, .mat = B} ; + RPQMatrixPlan kleeneR = { + .op = RPQ_MATRIX_OP_KLEENE_R, + .lhs = &planA2, + .rhs = &planB2} ; + + OK(LAGraph_RPQMatrix(&result_nnz, &kleeneR, msg)) ; + + expected = matrix_to_str(concat.res_mat) ; + check_result_matrix(kleeneR.res_mat, expected) ; + TEST_CHECK(result_nnz == expected_nnz) ; + + LAGraph_Finalize(msg) ; } +// c/(a|b)* +void test_RPQMatrix_Complex(void) +{ + LAGraph_Init(msg) ; + + GrB_Matrix A, B, C ; + load_matrix(&A, "rpq_data/a.mtx") ; + load_matrix(&B, "rpq_data/b.mtx") ; + load_matrix(&C, "rpq_data/c.mtx") ; + + RPQMatrixPlan planA = {.op = RPQ_MATRIX_OP_LABEL, .mat = A} ; + RPQMatrixPlan planB = {.op = RPQ_MATRIX_OP_LABEL, .mat = B} ; + RPQMatrixPlan planC = {.op = RPQ_MATRIX_OP_LABEL, .mat = C} ; + RPQMatrixPlan lor = {.op = RPQ_MATRIX_OP_LOR, .lhs = &planA, .rhs = &planB} ; + RPQMatrixPlan kleene = { + .op = RPQ_MATRIX_OP_KLEENE, + .rhs = &lor} ; + + RPQMatrixPlan concat = {.op = RPQ_MATRIX_OP_CONCAT, .lhs = &planC, .rhs = &kleene} ; + GrB_Index result_nnz ; + OK(LAGraph_RPQMatrix(&result_nnz, &concat, msg)) ; + + const char *expected = "(1, 1) (1, 2) (1, 3) (1, 4) (1, 5) (1, 6) (1, 7) (1, 8) " + "(2, 3) (2, 6) (2, 8) " + "(3, 1) (3, 2) (3, 3) (3, 4) (3, 5) (3, 6) (3, 7) (3, 8) " + "(4, 1) (4, 2) (4, 3) (4, 4) (4, 5) (4, 6) (4, 7) (4, 8) " + "(5, 1) (5, 2) (5, 3) (5, 4) (5, 5) (5, 6) (5, 7) (5, 8) " + "(6, 3) (6, 4) (6, 6) " + "(7, 1) (7, 2) (7, 3) (7, 4) (7, 5) (7, 6) (7, 7) (7, 8) " + "(8, 3) (8, 6)" ; + check_result_matrix(concat.res_mat, expected) ; + TEST_CHECK(result_nnz == 48) ; + LAGraph_Finalize(msg) ; +} + +//========================== +// Tests with invalid result +//========================== + +void test_RPQMatrix_Incorrect_size(void) +{ + LAGraph_Init(msg) ; + + GrB_Matrix M ; + OK(GrB_Matrix_new(&M, GrB_BOOL, 3, 4)) ; + + RPQMatrixPlan plan = {.op = RPQ_MATRIX_OP_LABEL, .mat = M} ; + GrB_Index result_nnz ; + + GrB_Info info = LAGraph_RPQMatrix(&result_nnz, &plan, msg) ; + TEST_CHECK(info == GrB_INVALID_VALUE) ; + TEST_MSG("Expected GrB_INVALID_VALUE for non-square matrix") ; + + GrB_Matrix_free(&M) ; + LAGraph_Finalize(msg) ; +} + +void test_RPQMatrix_Unequal_size(void) +{ + LAGraph_Init(msg) ; + + GrB_Matrix A, B ; + OK(GrB_Matrix_new(&A, GrB_BOOL, 3, 3)) ; + OK(GrB_Matrix_new(&B, GrB_BOOL, 4, 4)) ; + + RPQMatrixPlan planA = {.op = RPQ_MATRIX_OP_LABEL, .mat = A} ; + RPQMatrixPlan planB = {.op = RPQ_MATRIX_OP_LABEL, .mat = B} ; + RPQMatrixPlan concat = {.op = RPQ_MATRIX_OP_CONCAT, .lhs = &planA, .rhs = &planB} ; + + GrB_Index result_nnz ; + GrB_Info info = LAGraph_RPQMatrix(&result_nnz, &concat, msg) ; + + TEST_CHECK(info == GrB_INVALID_VALUE) ; + TEST_MSG("Expected GrB_INVALID_VALUE for unequal matrix sizes") ; + + GrB_Matrix_free(&A) ; + GrB_Matrix_free(&B) ; + LAGraph_Finalize(msg) ; +} + +void test_RPQMatrix_Null_Child_concat(void) +{ + LAGraph_Init(msg) ; + + RPQMatrixPlan planA = {.op = RPQ_MATRIX_OP_LABEL} ; + RPQMatrixPlan concat = {.op = RPQ_MATRIX_OP_CONCAT, .lhs = &planA, .rhs = NULL} ; + GrB_Index result_nnz ; + + GrB_Info info = LAGraph_RPQMatrix(&result_nnz, &concat, msg) ; + TEST_CHECK(info == GrB_NULL_POINTER || info == GrB_INVALID_VALUE) ; + TEST_MSG("retval = %d (%s)", info, msg) ; + + LAGraph_Finalize(msg) ; +} + +void test_RPQMatrix_Null_Child_lor(void) +{ + LAGraph_Init(msg) ; + + RPQMatrixPlan planA = {.op = RPQ_MATRIX_OP_LABEL} ; + RPQMatrixPlan lor = {.op = RPQ_MATRIX_OP_LOR, .lhs = &planA, .rhs = NULL} ; + GrB_Index result_nnz ; + + GrB_Info info = LAGraph_RPQMatrix(&result_nnz, &lor, msg) ; + TEST_CHECK(info == GrB_NULL_POINTER || info == GrB_INVALID_VALUE) ; + TEST_MSG("retval = %d (%s)", info, msg) ; + + LAGraph_Finalize(msg) ; +} + +void test_RPQMatrix_Null_Child_L_Kleene(void) +{ + LAGraph_Init(msg) ; + + RPQMatrixPlan planA = {.op = RPQ_MATRIX_OP_LABEL} ; + RPQMatrixPlan kleeneL = {.op = RPQ_MATRIX_OP_KLEENE_L, .lhs = &planA, .rhs = NULL} ; + GrB_Index result_nnz ; + + GrB_Info info = LAGraph_RPQMatrix(&result_nnz, &kleeneL, msg) ; + TEST_CHECK(info == GrB_NULL_POINTER || info == GrB_INVALID_VALUE) ; + TEST_MSG("retval = %d (%s)", info, msg) ; + + LAGraph_Finalize(msg) ; +} + +void test_RPQMatrix_Null_Child_R_Kleene(void) +{ + LAGraph_Init(msg) ; + + RPQMatrixPlan planA = {.op = RPQ_MATRIX_OP_LABEL} ; + RPQMatrixPlan kleeneR = {.op = RPQ_MATRIX_OP_KLEENE_R, .lhs = &planA, .rhs = NULL} ; + GrB_Index result_nnz ; + + GrB_Info info = LAGraph_RPQMatrix(&result_nnz, &kleeneR, msg) ; + TEST_CHECK(info == GrB_NULL_POINTER || info == GrB_INVALID_VALUE) ; + TEST_MSG("retval = %d (%s)", info, msg) ; + + LAGraph_Finalize(msg) ; +} + +void test_RPQMatrix_Non_Null_Children_Kleene(void) +{ + LAGraph_Init(msg) ; + + GrB_Matrix A ; + OK(GrB_Matrix_new(&A, GrB_BOOL, 3, 3)) ; + RPQMatrixPlan planA = {.op = RPQ_MATRIX_OP_LABEL, .mat = A} ; + + RPQMatrixPlan kleene = {.op = RPQ_MATRIX_OP_KLEENE, .lhs = &planA, .rhs = &planA} ; + GrB_Index result_nnz ; + + GrB_Info info = LAGraph_RPQMatrix(&result_nnz, &kleene, msg) ; + TEST_CHECK(info == GrB_INVALID_VALUE) ; + TEST_MSG("retval = %d (%s)", info, msg) ; + + GrB_Matrix_free(&A) ; + LAGraph_Finalize(msg) ; +} + +void test_RPQMatrix_Left_Child_Kleene(void) +{ + LAGraph_Init(msg) ; + + GrB_Matrix A ; + OK(GrB_Matrix_new(&A, GrB_BOOL, 3, 3)) ; + RPQMatrixPlan planA = {.op = RPQ_MATRIX_OP_LABEL, .mat = A} ; + + RPQMatrixPlan kleene = {.op = RPQ_MATRIX_OP_KLEENE, .lhs = &planA, .rhs = NULL} ; + GrB_Index result_nnz ; + + GrB_Info info = LAGraph_RPQMatrix(&result_nnz, &kleene, msg) ; + TEST_CHECK(info == GrB_NULL_POINTER) ; + TEST_MSG("Expected GrB_NULL_POINTER for KLEENE with only left child") ; + + GrB_Matrix_free(&A) ; + LAGraph_Finalize(msg) ; +} + +void test_RPQMatrix_Invalid_Op_type(void) +{ + LAGraph_Init(msg) ; + + RPQMatrixPlan plan = {.op = (RPQMatrixOp)52} ; + GrB_Index result_nnz ; + + GrB_Info info = LAGraph_RPQMatrix(&result_nnz, &plan, msg) ; + TEST_CHECK(info == GrB_INVALID_VALUE) ; + + LAGraph_Finalize(msg) ; +} + +void test_RPQMatrix_Null_root(void) +{ + LAGraph_Init(msg) ; + + GrB_Index result_nnz ; + GrB_Info info = LAGraph_RPQMatrix(&result_nnz, NULL, msg) ; + + TEST_CHECK(info == GrB_NULL_POINTER) ; + TEST_MSG("Expected GrB_NULL_POINTER for NULL plan root") ; + + LAGraph_Finalize(msg) ; +} + + TEST_LIST = { - // {"RPQMatrixKleene", test_RPQMatrixKleene}, - {"RPQMatrixConc", test_RPQMatrixConc}, - {"RPQMatrixLor", test_RPQMatrixLor}, - {NULL, NULL}}; \ No newline at end of file + {"RPQMatrix_CONCAT", test_RPQMatrix_CONCAT}, + {"RPQMatrix_LOR", test_RPQMatrix_LOR}, + {"RPQMatrix_KLEENE", test_RPQMatrix_KLEENE}, + {"RPQMatrix_KLEENE_L", test_RPQMatrix_KLEENE_L}, + {"RPQMatrix_KLEENE_R", test_RPQMatrix_KLEENE_R}, + {"RPQMatrix_Complex", test_RPQMatrix_Complex}, + {"RPQMatrix_Incorrect_size", test_RPQMatrix_Incorrect_size}, + {"RPQMatrix_Unequal_size", test_RPQMatrix_Unequal_size}, + {"RPQMatrix_Null_Child_concat", test_RPQMatrix_Null_Child_concat}, + {"RPQMatrix_Null_Child_lor", test_RPQMatrix_Null_Child_lor}, + {"RPQMatrix_Null_Child_L_Kleene", test_RPQMatrix_Null_Child_L_Kleene}, + {"RPQMatrix_Null_Child_R_Kleene", test_RPQMatrix_Null_Child_R_Kleene}, + {"RPQMatrix_Non_Null_Children_Kleene", test_RPQMatrix_Non_Null_Children_Kleene}, + {"RPQMatrix_Left_Child_Kleene", test_RPQMatrix_Left_Child_Kleene}, + {"RPQMatrix_Invalid_Op_type", test_RPQMatrix_Invalid_Op_type}, + {"RPQMatrix_Null_root", test_RPQMatrix_Null_root}, + {NULL, NULL}} ; From 34d0489b66bedaad9de052c3bec55ee58b9c90ec Mon Sep 17 00:00:00 2001 From: Rodion Suvorov Date: Mon, 6 Oct 2025 03:55:36 +0300 Subject: [PATCH 22/38] feat: add matrix in deps for RPQ-matrix tests --- data/rpq_data/c.mtx | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 data/rpq_data/c.mtx diff --git a/data/rpq_data/c.mtx b/data/rpq_data/c.mtx new file mode 100644 index 0000000000..6f7121ec43 --- /dev/null +++ b/data/rpq_data/c.mtx @@ -0,0 +1,17 @@ +%%MatrixMarket matrix coordinate pattern general$ +%%GraphBLAS type bool$ +8 8 14 +1 2 +1 4 +1 7 +2 3 +2 8 +3 1 +3 6 +4 5 +5 2 +5 8 +6 4 +7 1 +7 6 +8 3 From 8a17cff4d600c0377596e0e9c61108f5e1afff72 Mon Sep 17 00:00:00 2001 From: Rodion Suvorov Date: Mon, 6 Oct 2025 03:59:02 +0300 Subject: [PATCH 23/38] fix: typo in l kleene comment --- experimental/algorithm/LAGraph_RPQMatrix.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/experimental/algorithm/LAGraph_RPQMatrix.c b/experimental/algorithm/LAGraph_RPQMatrix.c index 06a7d6d6d3..a99fac5bd4 100644 --- a/experimental/algorithm/LAGraph_RPQMatrix.c +++ b/experimental/algorithm/LAGraph_RPQMatrix.c @@ -370,7 +370,7 @@ static GrB_Info LAGraph_RPQMatrixKleene_L(RPQMatrixPlan *plan, char *msg) for (;;) { - // T = S x (A + I) + // T = (A + I) x S GRB_TRY(GrB_mxm(T, NULL, NULL, sr, API, S, NULL)) ; GrB_Index nnz_T ; From d0893ff67489b9ad7964696234e692ffa45199fb Mon Sep 17 00:00:00 2001 From: Rodion Suvorov Date: Mon, 6 Oct 2025 14:31:40 +0300 Subject: [PATCH 24/38] feat: change kleene logic This patch brings old kleene logic back: - R kleene: S <- A S <- S x (B + I) - L kleene: S <- B S <- (A + I) x S Also all kleene stars now implemented via accumulator without creation new tmp matrices. Signed-off-by: Rodion Suvorov --- experimental/algorithm/LAGraph_RPQMatrix.c | 264 ++++++++------------- 1 file changed, 103 insertions(+), 161 deletions(-) diff --git a/experimental/algorithm/LAGraph_RPQMatrix.c b/experimental/algorithm/LAGraph_RPQMatrix.c index a99fac5bd4..85b8389c9d 100644 --- a/experimental/algorithm/LAGraph_RPQMatrix.c +++ b/experimental/algorithm/LAGraph_RPQMatrix.c @@ -230,71 +230,63 @@ static GrB_Info LAGraph_RPQMatrixConcat(RPQMatrixPlan *plan, char *msg) static GrB_Info LAGraph_RPQMatrixKleene(RPQMatrixPlan *plan, char *msg) { - LG_ASSERT(plan != NULL, GrB_NULL_POINTER) ; - LG_ASSERT(plan->op == RPQ_MATRIX_OP_KLEENE, GrB_INVALID_VALUE) ; - LG_ASSERT(plan->res_mat == NULL, GrB_INVALID_VALUE) ; + LG_ASSERT(plan != NULL, GrB_NULL_POINTER); + LG_ASSERT(plan->op == RPQ_MATRIX_OP_KLEENE, GrB_INVALID_VALUE); + LG_ASSERT(plan->res_mat == NULL, GrB_INVALID_VALUE); - RPQMatrixPlan *rhs = plan->rhs; // B - // KLEENE should have only right child - LG_ASSERT(rhs != NULL, GrB_NULL_POINTER) ; - LG_ASSERT(plan->lhs == NULL, GrB_INVALID_VALUE) ; + RPQMatrixPlan *lhs = plan->lhs; + RPQMatrixPlan *rhs = plan->rhs; - OK(LAGraph_RPQMatrix_solver(rhs, msg)) ; - GrB_Matrix B = rhs->res_mat ; + // Kleene star should have one child. Always right. + LG_ASSERT(lhs == NULL, GrB_INVALID_VALUE); + LG_ASSERT(rhs != NULL, GrB_NULL_POINTER); + + OK(LAGraph_RPQMatrix_solver(rhs, msg)); - GrB_Index n ; - GRB_TRY(GrB_Matrix_nrows(&n, B)) ; + GrB_Matrix B = rhs->res_mat; + // S <- I + GrB_Matrix S; - // create identity matrix I - GrB_Matrix I ; - GRB_TRY(GrB_Matrix_new(&I, GrB_BOOL, n, n)) ; - GrB_Vector v ; - GRB_TRY(GrB_Vector_new(&v, GrB_BOOL, n)) ; - GRB_TRY(GrB_Vector_assign_BOOL(v, NULL, NULL, true, GrB_ALL, n, NULL)) ; - GRB_TRY(GrB_Matrix_diag(&I, v, 0)) ; - GRB_TRY(GrB_Vector_free(&v)) ; + // Creating identity matrix. + GrB_Index n; + GRB_TRY(GrB_Matrix_nrows(&n, B)); + GrB_Matrix I; + GRB_TRY(GrB_Matrix_new(&I, GrB_BOOL, n, n)); - // BPI = B + I - GrB_Matrix BPI ; - GRB_TRY(GrB_Matrix_new(&BPI, GrB_BOOL, n, n)) ; - GRB_TRY(GrB_eWiseAdd(BPI, NULL, NULL, op, B, I, NULL)) ; + GrB_Vector v; + GRB_TRY(GrB_Vector_new(&v, GrB_BOOL, n)); + GRB_TRY(GrB_Vector_assign_BOOL(v, NULL, NULL, true, GrB_ALL, n, NULL)); - // S <- I - GrB_Matrix S ; - GRB_TRY(GrB_Matrix_dup(&S, I)) ; - GrB_Index nnz_S ; - GRB_TRY(GrB_Matrix_nvals(&nnz_S, S)) ; + GRB_TRY(GrB_Matrix_diag(&S, v, 0)); - // temp T - GrB_Matrix T ; - GRB_TRY(GrB_Matrix_new(&T, GrB_BOOL, n, n)) ; + GRB_TRY(GrB_Vector_free(&v)); + + bool changed = true; + GrB_Index nnz_S = n, nnz_Sold = 0; - for (;;) + while (changed) { - // T = S x (B + I) - GRB_TRY(GrB_mxm(T, NULL, NULL, sr, S, BPI, NULL)) ; - - GrB_Index nnz_T ; - GRB_TRY(GrB_Matrix_nvals(&nnz_T, T)) ; - if (nnz_T == nnz_S) break ; - - nnz_S = nnz_T ; - // swap(S, T) - GrB_Matrix tmp = S ; - S = T ; - T = tmp ; - GRB_TRY(GrB_Matrix_clear(T)) ; - } + // S <- S x (B + I) + GRB_TRY(GrB_mxm(S, S, GrB_NULL, + sr, S, B, GrB_DESC_C)); - plan->res_mat = S ; + GRB_TRY(GrB_Matrix_nvals(&nnz_S, S)); + if (nnz_S != nnz_Sold) + { + changed = true; + nnz_Sold = nnz_S; + } + else + { + changed = false; + } + } + plan->res_mat = S; - GRB_TRY(GrB_Matrix_free(&T)) ; - GRB_TRY(GrB_Matrix_free(&I)) ; - GRB_TRY(GrB_Matrix_free(&BPI)) ; - return GrB_SUCCESS ; + GRB_TRY(GrB_Matrix_free(&I)); + return (GrB_SUCCESS); } - // this function need to handle special case where some optimization // are available. // @@ -324,75 +316,49 @@ static GrB_Info LAGraph_RPQMatrixKleene(RPQMatrixPlan *plan, char *msg) // ┌─┬─┴─┬─┐ // │a│ │b│ // └─┘ └─┘ - static GrB_Info LAGraph_RPQMatrixKleene_L(RPQMatrixPlan *plan, char *msg) { - LG_ASSERT(plan != NULL, GrB_NULL_POINTER) ; - LG_ASSERT(plan->op == RPQ_MATRIX_OP_KLEENE_L, GrB_INVALID_VALUE) ; - LG_ASSERT(plan->res_mat == NULL, GrB_INVALID_VALUE) ; + LG_ASSERT(plan != NULL, GrB_NULL_POINTER); + LG_ASSERT(plan->op == RPQ_MATRIX_OP_KLEENE_L, GrB_INVALID_VALUE); + LG_ASSERT(plan->res_mat == NULL, GrB_INVALID_VALUE); - RPQMatrixPlan *lhs = plan->lhs ; // A - RPQMatrixPlan *rhs = plan->rhs ; // B - LG_ASSERT(lhs != NULL, GrB_NULL_POINTER) ; - LG_ASSERT(rhs != NULL, GrB_NULL_POINTER) ; + RPQMatrixPlan *lhs = plan->lhs; // A + RPQMatrixPlan *rhs = plan->rhs; // B - OK(LAGraph_RPQMatrix_solver(lhs, msg)) ; - OK(LAGraph_RPQMatrix_solver(rhs, msg)) ; - GrB_Matrix A = lhs->res_mat ; - GrB_Matrix B = rhs->res_mat ; - - GrB_Index n ; - GRB_TRY(GrB_Matrix_nrows(&n, B)) ; - - // creating identity matrix I - GrB_Matrix I ; - GRB_TRY(GrB_Matrix_new(&I, GrB_BOOL, n, n)) ; - GrB_Vector v ; - GRB_TRY(GrB_Vector_new(&v, GrB_BOOL, n)) ; - GRB_TRY(GrB_Vector_assign_BOOL(v, NULL, NULL, true, GrB_ALL, n, NULL)) ; - GRB_TRY(GrB_Matrix_diag(&I, v, 0)) ; - GRB_TRY(GrB_Vector_free(&v)) ; - - // API = A + I - GrB_Matrix API ; - GRB_TRY(GrB_Matrix_new(&API, GrB_BOOL, n, n)) ; - GRB_TRY(GrB_eWiseAdd(API, NULL, NULL, op, A, I, NULL)) ; + LG_ASSERT(lhs != NULL, GrB_NULL_POINTER); + LG_ASSERT(rhs != NULL, GrB_NULL_POINTER); + + OK(LAGraph_RPQMatrix_solver(lhs, msg)); + OK(LAGraph_RPQMatrix_solver(rhs, msg)); + + GrB_Matrix A = lhs->res_mat; + GrB_Matrix B = rhs->res_mat; // S <- B - GrB_Matrix S ; - GRB_TRY(GrB_Matrix_dup(&S, B)) ; - GrB_Index nnz_S ; - GRB_TRY(GrB_Matrix_nvals(&nnz_S, S)) ; + GrB_Matrix S; + GRB_TRY(GrB_Matrix_dup(&S, B)); - // temp T - GrB_Matrix T ; - GRB_TRY(GrB_Matrix_new(&T, GrB_BOOL, n, n)) ; + bool changed = true; + GrB_Index nnz_S = 0, nnz_Sold = 0; - for (;;) + while (changed) { - // T = (A + I) x S - GRB_TRY(GrB_mxm(T, NULL, NULL, sr, API, S, NULL)) ; + // S<- (A + I) x S + GRB_TRY(GrB_mxm(S, S, NULL, sr, A, S, GrB_DESC_C)); - GrB_Index nnz_T ; - GRB_TRY(GrB_Matrix_nvals(&nnz_T, T)) ; - if (nnz_T == nnz_S) + GRB_TRY(GrB_Matrix_nvals(&nnz_S, S)); + if (nnz_S != nnz_Sold) { - break ; + changed = true; + nnz_Sold = nnz_S; + } + else + { + changed = false; } - - nnz_S = nnz_T ; - // swap(S, T) - GrB_Matrix tmp = S ; - S = T ; - T = tmp ; - GRB_TRY(GrB_Matrix_clear(T)) ; } - plan->res_mat = S ; - - GRB_TRY(GrB_Matrix_free(&T)) ; - GRB_TRY(GrB_Matrix_free(&I)) ; - GRB_TRY(GrB_Matrix_free(&API)) ; + plan->res_mat = S; return GrB_SUCCESS; } @@ -427,76 +393,52 @@ static GrB_Info LAGraph_RPQMatrixKleene_L(RPQMatrixPlan *plan, char *msg) static GrB_Info LAGraph_RPQMatrixKleene_R(RPQMatrixPlan *plan, char *msg) { - LG_ASSERT(plan != NULL, GrB_NULL_POINTER) ; - LG_ASSERT(plan->op == RPQ_MATRIX_OP_KLEENE_R, GrB_INVALID_VALUE) ; - LG_ASSERT(plan->res_mat == NULL, GrB_INVALID_VALUE) ; + LG_ASSERT(plan != NULL, GrB_NULL_POINTER); + LG_ASSERT(plan->op == RPQ_MATRIX_OP_KLEENE_R, GrB_INVALID_VALUE); + LG_ASSERT(plan->res_mat == NULL, GrB_INVALID_VALUE); - RPQMatrixPlan *lhs = plan->lhs ; // A - RPQMatrixPlan *rhs = plan->rhs ; // B - LG_ASSERT(lhs != NULL, GrB_NULL_POINTER) ; - LG_ASSERT(rhs != NULL, GrB_NULL_POINTER) ; + RPQMatrixPlan *lhs = plan->lhs; // A + RPQMatrixPlan *rhs = plan->rhs; // B - OK(LAGraph_RPQMatrix_solver(lhs, msg)) ; - OK(LAGraph_RPQMatrix_solver(rhs, msg)) ; - GrB_Matrix A = lhs->res_mat ; - GrB_Matrix B = rhs->res_mat ; - - GrB_Index n ; - GRB_TRY(GrB_Matrix_nrows(&n, B)) ; - - // creating identity matrix I - GrB_Matrix I ; - GRB_TRY(GrB_Matrix_new(&I, GrB_BOOL, n, n)) ; - GrB_Vector v ; - GRB_TRY(GrB_Vector_new(&v, GrB_BOOL, n)) ; - GRB_TRY(GrB_Vector_assign_BOOL(v, NULL, NULL, true, GrB_ALL, n, NULL)) ; - GRB_TRY(GrB_Matrix_diag(&I, v, 0)) ; - GRB_TRY(GrB_Vector_free(&v)) ; - - // BPI = B + I - GrB_Matrix BPI ; - GRB_TRY(GrB_Matrix_new(&BPI, GrB_BOOL, n, n)) ; - GRB_TRY(GrB_eWiseAdd(BPI, NULL, NULL, op, B, I, NULL)) ; + LG_ASSERT(lhs != NULL, GrB_NULL_POINTER); + LG_ASSERT(rhs != NULL, GrB_NULL_POINTER); + + OK(LAGraph_RPQMatrix_solver(lhs, msg)); + OK(LAGraph_RPQMatrix_solver(rhs, msg)); + + GrB_Matrix A = lhs->res_mat; + GrB_Matrix B = rhs->res_mat; // S <- A - GrB_Matrix S ; - GRB_TRY(GrB_Matrix_dup(&S, A)) ; - GrB_Index nnz_S ; - GRB_TRY(GrB_Matrix_nvals(&nnz_S, S)) ; + GrB_Matrix S; + GRB_TRY(GrB_Matrix_dup(&S, A)); - // temp T - GrB_Matrix T ; - GRB_TRY(GrB_Matrix_new(&T, GrB_BOOL, n, n)) ; + bool changed = true; + GrB_Index nnz_S = 0, nnz_Sold = 0; - for (;;) + while (changed) { - // T = S x (B + I) - GRB_TRY(GrB_mxm(T, NULL, NULL, sr, S, BPI, NULL)) ; + // S <- S x (B + I) + GRB_TRY(GrB_mxm(S, S, NULL, sr, S, B, GrB_DESC_C)); - GrB_Index nnz_T ; - GRB_TRY(GrB_Matrix_nvals(&nnz_T, T)) ; - if (nnz_T == nnz_S) + GRB_TRY(GrB_Matrix_nvals(&nnz_S, S)); + if (nnz_S != nnz_Sold) { - break ; + changed = true; + nnz_Sold = nnz_S; + } + else + { + changed = false; } - - nnz_S = nnz_T ; - // swap(S, T) - GrB_Matrix tmp = S ; - S = T ; - T = tmp ; - GRB_TRY(GrB_Matrix_clear(T)) ; } - plan->res_mat = S ; - - GRB_TRY(GrB_Matrix_free(&T)) ; - GRB_TRY(GrB_Matrix_free(&I)) ; - GRB_TRY(GrB_Matrix_free(&BPI)) ; + plan->res_mat = S; return GrB_SUCCESS; } + GrB_Info LAGraph_RPQMatrix_solver(RPQMatrixPlan *plan, char *msg) { LG_ASSERT(plan->res_mat == NULL, GrB_INVALID_VALUE) ; From 6c30ede37e9c82c52b67ec729551e3252aef172e Mon Sep 17 00:00:00 2001 From: Rodion Suvorov Date: Mon, 6 Oct 2025 14:50:27 +0300 Subject: [PATCH 25/38] refactor: add spaces before semicolon Signed-off-by: Rodion Suvorov --- experimental/algorithm/LAGraph_RPQMatrix.c | 148 ++++++++++----------- 1 file changed, 74 insertions(+), 74 deletions(-) diff --git a/experimental/algorithm/LAGraph_RPQMatrix.c b/experimental/algorithm/LAGraph_RPQMatrix.c index 85b8389c9d..7ade0ad3de 100644 --- a/experimental/algorithm/LAGraph_RPQMatrix.c +++ b/experimental/algorithm/LAGraph_RPQMatrix.c @@ -230,61 +230,61 @@ static GrB_Info LAGraph_RPQMatrixConcat(RPQMatrixPlan *plan, char *msg) static GrB_Info LAGraph_RPQMatrixKleene(RPQMatrixPlan *plan, char *msg) { - LG_ASSERT(plan != NULL, GrB_NULL_POINTER); - LG_ASSERT(plan->op == RPQ_MATRIX_OP_KLEENE, GrB_INVALID_VALUE); - LG_ASSERT(plan->res_mat == NULL, GrB_INVALID_VALUE); + LG_ASSERT(plan != NULL, GrB_NULL_POINTER) ; + LG_ASSERT(plan->op == RPQ_MATRIX_OP_KLEENE, GrB_INVALID_VALUE) ; + LG_ASSERT(plan->res_mat == NULL, GrB_INVALID_VALUE) ; - RPQMatrixPlan *lhs = plan->lhs; - RPQMatrixPlan *rhs = plan->rhs; + RPQMatrixPlan *lhs = plan->lhs ; + RPQMatrixPlan *rhs = plan->rhs ; // Kleene star should have one child. Always right. - LG_ASSERT(lhs == NULL, GrB_INVALID_VALUE); - LG_ASSERT(rhs != NULL, GrB_NULL_POINTER); + LG_ASSERT(lhs == NULL, GrB_INVALID_VALUE) ; + LG_ASSERT(rhs != NULL, GrB_NULL_POINTER) ; - OK(LAGraph_RPQMatrix_solver(rhs, msg)); + OK(LAGraph_RPQMatrix_solver(rhs, msg)) ; - GrB_Matrix B = rhs->res_mat; + GrB_Matrix B = rhs->res_mat ; // S <- I - GrB_Matrix S; + GrB_Matrix S ; // Creating identity matrix. - GrB_Index n; - GRB_TRY(GrB_Matrix_nrows(&n, B)); - GrB_Matrix I; - GRB_TRY(GrB_Matrix_new(&I, GrB_BOOL, n, n)); + GrB_Index n ; + GRB_TRY(GrB_Matrix_nrows(&n, B)) ; + GrB_Matrix I ; + GRB_TRY(GrB_Matrix_new(&I, GrB_BOOL, n, n)) ; - GrB_Vector v; - GRB_TRY(GrB_Vector_new(&v, GrB_BOOL, n)); - GRB_TRY(GrB_Vector_assign_BOOL(v, NULL, NULL, true, GrB_ALL, n, NULL)); + GrB_Vector v ; + GRB_TRY(GrB_Vector_new(&v, GrB_BOOL, n)) ; + GRB_TRY(GrB_Vector_assign_BOOL(v, NULL, NULL, true, GrB_ALL, n, NULL)) ; - GRB_TRY(GrB_Matrix_diag(&S, v, 0)); + GRB_TRY(GrB_Matrix_diag(&S, v, 0)) ; - GRB_TRY(GrB_Vector_free(&v)); + GRB_TRY(GrB_Vector_free(&v)) ; - bool changed = true; - GrB_Index nnz_S = n, nnz_Sold = 0; + bool changed = true ; + GrB_Index nnz_S = n, nnz_Sold = 0 ; while (changed) { // S <- S x (B + I) GRB_TRY(GrB_mxm(S, S, GrB_NULL, - sr, S, B, GrB_DESC_C)); + sr, S, B, GrB_DESC_C)) ; - GRB_TRY(GrB_Matrix_nvals(&nnz_S, S)); + GRB_TRY(GrB_Matrix_nvals(&nnz_S, S)) ; if (nnz_S != nnz_Sold) { - changed = true; - nnz_Sold = nnz_S; + changed = true ; + nnz_Sold = nnz_S ; } else { - changed = false; + changed = false ; } } - plan->res_mat = S; + plan->res_mat = S ; - GRB_TRY(GrB_Matrix_free(&I)); - return (GrB_SUCCESS); + GRB_TRY(GrB_Matrix_free(&I)) ; + return (GrB_SUCCESS) ; } // this function need to handle special case where some optimization @@ -318,48 +318,48 @@ static GrB_Info LAGraph_RPQMatrixKleene(RPQMatrixPlan *plan, char *msg) // └─┘ └─┘ static GrB_Info LAGraph_RPQMatrixKleene_L(RPQMatrixPlan *plan, char *msg) { - LG_ASSERT(plan != NULL, GrB_NULL_POINTER); - LG_ASSERT(plan->op == RPQ_MATRIX_OP_KLEENE_L, GrB_INVALID_VALUE); - LG_ASSERT(plan->res_mat == NULL, GrB_INVALID_VALUE); + LG_ASSERT(plan != NULL, GrB_NULL_POINTER) ; + LG_ASSERT(plan->op == RPQ_MATRIX_OP_KLEENE_L, GrB_INVALID_VALUE) ; + LG_ASSERT(plan->res_mat == NULL, GrB_INVALID_VALUE) ; - RPQMatrixPlan *lhs = plan->lhs; // A - RPQMatrixPlan *rhs = plan->rhs; // B + RPQMatrixPlan *lhs = plan->lhs ; // A + RPQMatrixPlan *rhs = plan->rhs ; // B - LG_ASSERT(lhs != NULL, GrB_NULL_POINTER); - LG_ASSERT(rhs != NULL, GrB_NULL_POINTER); + LG_ASSERT(lhs != NULL, GrB_NULL_POINTER) ; + LG_ASSERT(rhs != NULL, GrB_NULL_POINTER) ; - OK(LAGraph_RPQMatrix_solver(lhs, msg)); - OK(LAGraph_RPQMatrix_solver(rhs, msg)); + OK(LAGraph_RPQMatrix_solver(lhs, msg)) ; + OK(LAGraph_RPQMatrix_solver(rhs, msg)) ; - GrB_Matrix A = lhs->res_mat; - GrB_Matrix B = rhs->res_mat; + GrB_Matrix A = lhs->res_mat ; + GrB_Matrix B = rhs->res_mat ; // S <- B - GrB_Matrix S; - GRB_TRY(GrB_Matrix_dup(&S, B)); + GrB_Matrix S ; + GRB_TRY(GrB_Matrix_dup(&S, B)) ; - bool changed = true; - GrB_Index nnz_S = 0, nnz_Sold = 0; + bool changed = true ; + GrB_Index nnz_S = 0, nnz_Sold = 0 ; while (changed) { - // S<- (A + I) x S - GRB_TRY(GrB_mxm(S, S, NULL, sr, A, S, GrB_DESC_C)); + // S <- (A + I) x S + GRB_TRY(GrB_mxm(S, S, NULL, sr, A, S, GrB_DESC_C)) ; - GRB_TRY(GrB_Matrix_nvals(&nnz_S, S)); + GRB_TRY(GrB_Matrix_nvals(&nnz_S, S)) ; if (nnz_S != nnz_Sold) { - changed = true; - nnz_Sold = nnz_S; + changed = true ; + nnz_Sold = nnz_S ; } else { - changed = false; + changed = false ; } } - plan->res_mat = S; - return GrB_SUCCESS; + plan->res_mat = S ; + return GrB_SUCCESS ; } // this function need to handle special case where some optimization @@ -393,48 +393,48 @@ static GrB_Info LAGraph_RPQMatrixKleene_L(RPQMatrixPlan *plan, char *msg) static GrB_Info LAGraph_RPQMatrixKleene_R(RPQMatrixPlan *plan, char *msg) { - LG_ASSERT(plan != NULL, GrB_NULL_POINTER); - LG_ASSERT(plan->op == RPQ_MATRIX_OP_KLEENE_R, GrB_INVALID_VALUE); - LG_ASSERT(plan->res_mat == NULL, GrB_INVALID_VALUE); + LG_ASSERT(plan != NULL, GrB_NULL_POINTER) ; + LG_ASSERT(plan->op == RPQ_MATRIX_OP_KLEENE_R, GrB_INVALID_VALUE) ; + LG_ASSERT(plan->res_mat == NULL, GrB_INVALID_VALUE) ; - RPQMatrixPlan *lhs = plan->lhs; // A - RPQMatrixPlan *rhs = plan->rhs; // B + RPQMatrixPlan *lhs = plan->lhs ; // A + RPQMatrixPlan *rhs = plan->rhs ; // B - LG_ASSERT(lhs != NULL, GrB_NULL_POINTER); - LG_ASSERT(rhs != NULL, GrB_NULL_POINTER); + LG_ASSERT(lhs != NULL, GrB_NULL_POINTER) ; + LG_ASSERT(rhs != NULL, GrB_NULL_POINTER) ; - OK(LAGraph_RPQMatrix_solver(lhs, msg)); - OK(LAGraph_RPQMatrix_solver(rhs, msg)); + OK(LAGraph_RPQMatrix_solver(lhs, msg)) ; + OK(LAGraph_RPQMatrix_solver(rhs, msg)) ; - GrB_Matrix A = lhs->res_mat; - GrB_Matrix B = rhs->res_mat; + GrB_Matrix A = lhs->res_mat ; + GrB_Matrix B = rhs->res_mat ; // S <- A - GrB_Matrix S; - GRB_TRY(GrB_Matrix_dup(&S, A)); + GrB_Matrix S ; + GRB_TRY(GrB_Matrix_dup(&S, A)) ; - bool changed = true; - GrB_Index nnz_S = 0, nnz_Sold = 0; + bool changed = true ; + GrB_Index nnz_S = 0, nnz_Sold = 0 ; while (changed) { // S <- S x (B + I) - GRB_TRY(GrB_mxm(S, S, NULL, sr, S, B, GrB_DESC_C)); + GRB_TRY(GrB_mxm(S, S, NULL, sr, S, B, GrB_DESC_C)) ; - GRB_TRY(GrB_Matrix_nvals(&nnz_S, S)); + GRB_TRY(GrB_Matrix_nvals(&nnz_S, S)) ; if (nnz_S != nnz_Sold) { - changed = true; - nnz_Sold = nnz_S; + changed = true ; + nnz_Sold = nnz_S ; } else { - changed = false; + changed = false ; } } - plan->res_mat = S; - return GrB_SUCCESS; + plan->res_mat = S ; + return GrB_SUCCESS ; } From 873f1d66380adda7f24fd4973e81e3b93b45da4e Mon Sep 17 00:00:00 2001 From: Rodion Suvorov Date: Mon, 6 Oct 2025 14:57:43 +0300 Subject: [PATCH 26/38] feat: additional non null assertion in lor --- experimental/algorithm/LAGraph_RPQMatrix.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/experimental/algorithm/LAGraph_RPQMatrix.c b/experimental/algorithm/LAGraph_RPQMatrix.c index 7ade0ad3de..0daf43e607 100644 --- a/experimental/algorithm/LAGraph_RPQMatrix.c +++ b/experimental/algorithm/LAGraph_RPQMatrix.c @@ -184,6 +184,9 @@ static GrB_Info LAGraph_RPQMatrixLor(RPQMatrixPlan *plan, char *msg) OK(LAGraph_RPQMatrix_solver(lhs, msg)) ; OK(LAGraph_RPQMatrix_solver(rhs, msg)) ; + LG_ASSERT(rhs->mat != NULL, GrB_NULL_POINTER) ; + LG_ASSERT(lhs->mat != NULL, GrB_NULL_POINTER) ; + GrB_Matrix lhs_mat = lhs->res_mat ; GrB_Matrix rhs_mat = rhs->res_mat ; From 145fe75b4051c8c9dd397251c41df46df311592a Mon Sep 17 00:00:00 2001 From: Rodion Suvorov Date: Mon, 6 Oct 2025 15:00:41 +0300 Subject: [PATCH 27/38] fix: free matrices in tests --- experimental/test/test_RPQMatrix.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/experimental/test/test_RPQMatrix.c b/experimental/test/test_RPQMatrix.c index 71f5d4f923..738418ff8f 100644 --- a/experimental/test/test_RPQMatrix.c +++ b/experimental/test/test_RPQMatrix.c @@ -104,6 +104,8 @@ void test_RPQMatrix_CONCAT(void) check_result_matrix(concat.res_mat, expected) ; TEST_CHECK(result_nnz == 6) ; + GrB_Matrix_free(&A) ; + GrB_Matrix_free(&B) ; LAGraph_Finalize(msg) ; } @@ -130,6 +132,8 @@ void test_RPQMatrix_LOR(void) check_result_matrix(lor.res_mat, expected) ; TEST_CHECK(result_nnz == 13) ; + GrB_Matrix_free(&A) ; + GrB_Matrix_free(&B) ; LAGraph_Finalize(msg) ; } @@ -152,6 +156,7 @@ void test_RPQMatrix_KLEENE(void) check_result_matrix(kleene.res_mat, expected) ; TEST_CHECK(result_nnz == 16) ; + GrB_Matrix_free(&A) ; LAGraph_Finalize(msg) ; } @@ -196,6 +201,8 @@ void test_RPQMatrix_KLEENE_L(void) check_result_matrix(kleeneL.res_mat, expected) ; TEST_CHECK(result_nnz == expected_nnz) ; + GrB_Matrix_free(&A) ; + GrB_Matrix_free(&B) ; LAGraph_Finalize(msg) ; } @@ -226,6 +233,7 @@ void test_RPQMatrix_KLEENE_R(void) check_result_matrix(concat.res_mat, expected) ; TEST_CHECK(result_nnz == 13) ; GrB_Info expected_nnz = result_nnz ; + RPQMatrixPlan planA2 = {.op = RPQ_MATRIX_OP_LABEL, .mat = A} ; RPQMatrixPlan planB2 = {.op = RPQ_MATRIX_OP_LABEL, .mat = B} ; RPQMatrixPlan kleeneR = { @@ -239,6 +247,8 @@ void test_RPQMatrix_KLEENE_R(void) check_result_matrix(kleeneR.res_mat, expected) ; TEST_CHECK(result_nnz == expected_nnz) ; + GrB_Matrix_free(&A) ; + GrB_Matrix_free(&B) ; LAGraph_Finalize(msg) ; } @@ -274,6 +284,10 @@ void test_RPQMatrix_Complex(void) "(8, 3) (8, 6)" ; check_result_matrix(concat.res_mat, expected) ; TEST_CHECK(result_nnz == 48) ; + + GrB_Matrix_free(&A); + GrB_Matrix_free(&B); + GrB_Matrix_free(&C); LAGraph_Finalize(msg) ; } @@ -413,7 +427,7 @@ void test_RPQMatrix_Left_Child_Kleene(void) GrB_Index result_nnz ; GrB_Info info = LAGraph_RPQMatrix(&result_nnz, &kleene, msg) ; - TEST_CHECK(info == GrB_NULL_POINTER) ; + TEST_CHECK(info == GrB_INVALID_VALUE) ; TEST_MSG("Expected GrB_NULL_POINTER for KLEENE with only left child") ; GrB_Matrix_free(&A) ; From ecabbef02eed34887b06ba1ae0a3bf5a41215def Mon Sep 17 00:00:00 2001 From: Rodion Suvorov Date: Wed, 8 Oct 2025 18:42:04 +0300 Subject: [PATCH 28/38] feat: change semiring and monoid operator --- experimental/algorithm/LAGraph_RPQMatrix.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/experimental/algorithm/LAGraph_RPQMatrix.c b/experimental/algorithm/LAGraph_RPQMatrix.c index 0daf43e607..91be10ac81 100644 --- a/experimental/algorithm/LAGraph_RPQMatrix.c +++ b/experimental/algorithm/LAGraph_RPQMatrix.c @@ -471,8 +471,8 @@ GrB_Info LAGraph_RPQMatrix_solver(RPQMatrixPlan *plan, char *msg) GrB_Info LAGraph_RPQMatrix_initialize(void) { - sr = GrB_LOR_LAND_SEMIRING_BOOL ; - op = GxB_LOR_BOOL_MONOID ; + sr = GxB_ANY_PAIR_BOOL ; + op = GxB_ANY_BOOL_MONOID ; return GrB_SUCCESS; } From 1c08178510d60f028e3a567da78fcc34f7b9fb07 Mon Sep 17 00:00:00 2001 From: Rodion Suvorov Date: Tue, 30 Sep 2025 16:36:33 +0300 Subject: [PATCH 29/38] fix: make lagraph_mm_read ignore duplicates --- src/utility/LAGraph_MMRead.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/utility/LAGraph_MMRead.c b/src/utility/LAGraph_MMRead.c index 5aa9e390cb..e524570f49 100644 --- a/src/utility/LAGraph_MMRead.c +++ b/src/utility/LAGraph_MMRead.c @@ -989,7 +989,7 @@ int LAGraph_MMRead if (type == GrB_BOOL) { - GRB_TRY (GrB_Matrix_build_BOOL (*A, I, J, (bool *) X, nvals2, NULL)) ; + GRB_TRY (GrB_Matrix_build_BOOL (*A, I, J, (bool *) X, nvals2, GxB_IGNORE_DUP)) ; } else if (type == GrB_INT8) { From 23968afdcf5ff530985c24d2d7814e7087c34169 Mon Sep 17 00:00:00 2001 From: Rodion Suvorov Date: Wed, 8 Oct 2025 19:20:42 +0300 Subject: [PATCH 30/38] feat: add label and destroy methods This patch brings public methods for rust la-n-egg-rpq algorithm. Signed-off-by: Rodion Suvorov --- experimental/algorithm/LAGraph_RPQMatrix.c | 35 ++++++++++++++++++++-- include/LAGraphX.h | 12 ++++++++ 2 files changed, 44 insertions(+), 3 deletions(-) diff --git a/experimental/algorithm/LAGraph_RPQMatrix.c b/experimental/algorithm/LAGraph_RPQMatrix.c index 91be10ac81..0ac57d5257 100644 --- a/experimental/algorithm/LAGraph_RPQMatrix.c +++ b/experimental/algorithm/LAGraph_RPQMatrix.c @@ -167,6 +167,35 @@ GrB_Info LAGraph_RPQMatrix_check(RPQMatrixPlan *plan, GrB_Index *dimension, char static GrB_Semiring sr ; static GrB_Monoid op ; +GrB_Info LAGraph_RPQMatrix_label(GrB_Matrix *mat, GrB_Index x, GrB_Index i, GrB_Index j) +{ + OK(GrB_Matrix_new(mat, GrB_BOOL, i, j)) ; + OK(GrB_Matrix_setElement(*mat, true, x, x)) ; + return (GrB_SUCCESS) ; +} +GrB_Info LAGraph_DestroyRpqMatrixPlan(RPQMatrixPlan *plan) +{ + if (plan == NULL) + { + return GrB_SUCCESS ; + } + if (plan->mat != NULL) + { + OK(GrB_Matrix_free(&(plan->mat))) ; + } + if (plan->res_mat != NULL) + { + OK(GrB_Matrix_free(&(plan->res_mat))) ; + } + GrB_Info lstatus = LAGraph_DestroyRpqMatrixPlan(plan->lhs) ; + GrB_Info rstatus = LAGraph_DestroyRpqMatrixPlan(plan->rhs) ; + if (rstatus || lstatus) + { + return GrB_INVALID_VALUE ; + } + return GrB_SUCCESS ; +} ; + GrB_Info LAGraph_RPQMatrix_solver(RPQMatrixPlan *plan, char *msg) ; static GrB_Info LAGraph_RPQMatrixLor(RPQMatrixPlan *plan, char *msg) @@ -253,8 +282,8 @@ static GrB_Info LAGraph_RPQMatrixKleene(RPQMatrixPlan *plan, char *msg) // Creating identity matrix. GrB_Index n ; GRB_TRY(GrB_Matrix_nrows(&n, B)) ; - GrB_Matrix I ; - GRB_TRY(GrB_Matrix_new(&I, GrB_BOOL, n, n)) ; + // GrB_Matrix I ; + // GRB_TRY(GrB_Matrix_new(&I, GrB_BOOL, n, n)) ; GrB_Vector v ; GRB_TRY(GrB_Vector_new(&v, GrB_BOOL, n)) ; @@ -286,7 +315,7 @@ static GrB_Info LAGraph_RPQMatrixKleene(RPQMatrixPlan *plan, char *msg) } plan->res_mat = S ; - GRB_TRY(GrB_Matrix_free(&I)) ; + // GRB_TRY(GrB_Matrix_free(&I)) ; return (GrB_SUCCESS) ; } diff --git a/include/LAGraphX.h b/include/LAGraphX.h index 132f875b11..30deba66d1 100644 --- a/include/LAGraphX.h +++ b/include/LAGraphX.h @@ -962,6 +962,18 @@ GrB_Info LAGraph_RPQMatrix( char *msg // LAGraph output message ) ; +LAGRAPHX_PUBLIC +GrB_Info LAGraph_RPQMatrix_label +( + GrB_Matrix *mat, + GrB_Index x, + GrB_Index i, + GrB_Index j +) ; + +LAGRAPHX_PUBLIC +GrB_Info LAGraph_DestroyRpqMatrixPlan(RPQMatrixPlan *plan) ; + //**************************************************************************** LAGRAPHX_PUBLIC int LAGraph_VertexCentrality_Triangle // vertex triangle-centrality From 7fc0a7004d53442563f782055eecc20133de88d9 Mon Sep 17 00:00:00 2001 From: Rodion Suvorov Date: Wed, 8 Oct 2025 21:29:51 +0300 Subject: [PATCH 31/38] fix: correct non null assert Fix the typo in non null assertion. we should check res_mat ofc. Signed-off-by: Rodion Suvorov --- experimental/algorithm/LAGraph_RPQMatrix.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/experimental/algorithm/LAGraph_RPQMatrix.c b/experimental/algorithm/LAGraph_RPQMatrix.c index 0ac57d5257..18d3054561 100644 --- a/experimental/algorithm/LAGraph_RPQMatrix.c +++ b/experimental/algorithm/LAGraph_RPQMatrix.c @@ -213,8 +213,8 @@ static GrB_Info LAGraph_RPQMatrixLor(RPQMatrixPlan *plan, char *msg) OK(LAGraph_RPQMatrix_solver(lhs, msg)) ; OK(LAGraph_RPQMatrix_solver(rhs, msg)) ; - LG_ASSERT(rhs->mat != NULL, GrB_NULL_POINTER) ; - LG_ASSERT(lhs->mat != NULL, GrB_NULL_POINTER) ; + LG_ASSERT(rhs->res_mat != NULL, GrB_NULL_POINTER) ; + LG_ASSERT(lhs->res_mat != NULL, GrB_NULL_POINTER) ; GrB_Matrix lhs_mat = lhs->res_mat ; GrB_Matrix rhs_mat = rhs->res_mat ; From 16d96aff7c0c5ed1076651d78b16cd1fec81ca4b Mon Sep 17 00:00:00 2001 From: Georgiy Belyanin Date: Tue, 11 Nov 2025 15:41:23 +0300 Subject: [PATCH 32/38] Fix repeated subexpr eval & extend error msgs This patch fixes the wrong assertion in the regex evaluator that made it impossible to have repeated subexpressions. Assume `(a|b)/(a|b)` regex as an example. This RE have two repeated subexpressions `(a|b)`. The e-graph logic would take into account the fact that these expressions are the same and the resulting tree of the regular expression would have the same node for the `(a|b)` expression. Let's get into the problem. Before this patch the LAGraph solver evaluated lhs, rhs first and then combined their results w.r.t. node type. If there were repeated subexpressions the solver failed due to the assertion that every subexpression had not been evaluated yet. This happened to the example: we evaluated LHS `(a|b)` at first and then we try to calculate RHS `(a|b)`. But the corresponding subtree is already calculated and the assertion is fired. Let's remove the wrong assertion and fix the problem. Apart from these fixes, this patch improves error messages. It has been done in terms of determining what is wrong. There is no reason to avoid these improvements. --- experimental/algorithm/LAGraph_RPQMatrix.c | 39 +++++++++++----------- 1 file changed, 20 insertions(+), 19 deletions(-) diff --git a/experimental/algorithm/LAGraph_RPQMatrix.c b/experimental/algorithm/LAGraph_RPQMatrix.c index 18d3054561..b578eab720 100644 --- a/experimental/algorithm/LAGraph_RPQMatrix.c +++ b/experimental/algorithm/LAGraph_RPQMatrix.c @@ -118,11 +118,13 @@ GrB_Info info = (s); \ if (info != GrB_SUCCESS) \ { \ - fprintf(stderr, "GraphBLAS error: %d\n", info); \ + printf("Message: %s\n", msg); \ + fprintf(stderr, "GraphBLAS error: %d (%s, %d)\n", info, __FILE__, __LINE__); \ return info; \ } \ } +char msg[LAGRAPH_MSG_LEN] ; #include #include @@ -179,11 +181,7 @@ GrB_Info LAGraph_DestroyRpqMatrixPlan(RPQMatrixPlan *plan) { return GrB_SUCCESS ; } - if (plan->mat != NULL) - { - OK(GrB_Matrix_free(&(plan->mat))) ; - } - if (plan->res_mat != NULL) + if (plan->res_mat != NULL && plan->mat != plan->res_mat) { OK(GrB_Matrix_free(&(plan->res_mat))) ; } @@ -201,8 +199,8 @@ GrB_Info LAGraph_RPQMatrix_solver(RPQMatrixPlan *plan, char *msg) ; static GrB_Info LAGraph_RPQMatrixLor(RPQMatrixPlan *plan, char *msg) { LG_ASSERT(plan != NULL, GrB_NULL_POINTER) ; - LG_ASSERT(plan->op == RPQ_MATRIX_OP_LOR, GrB_INVALID_VALUE) ; - LG_ASSERT(plan->res_mat == NULL, GrB_INVALID_VALUE) ; + LG_ASSERT_MSG(plan->op == RPQ_MATRIX_OP_LOR, GrB_INVALID_VALUE, "operator is not lor") ; + LG_ASSERT_MSG(plan->res_mat == NULL, GrB_INVALID_VALUE, "resulting matrix is already set as lor result") ; RPQMatrixPlan *lhs = plan->lhs ; RPQMatrixPlan *rhs = plan->rhs ; @@ -234,8 +232,8 @@ static GrB_Info LAGraph_RPQMatrixConcat(RPQMatrixPlan *plan, char *msg) { LG_ASSERT(plan != NULL, GrB_NULL_POINTER) ; - LG_ASSERT(plan->op == RPQ_MATRIX_OP_CONCAT, GrB_INVALID_VALUE) ; - LG_ASSERT(plan->res_mat == NULL, GrB_INVALID_VALUE) ; + LG_ASSERT_MSG(plan->op == RPQ_MATRIX_OP_CONCAT, GrB_INVALID_VALUE, "operator is not concat") ; + LG_ASSERT_MSG(plan->res_mat == NULL, GrB_INVALID_VALUE, "resulting matrix is already set as concat result") ; RPQMatrixPlan *lhs = plan->lhs ; RPQMatrixPlan *rhs = plan->rhs ; @@ -263,14 +261,14 @@ static GrB_Info LAGraph_RPQMatrixConcat(RPQMatrixPlan *plan, char *msg) static GrB_Info LAGraph_RPQMatrixKleene(RPQMatrixPlan *plan, char *msg) { LG_ASSERT(plan != NULL, GrB_NULL_POINTER) ; - LG_ASSERT(plan->op == RPQ_MATRIX_OP_KLEENE, GrB_INVALID_VALUE) ; - LG_ASSERT(plan->res_mat == NULL, GrB_INVALID_VALUE) ; + LG_ASSERT_MSG(plan->op == RPQ_MATRIX_OP_KLEENE, GrB_INVALID_VALUE, "operator is not kleene") ; + LG_ASSERT_MSG(plan->res_mat == NULL, GrB_INVALID_VALUE, "resulting matrix is already set for kleene") ; RPQMatrixPlan *lhs = plan->lhs ; RPQMatrixPlan *rhs = plan->rhs ; // Kleene star should have one child. Always right. - LG_ASSERT(lhs == NULL, GrB_INVALID_VALUE) ; + LG_ASSERT_MSG(lhs == NULL, GrB_INVALID_VALUE, "lhs is expected to be NULL for kleene") ; LG_ASSERT(rhs != NULL, GrB_NULL_POINTER) ; OK(LAGraph_RPQMatrix_solver(rhs, msg)) ; @@ -351,8 +349,8 @@ static GrB_Info LAGraph_RPQMatrixKleene(RPQMatrixPlan *plan, char *msg) static GrB_Info LAGraph_RPQMatrixKleene_L(RPQMatrixPlan *plan, char *msg) { LG_ASSERT(plan != NULL, GrB_NULL_POINTER) ; - LG_ASSERT(plan->op == RPQ_MATRIX_OP_KLEENE_L, GrB_INVALID_VALUE) ; - LG_ASSERT(plan->res_mat == NULL, GrB_INVALID_VALUE) ; + LG_ASSERT_MSG(plan->op == RPQ_MATRIX_OP_KLEENE_L, GrB_INVALID_VALUE, "different operator is not expected left-kleene") ; + LG_ASSERT_MSG(plan->res_mat == NULL, GrB_INVALID_VALUE, "resulting matrix is already set for left-kleene") ; RPQMatrixPlan *lhs = plan->lhs ; // A RPQMatrixPlan *rhs = plan->rhs ; // B @@ -426,8 +424,8 @@ static GrB_Info LAGraph_RPQMatrixKleene_L(RPQMatrixPlan *plan, char *msg) static GrB_Info LAGraph_RPQMatrixKleene_R(RPQMatrixPlan *plan, char *msg) { LG_ASSERT(plan != NULL, GrB_NULL_POINTER) ; - LG_ASSERT(plan->op == RPQ_MATRIX_OP_KLEENE_R, GrB_INVALID_VALUE) ; - LG_ASSERT(plan->res_mat == NULL, GrB_INVALID_VALUE) ; + LG_ASSERT_MSG(plan->op == RPQ_MATRIX_OP_KLEENE_R, GrB_INVALID_VALUE, "different operator is not expected right-kleene") ; + LG_ASSERT_MSG(plan->res_mat == NULL, GrB_INVALID_VALUE, "resulting matrix is already set for right-kleene") ; RPQMatrixPlan *lhs = plan->lhs ; // A RPQMatrixPlan *rhs = plan->rhs ; // B @@ -473,7 +471,10 @@ static GrB_Info LAGraph_RPQMatrixKleene_R(RPQMatrixPlan *plan, char *msg) GrB_Info LAGraph_RPQMatrix_solver(RPQMatrixPlan *plan, char *msg) { - LG_ASSERT(plan->res_mat == NULL, GrB_INVALID_VALUE) ; + if (plan->res_mat != NULL) + { + return (GrB_SUCCESS) ; + } switch (plan->op) { @@ -500,7 +501,7 @@ GrB_Info LAGraph_RPQMatrix_solver(RPQMatrixPlan *plan, char *msg) GrB_Info LAGraph_RPQMatrix_initialize(void) { - sr = GxB_ANY_PAIR_BOOL ; + sr = LAGraph_any_one_bool ; op = GxB_ANY_BOOL_MONOID ; return GrB_SUCCESS; } From 5e7e53502ec90f1c2055ca5aa54e36b85f78a1d8 Mon Sep 17 00:00:00 2001 From: Rodion Suvorov Date: Mon, 23 Feb 2026 15:08:02 +0300 Subject: [PATCH 33/38] feat: add reduce method this patch brings reduce method that allows calculate reduced matrix by rows and column in lanegg Signed-off-by: Rodion Suvorov --- experimental/algorithm/LAGraph_RPQMatrix.c | 17 +++++++++++++++++ include/LAGraphX.h | 10 ++++++++++ 2 files changed, 27 insertions(+) diff --git a/experimental/algorithm/LAGraph_RPQMatrix.c b/experimental/algorithm/LAGraph_RPQMatrix.c index b578eab720..b521b899ac 100644 --- a/experimental/algorithm/LAGraph_RPQMatrix.c +++ b/experimental/algorithm/LAGraph_RPQMatrix.c @@ -196,6 +196,23 @@ GrB_Info LAGraph_DestroyRpqMatrixPlan(RPQMatrixPlan *plan) GrB_Info LAGraph_RPQMatrix_solver(RPQMatrixPlan *plan, char *msg) ; +GrB_Info LAGraph_RPQMatrix_reduce(GrB_Index *res, GrB_Matrix mat, uint8_t reduce_type) +{ + GrB_Index nvals ; + GrB_Vector reduce ; + if (reduce_type == 0) + { + GrB_Matrix_reduce_Monoid(reduce,NULL,NULL,GxB_ANY_BOOL_MONOID,mat,NULL) ; + } + else if (reduce_type == 1) + { + GrB_Matrix_reduce_Monoid(reduce, NULL,NULL,GxB_ANY_BOOL_MONOID,mat,GrB_DESC_T0) ; + } + GrB_Vector_nvals(&nvals,reduce) ; + *res = nvals ; + return (GrB_SUCCESS) ; +} + static GrB_Info LAGraph_RPQMatrixLor(RPQMatrixPlan *plan, char *msg) { LG_ASSERT(plan != NULL, GrB_NULL_POINTER) ; diff --git a/include/LAGraphX.h b/include/LAGraphX.h index 30deba66d1..ec0f0d2fe7 100644 --- a/include/LAGraphX.h +++ b/include/LAGraphX.h @@ -974,6 +974,16 @@ GrB_Info LAGraph_RPQMatrix_label LAGRAPHX_PUBLIC GrB_Info LAGraph_DestroyRpqMatrixPlan(RPQMatrixPlan *plan) ; +LAGRAPHX_PUBLIC +GrB_Info LAGraph_RPQMatrix_reduce( + GrB_Index *res, + GrB_Matrix mat, + uint8_t reduce_type // reduce_type values: + // 0 --- reduce by row + // 1 --- reduce by col +) ; + + //**************************************************************************** LAGRAPHX_PUBLIC int LAGraph_VertexCentrality_Triangle // vertex triangle-centrality From bc734e7a66d954341d87ed7eb53668bf6a2e8367 Mon Sep 17 00:00:00 2001 From: Rodion Suvorov Date: Mon, 23 Feb 2026 17:26:13 +0300 Subject: [PATCH 34/38] feat: add methods for WanderJoin estimates Signed-off-by: Rodion Suvorov --- experimental/algorithm/LAGraph_RPQMatrix.c | 284 +++++++++++++++++++-- include/LAGraphX.h | 18 ++ 2 files changed, 284 insertions(+), 18 deletions(-) diff --git a/experimental/algorithm/LAGraph_RPQMatrix.c b/experimental/algorithm/LAGraph_RPQMatrix.c index b521b899ac..df42543e03 100644 --- a/experimental/algorithm/LAGraph_RPQMatrix.c +++ b/experimental/algorithm/LAGraph_RPQMatrix.c @@ -111,16 +111,17 @@ #include "LG_internal.h" #include "LAGraphX.h" +#include #include #define OK(s) \ { \ - GrB_Info info = (s); \ + GrB_Info info = (s) ; \ if (info != GrB_SUCCESS) \ { \ - printf("Message: %s\n", msg); \ - fprintf(stderr, "GraphBLAS error: %d (%s, %d)\n", info, __FILE__, __LINE__); \ - return info; \ + printf("Message: %s\n", msg) ; \ + fprintf(stderr, "GraphBLAS error: %d (%s, %d)\n", info, __FILE__, __LINE__) ; \ + return info ; \ } \ } @@ -137,7 +138,7 @@ GrB_Info LAGraph_RPQMatrix_check(RPQMatrixPlan *plan, GrB_Index *dimension, char } if (plan->op == RPQ_MATRIX_OP_LABEL) { - LG_ASSERT(plan->mat != NULL, GrB_NULL_POINTER); + LG_ASSERT(plan->mat != NULL, GrB_NULL_POINTER) ; GrB_Index nrows, ncols ; OK(GrB_Matrix_nrows(&nrows, plan->mat)) ; OK(GrB_Matrix_ncols(&ncols, plan->mat)) ; @@ -166,8 +167,8 @@ GrB_Info LAGraph_RPQMatrix_check(RPQMatrixPlan *plan, GrB_Index *dimension, char return GrB_SUCCESS ; } -static GrB_Semiring sr ; -static GrB_Monoid op ; +static GrB_Semiring sr = GrB_NULL ; +static GrB_Monoid op = GrB_NULL ; GrB_Info LAGraph_RPQMatrix_label(GrB_Matrix *mat, GrB_Index x, GrB_Index i, GrB_Index j) { @@ -199,17 +200,30 @@ GrB_Info LAGraph_RPQMatrix_solver(RPQMatrixPlan *plan, char *msg) ; GrB_Info LAGraph_RPQMatrix_reduce(GrB_Index *res, GrB_Matrix mat, uint8_t reduce_type) { GrB_Index nvals ; - GrB_Vector reduce ; + GrB_Vector reduce = GrB_NULL ; + + GrB_Index nrows ; + OK(GrB_Matrix_nrows(&nrows, mat)) ; + OK(GrB_Vector_new(&reduce, GrB_BOOL, nrows)) ; + if (reduce_type == 0) { - GrB_Matrix_reduce_Monoid(reduce,NULL,NULL,GxB_ANY_BOOL_MONOID,mat,NULL) ; + OK(GrB_reduce(reduce, GrB_NULL, GrB_NULL, op, mat, GrB_NULL)) ; } else if (reduce_type == 1) { - GrB_Matrix_reduce_Monoid(reduce, NULL,NULL,GxB_ANY_BOOL_MONOID,mat,GrB_DESC_T0) ; + OK(GrB_reduce(reduce, GrB_NULL, GrB_NULL, op, mat, GrB_DESC_T0)) ; } - GrB_Vector_nvals(&nvals,reduce) ; + else + { + OK(GrB_Vector_free(&reduce)) ; + return GrB_INVALID_VALUE ; + } + + OK(GrB_Vector_nvals(&nvals, reduce)) ; *res = nvals ; + + OK(GrB_Vector_free(&reduce)) ; return (GrB_SUCCESS) ; } @@ -239,12 +253,21 @@ static GrB_Info LAGraph_RPQMatrixLor(RPQMatrixPlan *plan, char *msg) GrB_Matrix res ; GrB_Matrix_new(&res, GrB_BOOL, dimension, dimension) ; GRB_TRY(GrB_eWiseAdd(res, GrB_NULL, GrB_NULL, - op, lhs_mat, rhs_mat, GrB_DESC_R)) ; + GrB_LOR, lhs_mat, rhs_mat, GrB_DESC_R)) ; plan->res_mat = res ; return (GrB_SUCCESS) ; } +#define abs(a) ((a) > 0.0f ? (a) : (-(a))) + +double error = 0.0 ; +double error2 = 0.0 ; +double c = 0.0 ; + +GrB_Info LAGraph_RPQMatrixEstimate_WanderJoin(GrB_Index *estimate, GrB_Matrix lhs, GrB_Matrix rhs) ; +GrB_Info LAGraph_RPQMatrixEstimate_WanderJoin_Kleene(GrB_Index *estimate, GrB_Matrix rhs) ; + static GrB_Info LAGraph_RPQMatrixConcat(RPQMatrixPlan *plan, char *msg) { @@ -272,6 +295,11 @@ static GrB_Info LAGraph_RPQMatrixConcat(RPQMatrixPlan *plan, char *msg) sr, lhs_mat, rhs_mat, GrB_DESC_R)) ; plan->res_mat = res ; + GrB_Vector ins ; + GrB_Vector_new(&ins, GrB_BOOL, dimension) ; + GrB_Vector outs ; + GrB_Vector_new(&outs, GrB_BOOL, dimension) ; + return (GrB_SUCCESS) ; } @@ -306,8 +334,6 @@ static GrB_Info LAGraph_RPQMatrixKleene(RPQMatrixPlan *plan, char *msg) GRB_TRY(GrB_Matrix_diag(&S, v, 0)) ; - GRB_TRY(GrB_Vector_free(&v)) ; - bool changed = true ; GrB_Index nnz_S = n, nnz_Sold = 0 ; @@ -408,7 +434,6 @@ static GrB_Info LAGraph_RPQMatrixKleene_L(RPQMatrixPlan *plan, char *msg) plan->res_mat = S ; return GrB_SUCCESS ; } - // this function need to handle special case where some optimization // are available. // consider following AST: @@ -484,8 +509,6 @@ static GrB_Info LAGraph_RPQMatrixKleene_R(RPQMatrixPlan *plan, char *msg) return GrB_SUCCESS ; } - - GrB_Info LAGraph_RPQMatrix_solver(RPQMatrixPlan *plan, char *msg) { if (plan->res_mat != NULL) @@ -518,9 +541,14 @@ GrB_Info LAGraph_RPQMatrix_solver(RPQMatrixPlan *plan, char *msg) GrB_Info LAGraph_RPQMatrix_initialize(void) { + if (sr != GrB_NULL) + { + return GrB_SUCCESS ; + } sr = LAGraph_any_one_bool ; op = GxB_ANY_BOOL_MONOID ; - return GrB_SUCCESS; + srand(time(NULL)) ; + return GrB_SUCCESS ; } GrB_Info LAGraph_RPQMatrix( @@ -560,3 +588,223 @@ GrB_Info LAGraph_RPQMatrix( GrB_Matrix_nvals(nnz, plan->res_mat) ; return GrB_SUCCESS ; } + +GrB_Info LAGraph_RPQMatrixOuts (GrB_Vector w, const GrB_Matrix A) { + return GrB_reduce (w, GrB_NULL, GrB_NULL, op, A, GrB_DESC_T0) ; +} +GrB_Info LAGraph_RPQMatrixIns (GrB_Vector w, const GrB_Matrix A) { + return GrB_reduce (w, GrB_NULL, GrB_NULL, op, A, GrB_NULL) ; +} + +#define max(a, b) ((a) >= (b) ? (a) : (b)) +#define min(a, b) ((a) <= (b) ? (a) : (b)) + +GrB_Info LAGraph_RPQMatrixEstimate (float *estimate,float *estimate2, GrB_Vector outs, GrB_Vector ins) { + GrB_Index outc ; + GrB_Index inc ; + + OK (GrB_Vector_nvals(&outc, outs)) ; + OK (GrB_Vector_nvals(&inc, ins)) ; + //printf ("OUTC INC: %llu %llu\n\n", outc, inc) ; + + GrB_Index dimension ; + GrB_Vector_size(&dimension, ins) ; + + GrB_Vector inter; + OK (GrB_Vector_new (&inter, GrB_BOOL, dimension)) ; + GrB_Index interc ; + + OK (GrB_assign(inter, ins, GrB_NULL, outs, GrB_ALL, dimension, GrB_DESC_RS)); + //GxB_print(inter, 2); + + OK (GrB_Vector_nvals(&interc, inter)) ; + + *estimate = ((float) interc) / ((float) max(outc, inc)) / ((float) min(outc, inc)); + *estimate2 = 1 / ((float) max(outc, inc)) ; + + return GrB_SUCCESS ; +} + +#define WANDER_JOIN_FACTOR 8 + +int compare( const void* a, const void* b) +{ + int int_a = * ( (int*) a ); + int int_b = * ( (int*) b ); + + if ( int_a == int_b ) return 0; + else if ( int_a < int_b ) return -1; + else return 1; +} + + +GrB_Info LAGraph_RPQMatrixEstimate_WanderJoin (GrB_Index *estimate, GrB_Matrix lhs, GrB_Matrix rhs) { + // TODO: check if square, of the same dimensions. + + GrB_Index dim ; + GRB_TRY (GrB_Matrix_nrows(&dim, lhs)) ; + GrB_Index nvals ; + GRB_TRY (GrB_Matrix_nvals(&nvals, lhs)) ; + + // nvals = n * n ~> join_factor = n + // nvals = big ~> join_factor = big + // nvals = small ~> join_factor = small + // nvals = 0 ~> join_factor = 1 + GrB_Index join_factor = WANDER_JOIN_FACTOR ; + + GrB_Index sdim = dim / join_factor ; + GrB_Matrix slhs ; + GrB_Matrix srhs ; + GRB_TRY (GrB_Matrix_new(&slhs, GrB_BOOL, sdim, sdim)) ; + GRB_TRY (GrB_Matrix_new(&srhs, GrB_BOOL, sdim, sdim)) ; + + GrB_Index I[sdim] ; + for (size_t i = 0; i < sdim; i++) { + GrB_Index k ; + while (true) { + k = rand() % dim ; + for (size_t j = 0; j < i; j++) { + if (I[j] == k) { + goto skip; + } + } + break; + skip:; + } + I[i] = k ; + } + + GRB_TRY (GrB_extract(slhs, GrB_NULL, GrB_NULL, lhs, I, sdim, I, sdim, GrB_DESC_R)) ; + GRB_TRY (GrB_extract(srhs, GrB_NULL, GrB_NULL, rhs, I, sdim, I, sdim, GrB_DESC_R)) ; + + GrB_Matrix sres ; + GRB_TRY (GrB_Matrix_new(&sres, GrB_BOOL, sdim, sdim)) ; + + GRB_TRY (GrB_mxm(sres, GrB_NULL, GrB_NULL, sr, slhs, srhs, GrB_DESC_R)) ; + + GrB_Index snv ; + GRB_TRY (GrB_Matrix_nvals(&snv, sres)) ; + + *estimate = snv * join_factor * join_factor * join_factor ; + + return GrB_SUCCESS ; +} + +GrB_Info LAGraph_RPQMatrixEstimate_WanderJoin_Kleene (GrB_Index *estimate, GrB_Matrix rhs) { + // TODO: check if square, of the same dimensions. + + GrB_Index dim ; + + GRB_TRY (GrB_Matrix_nrows(&dim, rhs)) ; + + GrB_Index sdim = dim / WANDER_JOIN_FACTOR ; + GrB_Matrix srhs ; + GRB_TRY (GrB_Matrix_new(&srhs, GrB_BOOL, sdim, sdim)) ; + + GrB_Index I[sdim] ; + for (size_t i = 0; i < sdim; i++) { + GrB_Index k ; + while (true) { + k = rand() % dim ; + for (size_t j = 0; j < i; j++) { + if (I[j] == k) { + goto skip; + } + } + break; + skip:; + } + I[i] = k ; + } + + GRB_TRY (GrB_extract(srhs, GrB_NULL, GrB_NULL, rhs, I, sdim, I, sdim, GrB_DESC_R)) ; + + GrB_Matrix S ; + GRB_TRY(GrB_Matrix_dup(&S, srhs)) ; + + bool changed = true ; + GrB_Index nnz_S = 0, nnz_Sold = 0 ; + + while (changed) + { + // S <- S x (B + I) + GRB_TRY(GrB_mxm(S, S, GrB_NULL, + sr, S, srhs, GrB_DESC_C)) ; + + GRB_TRY(GrB_Matrix_nvals(&nnz_S, S)) ; + if (nnz_S != nnz_Sold) + { + changed = true ; + nnz_Sold = nnz_S ; + } + else + { + changed = false ; + } + } + + GrB_Index snv ; + GRB_TRY (GrB_Matrix_nvals(&snv, S)) ; + + *estimate = snv * WANDER_JOIN_FACTOR * WANDER_JOIN_FACTOR * WANDER_JOIN_FACTOR; + + return GrB_SUCCESS ; +} + +static GrB_Index *I = NULL; + +GrB_Info LAGraph_RPQMatrix_Alt (GrB_Matrix lhs, GrB_Matrix rhs, GrB_Matrix *res, uint64_t *nvals) { + GrB_Index sdim; + GRB_TRY (GrB_Matrix_nrows(&sdim, rhs)) ; + + GRB_TRY (GrB_Matrix_new(res, GrB_BOOL, sdim, sdim)) ; + + GRB_TRY(GrB_eWiseAdd(*res, GrB_NULL, GrB_NULL, + op, lhs, rhs, GrB_DESC_R)) ; + + GRB_TRY (GrB_Matrix_nvals(nvals, *res)) ; +} +GrB_Info LAGraph_RPQMatrix_Seq (GrB_Matrix lhs, GrB_Matrix rhs, GrB_Matrix *res, uint64_t *nvals) { + GrB_Index sdim; + GRB_TRY (GrB_Matrix_nrows(&sdim, rhs)) ; + + GRB_TRY (GrB_Matrix_new(res, GrB_BOOL, sdim, sdim)) ; + + GRB_TRY (GrB_mxm(*res, GrB_NULL, GrB_NULL, sr, lhs, rhs, GrB_DESC_R)) ; + + GRB_TRY (GrB_Matrix_nvals(nvals, *res)) ; +} +GrB_Info LAGraph_RPQMatrix_ExtractRandom (GrB_Matrix rhs, GrB_Matrix *srhs, uint64_t seed) { + // TODO: check if square, of the same dimensions. + GrB_Index dim ; + + GRB_TRY (GrB_Matrix_nrows(&dim, rhs)) ; + + GrB_Index sdim = dim / WANDER_JOIN_FACTOR ; + GRB_TRY (GrB_Matrix_new(srhs, GrB_BOOL, sdim, sdim)) ; + + + if (I == NULL) { + srand(seed); + I = calloc(sizeof(GrB_Index), sdim); + + for (size_t i = 0; i < sdim; i++) { + size_t u = rand(); + size_t k = u % WANDER_JOIN_FACTOR + WANDER_JOIN_FACTOR * i; + I[i] = k ; + } + } + + GRB_TRY (GrB_extract(*srhs, GrB_NULL, GrB_NULL, rhs, I, sdim, I, sdim, GrB_DESC_R)) ; + return GrB_SUCCESS ; +} + +/*GrB_Info LAGraph_RPQMatrixEstimateSum(GrB_Index *estimate, RPQMatrix *lhs, RPQMatrix *rhs, char *msg) { + GrB_Index lhs_nvals, rhs_nvals ; + OK (GrB_Matrix_nvals(&lhs_nvals, lhs->m)) ; + OK (GrB_Matrix_nvals(&rhs_nvals, lhs->m)) ; + + *estimate = lhs_nvals + rhs_nvals ; + + return GrB_SUCCESS ; +}*/ diff --git a/include/LAGraphX.h b/include/LAGraphX.h index ec0f0d2fe7..9b0620e740 100644 --- a/include/LAGraphX.h +++ b/include/LAGraphX.h @@ -974,6 +974,24 @@ GrB_Info LAGraph_RPQMatrix_label LAGRAPHX_PUBLIC GrB_Info LAGraph_DestroyRpqMatrixPlan(RPQMatrixPlan *plan) ; +LAGRAPHX_PUBLIC +GrB_Info LAGraph_RPQMatrixOuts (GrB_Vector w, const GrB_Matrix A); + +LAGRAPHX_PUBLIC +GrB_Info LAGraph_RPQMatrixIns (GrB_Vector w, const GrB_Matrix A); + +LAGRAPHX_PUBLIC +GrB_Info LAGraph_RPQMatrixEstimate (float *estimate, float *estimate2, GrB_Vector outs, GrB_Vector ins); + +LAGRAPHX_PUBLIC +GrB_Info LAGraph_RPQMatrix_Alt (GrB_Matrix lhs, GrB_Matrix rhs, GrB_Matrix *res, uint64_t *nvals); + +LAGRAPHX_PUBLIC +GrB_Info LAGraph_RPQMatrix_Seq (GrB_Matrix lhs, GrB_Matrix rhs, GrB_Matrix *res, uint64_t *nvals); + +LAGRAPHX_PUBLIC +GrB_Info LAGraph_RPQMatrix_ExtractRandom (GrB_Matrix rhs, GrB_Matrix *srhs, uint64_t seed); + LAGRAPHX_PUBLIC GrB_Info LAGraph_RPQMatrix_reduce( GrB_Index *res, From b20f305fa3ec62fe7099fd7766c1a4d788df2cbe Mon Sep 17 00:00:00 2001 From: Rodion Suvorov Date: Fri, 6 Mar 2026 12:37:37 +0300 Subject: [PATCH 35/38] wip --- experimental/algorithm/LAGraph_RPQMatrix.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/experimental/algorithm/LAGraph_RPQMatrix.c b/experimental/algorithm/LAGraph_RPQMatrix.c index df42543e03..b67c7e8db3 100644 --- a/experimental/algorithm/LAGraph_RPQMatrix.c +++ b/experimental/algorithm/LAGraph_RPQMatrix.c @@ -208,11 +208,11 @@ GrB_Info LAGraph_RPQMatrix_reduce(GrB_Index *res, GrB_Matrix mat, uint8_t reduce if (reduce_type == 0) { - OK(GrB_reduce(reduce, GrB_NULL, GrB_NULL, op, mat, GrB_NULL)) ; + OK(GrB_reduce(reduce, GrB_NULL, GrB_NULL, GxB_ANY_BOOL_MONOID, mat, GrB_NULL)) ; } else if (reduce_type == 1) { - OK(GrB_reduce(reduce, GrB_NULL, GrB_NULL, op, mat, GrB_DESC_T0)) ; + OK(GrB_reduce(reduce, GrB_NULL, GrB_NULL, GxB_ANY_BOOL_MONOID, mat, GrB_DESC_T0)) ; } else { From ccb2ea7eacd700aeb075b35a7c5722fc19b3de5e Mon Sep 17 00:00:00 2001 From: Rodion Suvorov Date: Sat, 7 Mar 2026 04:23:49 +0300 Subject: [PATCH 36/38] fix memory leak --- experimental/algorithm/LAGraph_RPQMatrix.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/experimental/algorithm/LAGraph_RPQMatrix.c b/experimental/algorithm/LAGraph_RPQMatrix.c index b67c7e8db3..c55dec9d1d 100644 --- a/experimental/algorithm/LAGraph_RPQMatrix.c +++ b/experimental/algorithm/LAGraph_RPQMatrix.c @@ -294,12 +294,6 @@ static GrB_Info LAGraph_RPQMatrixConcat(RPQMatrixPlan *plan, char *msg) GRB_TRY(GrB_mxm(res, GrB_NULL, GrB_NULL, sr, lhs_mat, rhs_mat, GrB_DESC_R)) ; plan->res_mat = res ; - - GrB_Vector ins ; - GrB_Vector_new(&ins, GrB_BOOL, dimension) ; - GrB_Vector outs ; - GrB_Vector_new(&outs, GrB_BOOL, dimension) ; - return (GrB_SUCCESS) ; } @@ -354,6 +348,7 @@ static GrB_Info LAGraph_RPQMatrixKleene(RPQMatrixPlan *plan, char *msg) changed = false ; } } + GrB_Vector_free(&v) ; plan->res_mat = S ; // GRB_TRY(GrB_Matrix_free(&I)) ; From 8acf1c3f67d28da947af6fbeb629e3f97ca3577e Mon Sep 17 00:00:00 2001 From: Rodion Suvorov Date: Sat, 7 Mar 2026 05:20:07 +0300 Subject: [PATCH 37/38] add free --- experimental/algorithm/LAGraph_RPQMatrix.c | 5 +++++ include/LAGraphX.h | 3 +++ 2 files changed, 8 insertions(+) diff --git a/experimental/algorithm/LAGraph_RPQMatrix.c b/experimental/algorithm/LAGraph_RPQMatrix.c index c55dec9d1d..e20e46285e 100644 --- a/experimental/algorithm/LAGraph_RPQMatrix.c +++ b/experimental/algorithm/LAGraph_RPQMatrix.c @@ -170,6 +170,11 @@ GrB_Info LAGraph_RPQMatrix_check(RPQMatrixPlan *plan, GrB_Index *dimension, char static GrB_Semiring sr = GrB_NULL ; static GrB_Monoid op = GrB_NULL ; +GrB_Info LAGraph_RPQMatrix_Free(GrB_Matrix *mat) { + OK(GrB_Matrix_free(mat)); + return GrB_SUCCESS ; +} + GrB_Info LAGraph_RPQMatrix_label(GrB_Matrix *mat, GrB_Index x, GrB_Index i, GrB_Index j) { OK(GrB_Matrix_new(mat, GrB_BOOL, i, j)) ; diff --git a/include/LAGraphX.h b/include/LAGraphX.h index 9b0620e740..5ce373210f 100644 --- a/include/LAGraphX.h +++ b/include/LAGraphX.h @@ -974,6 +974,9 @@ GrB_Info LAGraph_RPQMatrix_label LAGRAPHX_PUBLIC GrB_Info LAGraph_DestroyRpqMatrixPlan(RPQMatrixPlan *plan) ; +LAGRAPHX_PUBLIC +GrB_Info LAGraph_RPQMatrix_Free(GrB_Matrix *mat) ; + LAGRAPHX_PUBLIC GrB_Info LAGraph_RPQMatrixOuts (GrB_Vector w, const GrB_Matrix A); From bc004979161db08389f52e2eff1e84e5cac42a64 Mon Sep 17 00:00:00 2001 From: Rodion Suvorov Date: Sun, 8 Mar 2026 14:56:26 +0300 Subject: [PATCH 38/38] refactor: remove unused wander join methods --- experimental/algorithm/LAGraph_RPQMatrix.c | 229 --------------------- 1 file changed, 229 deletions(-) diff --git a/experimental/algorithm/LAGraph_RPQMatrix.c b/experimental/algorithm/LAGraph_RPQMatrix.c index e20e46285e..75f6a5048a 100644 --- a/experimental/algorithm/LAGraph_RPQMatrix.c +++ b/experimental/algorithm/LAGraph_RPQMatrix.c @@ -264,15 +264,6 @@ static GrB_Info LAGraph_RPQMatrixLor(RPQMatrixPlan *plan, char *msg) return (GrB_SUCCESS) ; } -#define abs(a) ((a) > 0.0f ? (a) : (-(a))) - -double error = 0.0 ; -double error2 = 0.0 ; -double c = 0.0 ; - -GrB_Info LAGraph_RPQMatrixEstimate_WanderJoin(GrB_Index *estimate, GrB_Matrix lhs, GrB_Matrix rhs) ; -GrB_Info LAGraph_RPQMatrixEstimate_WanderJoin_Kleene(GrB_Index *estimate, GrB_Matrix rhs) ; - static GrB_Info LAGraph_RPQMatrixConcat(RPQMatrixPlan *plan, char *msg) { @@ -588,223 +579,3 @@ GrB_Info LAGraph_RPQMatrix( GrB_Matrix_nvals(nnz, plan->res_mat) ; return GrB_SUCCESS ; } - -GrB_Info LAGraph_RPQMatrixOuts (GrB_Vector w, const GrB_Matrix A) { - return GrB_reduce (w, GrB_NULL, GrB_NULL, op, A, GrB_DESC_T0) ; -} -GrB_Info LAGraph_RPQMatrixIns (GrB_Vector w, const GrB_Matrix A) { - return GrB_reduce (w, GrB_NULL, GrB_NULL, op, A, GrB_NULL) ; -} - -#define max(a, b) ((a) >= (b) ? (a) : (b)) -#define min(a, b) ((a) <= (b) ? (a) : (b)) - -GrB_Info LAGraph_RPQMatrixEstimate (float *estimate,float *estimate2, GrB_Vector outs, GrB_Vector ins) { - GrB_Index outc ; - GrB_Index inc ; - - OK (GrB_Vector_nvals(&outc, outs)) ; - OK (GrB_Vector_nvals(&inc, ins)) ; - //printf ("OUTC INC: %llu %llu\n\n", outc, inc) ; - - GrB_Index dimension ; - GrB_Vector_size(&dimension, ins) ; - - GrB_Vector inter; - OK (GrB_Vector_new (&inter, GrB_BOOL, dimension)) ; - GrB_Index interc ; - - OK (GrB_assign(inter, ins, GrB_NULL, outs, GrB_ALL, dimension, GrB_DESC_RS)); - //GxB_print(inter, 2); - - OK (GrB_Vector_nvals(&interc, inter)) ; - - *estimate = ((float) interc) / ((float) max(outc, inc)) / ((float) min(outc, inc)); - *estimate2 = 1 / ((float) max(outc, inc)) ; - - return GrB_SUCCESS ; -} - -#define WANDER_JOIN_FACTOR 8 - -int compare( const void* a, const void* b) -{ - int int_a = * ( (int*) a ); - int int_b = * ( (int*) b ); - - if ( int_a == int_b ) return 0; - else if ( int_a < int_b ) return -1; - else return 1; -} - - -GrB_Info LAGraph_RPQMatrixEstimate_WanderJoin (GrB_Index *estimate, GrB_Matrix lhs, GrB_Matrix rhs) { - // TODO: check if square, of the same dimensions. - - GrB_Index dim ; - GRB_TRY (GrB_Matrix_nrows(&dim, lhs)) ; - GrB_Index nvals ; - GRB_TRY (GrB_Matrix_nvals(&nvals, lhs)) ; - - // nvals = n * n ~> join_factor = n - // nvals = big ~> join_factor = big - // nvals = small ~> join_factor = small - // nvals = 0 ~> join_factor = 1 - GrB_Index join_factor = WANDER_JOIN_FACTOR ; - - GrB_Index sdim = dim / join_factor ; - GrB_Matrix slhs ; - GrB_Matrix srhs ; - GRB_TRY (GrB_Matrix_new(&slhs, GrB_BOOL, sdim, sdim)) ; - GRB_TRY (GrB_Matrix_new(&srhs, GrB_BOOL, sdim, sdim)) ; - - GrB_Index I[sdim] ; - for (size_t i = 0; i < sdim; i++) { - GrB_Index k ; - while (true) { - k = rand() % dim ; - for (size_t j = 0; j < i; j++) { - if (I[j] == k) { - goto skip; - } - } - break; - skip:; - } - I[i] = k ; - } - - GRB_TRY (GrB_extract(slhs, GrB_NULL, GrB_NULL, lhs, I, sdim, I, sdim, GrB_DESC_R)) ; - GRB_TRY (GrB_extract(srhs, GrB_NULL, GrB_NULL, rhs, I, sdim, I, sdim, GrB_DESC_R)) ; - - GrB_Matrix sres ; - GRB_TRY (GrB_Matrix_new(&sres, GrB_BOOL, sdim, sdim)) ; - - GRB_TRY (GrB_mxm(sres, GrB_NULL, GrB_NULL, sr, slhs, srhs, GrB_DESC_R)) ; - - GrB_Index snv ; - GRB_TRY (GrB_Matrix_nvals(&snv, sres)) ; - - *estimate = snv * join_factor * join_factor * join_factor ; - - return GrB_SUCCESS ; -} - -GrB_Info LAGraph_RPQMatrixEstimate_WanderJoin_Kleene (GrB_Index *estimate, GrB_Matrix rhs) { - // TODO: check if square, of the same dimensions. - - GrB_Index dim ; - - GRB_TRY (GrB_Matrix_nrows(&dim, rhs)) ; - - GrB_Index sdim = dim / WANDER_JOIN_FACTOR ; - GrB_Matrix srhs ; - GRB_TRY (GrB_Matrix_new(&srhs, GrB_BOOL, sdim, sdim)) ; - - GrB_Index I[sdim] ; - for (size_t i = 0; i < sdim; i++) { - GrB_Index k ; - while (true) { - k = rand() % dim ; - for (size_t j = 0; j < i; j++) { - if (I[j] == k) { - goto skip; - } - } - break; - skip:; - } - I[i] = k ; - } - - GRB_TRY (GrB_extract(srhs, GrB_NULL, GrB_NULL, rhs, I, sdim, I, sdim, GrB_DESC_R)) ; - - GrB_Matrix S ; - GRB_TRY(GrB_Matrix_dup(&S, srhs)) ; - - bool changed = true ; - GrB_Index nnz_S = 0, nnz_Sold = 0 ; - - while (changed) - { - // S <- S x (B + I) - GRB_TRY(GrB_mxm(S, S, GrB_NULL, - sr, S, srhs, GrB_DESC_C)) ; - - GRB_TRY(GrB_Matrix_nvals(&nnz_S, S)) ; - if (nnz_S != nnz_Sold) - { - changed = true ; - nnz_Sold = nnz_S ; - } - else - { - changed = false ; - } - } - - GrB_Index snv ; - GRB_TRY (GrB_Matrix_nvals(&snv, S)) ; - - *estimate = snv * WANDER_JOIN_FACTOR * WANDER_JOIN_FACTOR * WANDER_JOIN_FACTOR; - - return GrB_SUCCESS ; -} - -static GrB_Index *I = NULL; - -GrB_Info LAGraph_RPQMatrix_Alt (GrB_Matrix lhs, GrB_Matrix rhs, GrB_Matrix *res, uint64_t *nvals) { - GrB_Index sdim; - GRB_TRY (GrB_Matrix_nrows(&sdim, rhs)) ; - - GRB_TRY (GrB_Matrix_new(res, GrB_BOOL, sdim, sdim)) ; - - GRB_TRY(GrB_eWiseAdd(*res, GrB_NULL, GrB_NULL, - op, lhs, rhs, GrB_DESC_R)) ; - - GRB_TRY (GrB_Matrix_nvals(nvals, *res)) ; -} -GrB_Info LAGraph_RPQMatrix_Seq (GrB_Matrix lhs, GrB_Matrix rhs, GrB_Matrix *res, uint64_t *nvals) { - GrB_Index sdim; - GRB_TRY (GrB_Matrix_nrows(&sdim, rhs)) ; - - GRB_TRY (GrB_Matrix_new(res, GrB_BOOL, sdim, sdim)) ; - - GRB_TRY (GrB_mxm(*res, GrB_NULL, GrB_NULL, sr, lhs, rhs, GrB_DESC_R)) ; - - GRB_TRY (GrB_Matrix_nvals(nvals, *res)) ; -} -GrB_Info LAGraph_RPQMatrix_ExtractRandom (GrB_Matrix rhs, GrB_Matrix *srhs, uint64_t seed) { - // TODO: check if square, of the same dimensions. - GrB_Index dim ; - - GRB_TRY (GrB_Matrix_nrows(&dim, rhs)) ; - - GrB_Index sdim = dim / WANDER_JOIN_FACTOR ; - GRB_TRY (GrB_Matrix_new(srhs, GrB_BOOL, sdim, sdim)) ; - - - if (I == NULL) { - srand(seed); - I = calloc(sizeof(GrB_Index), sdim); - - for (size_t i = 0; i < sdim; i++) { - size_t u = rand(); - size_t k = u % WANDER_JOIN_FACTOR + WANDER_JOIN_FACTOR * i; - I[i] = k ; - } - } - - GRB_TRY (GrB_extract(*srhs, GrB_NULL, GrB_NULL, rhs, I, sdim, I, sdim, GrB_DESC_R)) ; - return GrB_SUCCESS ; -} - -/*GrB_Info LAGraph_RPQMatrixEstimateSum(GrB_Index *estimate, RPQMatrix *lhs, RPQMatrix *rhs, char *msg) { - GrB_Index lhs_nvals, rhs_nvals ; - OK (GrB_Matrix_nvals(&lhs_nvals, lhs->m)) ; - OK (GrB_Matrix_nvals(&rhs_nvals, lhs->m)) ; - - *estimate = lhs_nvals + rhs_nvals ; - - return GrB_SUCCESS ; -}*/