From c76663fb0aa1bef286d546ce17fb6c8d358d0dcd Mon Sep 17 00:00:00 2001 From: Rodion Suvorov Date: Sun, 20 Jul 2025 14:00:11 +0300 Subject: [PATCH 01/28] 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/28] 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/28] 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/28] 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/28] 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/28] 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/28] 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/28] 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/28] 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/28] 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/28] 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/28] 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/28] 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/28] 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/28] 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/28] 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/28] 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/28] 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/28] 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/28] 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/28] 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/28] 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/28] 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/28] 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/28] 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/28] 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/28] 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/28] 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; }