diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml index 5b2a5a924..c11d2e8a6 100644 --- a/.github/workflows/coverage.yml +++ b/.github/workflows/coverage.yml @@ -46,18 +46,25 @@ jobs: - name: Build run: | - rustup toolchain list rustup default nightly apt-get update - apt-get install -y clang libomp-dev libc6-dbg python3-venv + apt-get install -y lsb-release wget software-properties-common gnupg + wget https://apt.llvm.org/llvm.sh + chmod +x llvm.sh + ./llvm.sh 17 + apt-get update + apt-get install -y libomp-17-dev libc6-dbg python3-venv python3 -m venv venv . venv/bin/activate pip install -r tests/requirements.txt - apt update && apt install lsb-release -y curl -fsSL https://packages.redis.io/gpg | gpg --dearmor -o /usr/share/keyrings/redis-archive-keyring.gpg && \ echo "deb [signed-by=/usr/share/keyrings/redis-archive-keyring.gpg] https://packages.redis.io/deb $(lsb_release -cs) main" | tee /etc/apt/sources.list.d/redis.list apt update && apt install redis -y - make coverage NPROC=16 + update-alternatives \ + --verbose \ + --install /usr/bin/clang clang /usr/bin/clang-17 100 \ + --slave /usr/bin/clang++ clang++ /usr/bin/clang++-17 + make coverage NPROC=16 CLANG=1 continue-on-error: true - name: Upload coverage reports to Codecov diff --git a/.github/workflows/sanitize.yml b/.github/workflows/sanitize.yml index 4f873be2c..4b0ab4542 100644 --- a/.github/workflows/sanitize.yml +++ b/.github/workflows/sanitize.yml @@ -46,13 +46,21 @@ jobs: - name: Build run: | - rustup toolchain list rustup default nightly apt-get update - apt-get install -y clang libomp-dev libc6-dbg python3-venv + apt-get install -y lsb-release wget software-properties-common gnupg + wget https://apt.llvm.org/llvm.sh + chmod +x llvm.sh + ./llvm.sh 17 + apt-get update + apt-get install -y libomp-17-dev libc6-dbg python3-venv python3 -m venv venv . venv/bin/activate pip install -r tests/requirements.txt + update-alternatives \ + --verbose \ + --install /usr/bin/clang clang /usr/bin/clang-17 100 \ + --slave /usr/bin/clang++ clang++ /usr/bin/clang++-17 make CLANG=1 SAN=address NPROC=16 - name: Unit tests diff --git a/CMakeLists.txt b/CMakeLists.txt index 137351109..5cb469110 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -53,7 +53,7 @@ set(FALKORDB_OBJECTS $) find_package(OpenSSL) lists_from_env(GRAPHBLAS LIBXXHASH RAX LIBCYPHER_PARSER REDISEARCH_LIBS UTF8PROC ONIGURUMA FalkorDBRS) -set(FALKORDB_LIBS ${GRAPHBLAS} ${LIBXXHASH} ${RAX} ${LIBCYPHER_PARSER} ${REDISEARCH_LIBS} ${UTF8PROC} ${ONIGURUMA} ${FalkorDBRS} OpenSSL::SSL) +set(FALKORDB_LIBS ${FalkorDBRS} ${GRAPHBLAS} ${LIBXXHASH} ${RAX} ${LIBCYPHER_PARSER} ${REDISEARCH_LIBS} ${UTF8PROC} ${ONIGURUMA} OpenSSL::SSL) target_link_options(falkordb PRIVATE ${CMAKE_LD_FLAGS_LIST} ${CMAKE_SO_LD_FLAGS_LIST}) target_link_libraries(falkordb PRIVATE ${FALKORDB_LIBS} ${CMAKE_LD_LIBS}) diff --git a/Makefile b/Makefile index 962c517e5..4a909329e 100644 --- a/Makefile +++ b/Makefile @@ -281,6 +281,10 @@ export RUSTFLAGS=-Zsanitizer=$(SAN) CARGO_FLAGS=--target x86_64-unknown-linux-gnu endif +ifneq ($(COV),) +export RUSTFLAGS=-C instrument-coverage +endif + falkordbrs: @echo Building $@ ... cd deps/FalkorDB-core-rs && cargo build $(CARGO_FLAGS) --features falkordb_allocator --target-dir $(FalkorDBRS_BINDIR) @@ -367,6 +371,7 @@ ifneq ($(BUILD),0) $(SHOW)$(MAKE) build FORCE=1 UNIT_TESTS=1 endif $(SHOW)BINROOT=$(BINROOT) ./tests/unit/tests.sh + $(SHOW)BINROOT=$(BINROOT) cargo test --lib -vv flow-tests: $(TEST_DEPS) $(SHOW)MODULE=$(TARGET) BINROOT=$(BINROOT) PARALLEL=$(_RLTEST_PARALLEL) GEN=$(GEN) AOF=$(AOF) TCK=0 ./tests/flow/tests.sh @@ -408,7 +413,13 @@ benchmark: $(TARGET) #---------------------------------------------------------------------------------------------- COV_EXCLUDE_DIRS += \ - deps \ + deps/GraphBLAS \ + deps/libcypher-parser \ + deps/oniguruma \ + deps/rax \ + deps/RediSearch \ + deps/utf8proc \ + deps/xxHash \ src/util/sds \ tests diff --git a/codecov.yml b/codecov.yml index af9a01ad3..b8b3d718e 100644 --- a/codecov.yml +++ b/codecov.yml @@ -1,5 +1,11 @@ ignore: - - "deps" + - "deps/GraphBLAS" + - "deps/libcypher-parser" + - "deps/oniguruma" + - "deps/rax" + - "deps/RediSearch" + - "deps/utf8proc" + - "deps/xxHash" - "src/util/sds" - "src/util/roaring.c" - "tests" \ No newline at end of file diff --git a/deps/FalkorDB-core-rs b/deps/FalkorDB-core-rs index dcd9b1bf4..cf26aae5e 160000 --- a/deps/FalkorDB-core-rs +++ b/deps/FalkorDB-core-rs @@ -1 +1 @@ -Subproject commit dcd9b1bf498540d5bb003f2ec2d829d6de5e11c4 +Subproject commit cf26aae5e4d7087c9fce8d11d53b9809bafc69ad diff --git a/src/algorithms/all_neighbors.c b/src/algorithms/all_neighbors.c index 8c59a19bd..ac99df9bb 100644 --- a/src/algorithms/all_neighbors.c +++ b/src/algorithms/all_neighbors.c @@ -16,11 +16,11 @@ static void _AllNeighborsCtx_CollectNeighbors ) { ctx->current_level++; if(ctx->current_level == array_len(ctx->levels)) { - RG_MatrixTupleIter iter = {0}; - RG_MatrixTupleIter_AttachRange(&iter, ctx->M, id, id); + Delta_MatrixTupleIter iter = {0}; + Delta_MatrixTupleIter_AttachRange(&iter, ctx->M, id, id); array_append(ctx->levels, iter); } else { - RG_MatrixTupleIter_iterate_row(&ctx->levels[ctx->current_level], id); + Delta_MatrixTupleIter_iterate_row(&ctx->levels[ctx->current_level], id); } } @@ -28,7 +28,7 @@ void AllNeighborsCtx_Reset ( AllNeighborsCtx *ctx, // all neighbors context to reset EntityID src, // source node from which to traverse - RG_Matrix M, // matrix describing connections + Delta_Matrix M, // matrix describing connections uint minLen, // minimum traversal depth uint maxLen // maximum traversal depth ) { @@ -53,15 +53,15 @@ void AllNeighborsCtx_Reset ctx->visited_nodes = HashTableCreate(&def_dt); // dummy iterator at level 0 - array_append(ctx->levels, (RG_MatrixTupleIter) {0}); + array_append(ctx->levels, (Delta_MatrixTupleIter) {0}); } AllNeighborsCtx *AllNeighborsCtx_New ( - EntityID src, // source node from which to traverse - RG_Matrix M, // matrix describing connections - uint minLen, // minimum traversal depth - uint maxLen // maximum traversal depth + EntityID src, // source node from which to traverse + Delta_Matrix M, // matrix describing connections + uint minLen, // minimum traversal depth + uint maxLen // maximum traversal depth ) { ASSERT(M != NULL); ASSERT(src != INVALID_ENTITY_ID); @@ -72,14 +72,14 @@ AllNeighborsCtx *AllNeighborsCtx_New ctx->src = src; ctx->minLen = minLen; ctx->maxLen = maxLen; - ctx->levels = array_new(RG_MatrixTupleIter, 1); + ctx->levels = array_new(Delta_MatrixTupleIter, 1); ctx->visited = array_new(EntityID, 1); ctx->first_pull = true; ctx->current_level = 0; ctx->visited_nodes = HashTableCreate(&def_dt); // Dummy iterator at level 0 - array_append(ctx->levels, (RG_MatrixTupleIter) {0}); + array_append(ctx->levels, (Delta_MatrixTupleIter) {0}); return ctx; } @@ -112,10 +112,10 @@ EntityID AllNeighborsCtx_NextNeighbor while(ctx->current_level > 0) { ASSERT(ctx->current_level < array_len(ctx->levels)); - RG_MatrixTupleIter *it = &ctx->levels[ctx->current_level]; + Delta_MatrixTupleIter *it = &ctx->levels[ctx->current_level]; GrB_Index dest_id; - GrB_Info info = RG_MatrixTupleIter_next_UINT64(it, NULL, &dest_id, NULL); + GrB_Info info = Delta_MatrixTupleIter_next_BOOL(it, NULL, &dest_id, NULL); if(info == GxB_EXHAUSTED) { // backtrack @@ -160,7 +160,7 @@ void AllNeighborsCtx_Free uint count = array_len(ctx->levels); for (uint i = 0; i < count; i++) { - RG_MatrixTupleIter_detach(ctx->levels + i); + Delta_MatrixTupleIter_detach(ctx->levels + i); } array_free(ctx->levels); array_free(ctx->visited); diff --git a/src/algorithms/all_neighbors.h b/src/algorithms/all_neighbors.h index cba920159..753fb7a51 100644 --- a/src/algorithms/all_neighbors.h +++ b/src/algorithms/all_neighbors.h @@ -8,8 +8,8 @@ #include "../../deps/GraphBLAS/Include/GraphBLAS.h" #include "../util/dict.h" -#include "../graph/rg_matrix/rg_matrix.h" -#include "../graph/rg_matrix/rg_matrix_iter.h" +#include "../graph/delta_matrix/delta_matrix.h" +#include "../graph/delta_matrix/delta_matrix_iter.h" #include "../graph/entities/node.h" // performs iterative DFS from 'src' @@ -22,32 +22,32 @@ // current path typedef struct { - EntityID src; // traverse begin here - RG_Matrix M; // adjacency matrix - uint minLen; // minimum required depth - uint maxLen; // maximum allowed depth - int current_level; // current depth - bool first_pull; // first call to Next - EntityID *visited; // visited nodes - RG_MatrixTupleIter *levels; // array of neighbors iterator - dict *visited_nodes; // visited nodes + EntityID src; // traverse begin here + Delta_Matrix M; // adjacency matrix + uint minLen; // minimum required depth + uint maxLen; // maximum allowed depth + int current_level; // current depth + bool first_pull; // first call to Next + EntityID *visited; // visited nodes + Delta_MatrixTupleIter *levels; // array of neighbors iterator + dict *visited_nodes; // visited nodes } AllNeighborsCtx; void AllNeighborsCtx_Reset ( AllNeighborsCtx *ctx, // all neighbors context to reset EntityID src, // source node from which to traverse - RG_Matrix M, // matrix describing connections + Delta_Matrix M, // matrix describing connections uint minLen, // minimum traversal depth uint maxLen // maximum traversal depth ); AllNeighborsCtx *AllNeighborsCtx_New ( - EntityID src, // source node from which to traverse - RG_Matrix M, // matrix describing connections - uint minLen, // minimum traversal depth - uint maxLen // maximum traversal depth + EntityID src, // source node from which to traverse + Delta_Matrix M, // matrix describing connections + uint minLen, // minimum traversal depth + uint maxLen // maximum traversal depth ); // produce next reachable destination node diff --git a/src/arithmetic/algebraic_expression.h b/src/arithmetic/algebraic_expression.h index 1fd4deeaa..4abde25e1 100644 --- a/src/arithmetic/algebraic_expression.h +++ b/src/arithmetic/algebraic_expression.h @@ -9,7 +9,7 @@ #include "../graph/graph.h" #include "../graph/query_graph.h" -static RG_Matrix IDENTITY_MATRIX = (RG_Matrix)0x31032017; // identity matrix +static Delta_Matrix IDENTITY_MATRIX = (Delta_Matrix)0x31032017; // identity matrix // Matrix, vector operations typedef enum { @@ -40,7 +40,7 @@ struct AlgebraicExpression { const char *dest; // alias given to operand's columns const char *edge; // alias given to operand (edge) const char *label; // label attached to matrix - RG_Matrix matrix; // matrix + Delta_Matrix matrix; // matrix } operand; struct { AL_EXP_OP op; // operation: `*`,`+`,`transpose` @@ -72,7 +72,7 @@ AlgebraicExpression *AlgebraicExpression_NewOperation // Create a new AlgebraicExpression operand node. AlgebraicExpression *AlgebraicExpression_NewOperand ( - RG_Matrix mat, // Matrix. + Delta_Matrix mat, // Matrix. bool diagonal, // Is operand a diagonal matrix? const char *src, // Operand row domain (src node). const char *dest, // Operand column domain (destination node). @@ -185,7 +185,7 @@ AlgebraicExpression *AlgebraicExpression_RemoveDest void AlgebraicExpression_MultiplyToTheLeft ( AlgebraicExpression **root, - RG_Matrix m + Delta_Matrix m ); // Multiply expression to the right by operand @@ -193,7 +193,7 @@ void AlgebraicExpression_MultiplyToTheLeft void AlgebraicExpression_MultiplyToTheRight ( AlgebraicExpression **root, - RG_Matrix m + Delta_Matrix m ); // Add expression to the left by operand @@ -201,7 +201,7 @@ void AlgebraicExpression_MultiplyToTheRight void AlgebraicExpression_AddToTheLeft ( AlgebraicExpression **root, - RG_Matrix m + Delta_Matrix m ); // Add expression to the right by operand @@ -209,7 +209,7 @@ void AlgebraicExpression_AddToTheLeft void AlgebraicExpression_AddToTheRight ( AlgebraicExpression **root, - RG_Matrix m + Delta_Matrix m ); // Transpose expression @@ -220,10 +220,10 @@ void AlgebraicExpression_Transpose ); // Evaluate expression tree. -RG_Matrix AlgebraicExpression_Eval +Delta_Matrix AlgebraicExpression_Eval ( const AlgebraicExpression *exp, // Root node - RG_Matrix res // Result output + Delta_Matrix res // Result output ); // locates operand based on row,column domain and edge or label diff --git a/src/arithmetic/algebraic_expression/algebraic_expression.c b/src/arithmetic/algebraic_expression/algebraic_expression.c index 977dfa11a..41479581d 100644 --- a/src/arithmetic/algebraic_expression/algebraic_expression.c +++ b/src/arithmetic/algebraic_expression/algebraic_expression.c @@ -171,7 +171,7 @@ AlgebraicExpression *AlgebraicExpression_NewOperation // Create a new AlgebraicExpression operand node AlgebraicExpression *AlgebraicExpression_NewOperand ( - RG_Matrix mat, // Matrix + Delta_Matrix mat, // Matrix bool diagonal, // Is operand a diagonal matrix? const char *src, // Operand row domain (src node) const char *dest, // Operand column domain (destination node) @@ -490,7 +490,7 @@ AlgebraicExpression *AlgebraicExpression_RemoveDest void AlgebraicExpression_MultiplyToTheLeft ( AlgebraicExpression **root, - RG_Matrix m + Delta_Matrix m ) { ASSERT(root && m); AlgebraicExpression *rhs = *root; @@ -508,7 +508,7 @@ void AlgebraicExpression_MultiplyToTheLeft void AlgebraicExpression_MultiplyToTheRight ( AlgebraicExpression **root, - RG_Matrix m + Delta_Matrix m ) { ASSERT(root && m); AlgebraicExpression *lhs = *root; @@ -526,7 +526,7 @@ void AlgebraicExpression_MultiplyToTheRight void AlgebraicExpression_AddToTheLeft ( AlgebraicExpression **root, - RG_Matrix m + Delta_Matrix m ) { ASSERT(root && m); AlgebraicExpression *rhs = *root; @@ -545,7 +545,7 @@ void AlgebraicExpression_AddToTheLeft void AlgebraicExpression_AddToTheRight ( AlgebraicExpression **root, - RG_Matrix m + Delta_Matrix m ) { ASSERT(root && m); AlgebraicExpression *lhs = *root; diff --git a/src/arithmetic/algebraic_expression/algebraic_expression_add.c b/src/arithmetic/algebraic_expression/algebraic_expression_add.c index 1d0068ec4..22bcf3c9c 100644 --- a/src/arithmetic/algebraic_expression/algebraic_expression_add.c +++ b/src/arithmetic/algebraic_expression/algebraic_expression_add.c @@ -8,10 +8,10 @@ #include "../../query_ctx.h" #include "../algebraic_expression.h" -RG_Matrix _Eval_Add +Delta_Matrix _Eval_Add ( const AlgebraicExpression *exp, - RG_Matrix res + Delta_Matrix res ) { ASSERT(exp); ASSERT(AlgebraicExpression_ChildCount(exp) > 1); @@ -22,9 +22,9 @@ RG_Matrix _Eval_Add GrB_Index ncols; // number of columns of operand bool res_in_use = false; // can we use `res` for intermediate evaluation - RG_Matrix A = NULL; // left operand - RG_Matrix B = NULL; // right operand - RG_Matrix inter = NULL; // intermediate matrix + Delta_Matrix A = NULL; // left operand + Delta_Matrix B = NULL; // right operand + Delta_Matrix inter = NULL; // intermediate matrix // get left and right operands AlgebraicExpression *left = CHILD_AT(exp, 0); @@ -45,9 +45,9 @@ RG_Matrix _Eval_Add if(right->type == AL_OPERATION) { if(res_in_use) { // `res` is in use, create an additional matrix - RG_Matrix_nrows(&nrows, res); - RG_Matrix_ncols(&ncols, res); - info = RG_Matrix_new(&inter, GrB_BOOL, nrows, ncols); + Delta_Matrix_nrows(&nrows, res); + Delta_Matrix_ncols(&ncols, res); + info = Delta_Matrix_new(&inter, GrB_BOOL, nrows, ncols, false); ASSERT(info == GrB_SUCCESS); B = AlgebraicExpression_Eval(right, inter); } else { @@ -62,7 +62,7 @@ RG_Matrix _Eval_Add // perform addition //-------------------------------------------------------------------------- - info = RG_eWiseAdd(res, GxB_ANY_PAIR_BOOL, A, B); + info = Delta_eWiseAdd(res, GxB_ANY_PAIR_BOOL, A, B); ASSERT(info == GrB_SUCCESS); uint child_count = AlgebraicExpression_ChildCount(exp); @@ -76,9 +76,9 @@ RG_Matrix _Eval_Add // 'right' represents either + or * operation if(inter == NULL) { // can't use `res`, use an intermidate matrix - RG_Matrix_nrows(&nrows, res); - RG_Matrix_ncols(&ncols, res); - info = RG_Matrix_new(&inter, GrB_BOOL, nrows, ncols); + Delta_Matrix_nrows(&nrows, res); + Delta_Matrix_ncols(&ncols, res); + info = Delta_Matrix_new(&inter, GrB_BOOL, nrows, ncols, false); ASSERT(info == GrB_SUCCESS); } AlgebraicExpression_Eval(right, inter); @@ -86,11 +86,11 @@ RG_Matrix _Eval_Add } // perform addition - info = RG_eWiseAdd(res, GxB_ANY_PAIR_BOOL, res, B); + info = Delta_eWiseAdd(res, GxB_ANY_PAIR_BOOL, res, B); ASSERT(info == GrB_SUCCESS); } - if(inter != NULL) RG_Matrix_free(&inter); + if(inter != NULL) Delta_Matrix_free(&inter); return res; } diff --git a/src/arithmetic/algebraic_expression/algebraic_expression_debug.c b/src/arithmetic/algebraic_expression/algebraic_expression_debug.c index 93c308faa..197adb750 100644 --- a/src/arithmetic/algebraic_expression/algebraic_expression_debug.c +++ b/src/arithmetic/algebraic_expression/algebraic_expression_debug.c @@ -30,7 +30,7 @@ AlgebraicExpression *_AlgebraicExpression_FromString int len = 0; char *alias; const char *operand; - RG_Matrix m; + Delta_Matrix m; AlgebraicExpression *op; AlgebraicExpression *rhs; AlgebraicExpression *root = NULL; @@ -83,7 +83,7 @@ AlgebraicExpression *_AlgebraicExpression_FromString m = NULL; if(matrices) { - m = (RG_Matrix)raxFind(matrices, (unsigned char *)alias, strlen(alias)); + m = (Delta_Matrix)raxFind(matrices, (unsigned char *)alias, strlen(alias)); ASSERT(m != raxNotFound && "Missing matrix"); } root = AlgebraicExpression_NewOperand(m, false, alias, alias, NULL, NULL); diff --git a/src/arithmetic/algebraic_expression/algebraic_expression_eval.c b/src/arithmetic/algebraic_expression/algebraic_expression_eval.c index 12476bcc8..d1c309c0f 100644 --- a/src/arithmetic/algebraic_expression/algebraic_expression_eval.c +++ b/src/arithmetic/algebraic_expression/algebraic_expression_eval.c @@ -9,28 +9,28 @@ #include "../algebraic_expression.h" // forward declarations -RG_Matrix _AlgebraicExpression_Eval +Delta_Matrix _AlgebraicExpression_Eval ( const AlgebraicExpression *exp, - RG_Matrix res + Delta_Matrix res ); -RG_Matrix _Eval_Mul +Delta_Matrix _Eval_Mul ( const AlgebraicExpression *exp, - RG_Matrix res + Delta_Matrix res ); -RG_Matrix _Eval_Add +Delta_Matrix _Eval_Add ( const AlgebraicExpression *exp, - RG_Matrix res + Delta_Matrix res ); -RG_Matrix _AlgebraicExpression_Eval +Delta_Matrix _AlgebraicExpression_Eval ( const AlgebraicExpression *exp, - RG_Matrix res + Delta_Matrix res ) { ASSERT(exp); @@ -64,10 +64,10 @@ RG_Matrix _AlgebraicExpression_Eval return res; } -RG_Matrix AlgebraicExpression_Eval +Delta_Matrix AlgebraicExpression_Eval ( const AlgebraicExpression *exp, - RG_Matrix res + Delta_Matrix res ) { ASSERT(exp != NULL); return _AlgebraicExpression_Eval(exp, res); diff --git a/src/arithmetic/algebraic_expression/algebraic_expression_mul.c b/src/arithmetic/algebraic_expression/algebraic_expression_mul.c index 6de8e6fb3..572a12bca 100644 --- a/src/arithmetic/algebraic_expression/algebraic_expression_mul.c +++ b/src/arithmetic/algebraic_expression/algebraic_expression_mul.c @@ -8,10 +8,10 @@ #include "../../query_ctx.h" #include "../algebraic_expression.h" -RG_Matrix _Eval_Mul +Delta_Matrix _Eval_Mul ( const AlgebraicExpression *exp, - RG_Matrix res + Delta_Matrix res ) { //-------------------------------------------------------------------------- // validate expression @@ -22,13 +22,13 @@ RG_Matrix _Eval_Mul ASSERT(AlgebraicExpression_OperationCount(exp, AL_EXP_MUL) == 1) ; GrB_Info info ; - RG_Matrix M ; // current operand + Delta_Matrix M ; // current operand GrB_Index nvals ; // NNZ in res AlgebraicExpression *c ; // current child node UNUSED(info) ; - RG_Matrix A = NULL ; + Delta_Matrix A = NULL ; bool res_modified = false ; GrB_Semiring semiring = GxB_ANY_PAIR_BOOL ; uint child_count = AlgebraicExpression_ChildCount(exp) ; @@ -46,19 +46,19 @@ RG_Matrix _Eval_Mul } // both A and M are valid matrices, perform multiplication - info = RG_mxm(res, semiring, A, M) ; + info = Delta_mxm(res, semiring, A, M) ; res_modified = true ; // setup for next iteration A = res ; // exit early if 'res' is empty 0 * A = 0 - info = RG_Matrix_nvals(&nvals, res); + info = Delta_Matrix_nvals(&nvals, res); ASSERT(info == GrB_SUCCESS) ; if(nvals == 0) break ; } if(!res_modified) { - info = RG_Matrix_copy(res, A) ; + info = Delta_Matrix_copy(res, A) ; ASSERT(info == GrB_SUCCESS) ; } diff --git a/src/arithmetic/algebraic_expression/utils.c b/src/arithmetic/algebraic_expression/utils.c index 7e19cc9ec..a9fbf20bf 100644 --- a/src/arithmetic/algebraic_expression/utils.c +++ b/src/arithmetic/algebraic_expression/utils.c @@ -203,7 +203,7 @@ void _AlgebraicExpression_FreeOperand ) { ASSERT(node && node->type == AL_OPERAND); if(node->operand.bfree) { - RG_Matrix_free(&node->operand.matrix); + Delta_Matrix_free(&node->operand.matrix); } } @@ -257,7 +257,7 @@ static void _AlgebraicExpression_PopulateOperand(AlgebraicExpression *operand, Graph *g = gc->g; Schema *s = NULL; - RG_Matrix m = NULL; + Delta_Matrix m = NULL; const char *label = operand->operand.label; if(label == NULL) { @@ -298,7 +298,7 @@ static void _AlgebraicExpression_PopulateTransposedOperand(AlgebraicExpression * if(operand->operand.matrix != NULL) return; Schema *s = NULL; - RG_Matrix m = NULL; + Delta_Matrix m = NULL; const char *label = operand->operand.label; if(label == NULL) { diff --git a/src/arithmetic/entity_funcs/entity_funcs.c b/src/arithmetic/entity_funcs/entity_funcs.c index 247d750c8..21f6563fa 100644 --- a/src/arithmetic/entity_funcs/entity_funcs.c +++ b/src/arithmetic/entity_funcs/entity_funcs.c @@ -75,10 +75,10 @@ SIValue AR_HAS_LABELS(SIValue *argv, int argc, void *private_data) { // validate label is set bool x; - RG_Matrix M = Graph_GetLabelMatrix(g, Schema_GetID(s)); + Delta_Matrix M = Graph_GetLabelMatrix(g, Schema_GetID(s)); ASSERT(M != NULL); - if(RG_Matrix_extractElement_BOOL(&x, M, id, id) == GrB_NO_VALUE) { + if(Delta_Matrix_extractElement_BOOL(&x, M, id, id) == GrB_NO_VALUE) { res = false; break; } diff --git a/src/arithmetic/path_funcs/path_funcs.c b/src/arithmetic/path_funcs/path_funcs.c index 96752d987..d7d7f4c4e 100644 --- a/src/arithmetic/path_funcs/path_funcs.c +++ b/src/arithmetic/path_funcs/path_funcs.c @@ -162,18 +162,18 @@ SIValue AR_SHORTEST_PATH(SIValue *argv, int argc, void *private_data) { if(ctx->reltypes == NULL) { // No edge types were specified, use the overall adjacency matrix. ctx->free_matrices = true; - res = RG_Matrix_export(&ctx->R, Graph_GetAdjacencyMatrix(gc->g, + res = Delta_Matrix_export(&ctx->R, Graph_GetAdjacencyMatrix(gc->g, false)); ASSERT(res == GrB_SUCCESS); } else if(ctx->reltype_count == 0) { // If edge types were specified but none were valid, // use the zero matrix ctx->free_matrices = true; - res = RG_Matrix_export(&ctx->R, Graph_GetZeroMatrix(gc->g)); + res = Delta_Matrix_export(&ctx->R, Graph_GetZeroMatrix(gc->g)); ASSERT(res == GrB_SUCCESS); } else if(ctx->reltype_count == 1) { ctx->free_matrices = true; - res = RG_Matrix_export(&ctx->R, Graph_GetRelationMatrix(gc->g, + res = Delta_Matrix_export(&ctx->R, Graph_GetRelationMatrix(gc->g, ctx->reltypes[0], false)); ASSERT(res == GrB_SUCCESS); } else { @@ -185,7 +185,7 @@ SIValue AR_SHORTEST_PATH(SIValue *argv, int argc, void *private_data) { for(uint i = 0; i < ctx->reltype_count; i ++) { GrB_Matrix adj; - res = RG_Matrix_export(&adj, Graph_GetRelationMatrix(gc->g, + res = Delta_Matrix_export(&adj, Graph_GetRelationMatrix(gc->g, ctx->reltypes[i], false)); ASSERT(res == GrB_SUCCESS); res = GrB_eWiseAdd(ctx->R, GrB_NULL, GrB_NULL, diff --git a/src/bulk_insert/bulk_insert.c b/src/bulk_insert/bulk_insert.c index 039c0d84b..1230f41de 100644 --- a/src/bulk_insert/bulk_insert.c +++ b/src/bulk_insert/bulk_insert.c @@ -40,15 +40,15 @@ static int* _BulkInsert_ReadHeaderLabels ASSERT(data != NULL); ASSERT(data_idx != NULL); - // first sequence is entity label(s) - const char* labels = data + *data_idx; - int labels_len = strlen(labels); - *data_idx += labels_len + 1; + // first sequence is entity label(s) + const char* labels = data + *data_idx; + int labels_len = strlen(labels); + *data_idx += labels_len + 1; - // array of all label IDs - int* label_ids = array_new(int, 1); - // stack variable to contain a single label - char label[labels_len + 1]; + // array of all label IDs + int* label_ids = array_new(int, 1); + // stack variable to contain a single label + char label[labels_len + 1]; while (true) { // look for a colon delimiting another label @@ -82,7 +82,7 @@ static int* _BulkInsert_ReadHeaderLabels if (!found) break; } - return label_ids; + return label_ids; } // read the property keys from a header @@ -99,15 +99,15 @@ static AttributeID* _BulkInsert_ReadHeaderProperties ASSERT(data_idx != NULL); ASSERT(prop_count != NULL); - // next 4 bytes are property count - *prop_count = *(uint*)&data[*data_idx]; - *data_idx += sizeof(unsigned int); + // next 4 bytes are property count + *prop_count = *(uint*)&data[*data_idx]; + *data_idx += sizeof(unsigned int); - if (*prop_count == 0) return NULL; + if (*prop_count == 0) return NULL; - AttributeID* prop_indices = rm_malloc(*prop_count * sizeof(AttributeID)); + AttributeID* prop_indices = rm_malloc(*prop_count * sizeof(AttributeID)); - // the rest of the line is [char *prop_key] * prop_count + // the rest of the line is [char *prop_key] * prop_count for (uint j = 0; j < *prop_count; j++) { char* prop_key = (char*)data + *data_idx; *data_idx += strlen(prop_key) + 1; @@ -116,7 +116,7 @@ static AttributeID* _BulkInsert_ReadHeaderProperties prop_indices[j] = GraphContext_FindOrAddAttribute(gc, prop_key, NULL); } - return prop_indices; + return prop_indices; } // read an SIValue from the data stream and update the index appropriately @@ -125,7 +125,7 @@ static SIValue _BulkInsert_ReadProperty const char* data, size_t* data_idx ) { - // binary property format: + // binary property format: // - property type : 1-byte integer corresponding to TYPE enum // - Nothing if type is NULL // - 1-byte true/false if type is boolean @@ -134,16 +134,16 @@ static SIValue _BulkInsert_ReadProperty // - Null-terminated C string if type is string // - 8-byte array length followed by N values if type is array - // possible property values - bool b; - double d; - int64_t i; - int64_t len; - const char* s; + // possible property values + bool b; + double d; + int64_t i; + int64_t len; + const char* s; - SIValue v = SI_NullVal(); - TYPE t = data[*data_idx]; - *data_idx += 1; + SIValue v = SI_NullVal(); + TYPE t = data[*data_idx]; + *data_idx += 1; switch (t) { case BI_NULL: @@ -191,7 +191,7 @@ static SIValue _BulkInsert_ReadProperty break; } - return v; + return v; } static int _BulkInsert_ProcessNodeFile @@ -200,30 +200,30 @@ static int _BulkInsert_ProcessNodeFile const char* data, size_t data_len ) { - uint prop_count; - size_t data_idx = 0; - - // read the CSV file header labels and update all schemas - int* label_ids = _BulkInsert_ReadHeaderLabels(gc, SCHEMA_NODE, data, &data_idx); - uint label_count = array_len(label_ids); - // read the CSV header properties and collect their indices - AttributeID* prop_indices = _BulkInsert_ReadHeaderProperties(gc, SCHEMA_NODE, data, + uint prop_count; + size_t data_idx = 0; + + // read the CSV file header labels and update all schemas + int* label_ids = _BulkInsert_ReadHeaderLabels(gc, SCHEMA_NODE, data, &data_idx); + uint label_count = array_len(label_ids); + // read the CSV header properties and collect their indices + AttributeID* prop_indices = _BulkInsert_ReadHeaderProperties(gc, SCHEMA_NODE, data, &data_idx, &prop_count); - // sync each matrix once - ASSERT(Graph_GetMatrixPolicy(gc->g) == SYNC_POLICY_RESIZE); + // sync each matrix once + ASSERT(Graph_GetMatrixPolicy(gc->g) == SYNC_POLICY_RESIZE); for (uint i = 0; i < label_count; i++) { Graph_GetLabelMatrix(gc->g, label_ids[i]); } - // sync node-label matrix - Graph_GetNodeLabelMatrix(gc->g); - Graph_SetMatrixPolicy(gc->g, SYNC_POLICY_NOP); + // sync node-label matrix + Graph_GetNodeLabelMatrix(gc->g); + Graph_SetMatrixPolicy(gc->g, SYNC_POLICY_NOP); - //-------------------------------------------------------------------------- - // load nodes - //-------------------------------------------------------------------------- + //-------------------------------------------------------------------------- + // load nodes + //-------------------------------------------------------------------------- while (data_idx < data_len) { Node n = GE_NEW_NODE(); @@ -240,11 +240,11 @@ static int _BulkInsert_ProcessNodeFile } } - Graph_SetMatrixPolicy(gc->g, SYNC_POLICY_RESIZE); - if (prop_indices) rm_free(prop_indices); - array_free(label_ids); + Graph_SetMatrixPolicy(gc->g, SYNC_POLICY_RESIZE); + if (prop_indices) rm_free(prop_indices); + array_free(label_ids); - return BULK_OK; + return BULK_OK; } static int _BulkInsert_ProcessEdgeFile @@ -253,31 +253,32 @@ static int _BulkInsert_ProcessEdgeFile const char* data, size_t data_len ) { - int relation_id; - uint prop_count; - size_t data_idx = 0; + int relation_id; + uint prop_count; + size_t data_idx = 0; - // read the CSV file header - // and commit all labels and properties it introduces - int* type_ids = _BulkInsert_ReadHeaderLabels(gc, SCHEMA_EDGE, data, &data_idx); - uint type_count = array_len(type_ids); + // read the CSV file header + // and commit all labels and properties it introduces + int* type_ids = _BulkInsert_ReadHeaderLabels(gc, SCHEMA_EDGE, data, &data_idx); + uint type_count = array_len(type_ids); - // edges can only have one type - ASSERT(type_count == 1); + // edges can only have one type + ASSERT(type_count == 1); - int type_id = type_ids[0]; - AttributeID* prop_indices = _BulkInsert_ReadHeaderProperties(gc, SCHEMA_EDGE, + int type_id = type_ids[0]; + AttributeID* prop_indices = _BulkInsert_ReadHeaderProperties(gc, SCHEMA_EDGE, data, &data_idx, &prop_count); - // sync matrix once - ASSERT(Graph_GetMatrixPolicy(gc->g) == SYNC_POLICY_RESIZE); - Graph_GetRelationMatrix(gc->g, type_id, false); - Graph_GetAdjacencyMatrix(gc->g, false); - Graph_SetMatrixPolicy(gc->g, SYNC_POLICY_NOP); + // sync matrix once + ASSERT(Graph_GetMatrixPolicy(gc->g) == SYNC_POLICY_RESIZE); + Graph_GetRelationMatrix(gc->g, type_id, false); + Graph_GetMultiEdgeRelationMatrix(gc->g, type_id); + Graph_GetAdjacencyMatrix(gc->g, false); + Graph_SetMatrixPolicy(gc->g, SYNC_POLICY_NOP); - //-------------------------------------------------------------------------- - // load edges - //-------------------------------------------------------------------------- + //-------------------------------------------------------------------------- + // load edges + //-------------------------------------------------------------------------- while (data_idx < data_len) { Edge e; @@ -305,11 +306,11 @@ static int _BulkInsert_ProcessEdgeFile } } - array_free(type_ids); - if (prop_indices) rm_free(prop_indices); - Graph_SetMatrixPolicy(gc->g, SYNC_POLICY_RESIZE); + array_free(type_ids); + if (prop_indices) rm_free(prop_indices); + Graph_SetMatrixPolicy(gc->g, SYNC_POLICY_RESIZE); - return BULK_OK; + return BULK_OK; } static int _BulkInsert_ProcessTokens @@ -330,7 +331,7 @@ static int _BulkInsert_ProcessTokens ASSERT(rc == BULK_OK); } - return BULK_OK; + return BULK_OK; } int BulkInsert diff --git a/src/configuration/config.c b/src/configuration/config.c index 478c82301..afdd71360 100644 --- a/src/configuration/config.c +++ b/src/configuration/config.c @@ -49,7 +49,7 @@ // Max mem(bytes) that query/thread can utilize at any given time #define QUERY_MEM_CAPACITY "QUERY_MEM_CAPACITY" -// number of pending changed befor RG_Matrix flushed +// number of pending changed before Delta_Matrix flushed #define DELTA_MAX_PENDING_CHANGES "DELTA_MAX_PENDING_CHANGES" // size of node creation buffer @@ -93,7 +93,7 @@ typedef struct { uint64_t max_queued_queries; // max number of queued queries int64_t query_mem_capacity; // Max mem(bytes) that query/thread can utilize at any given time uint64_t node_creation_buffer; // Number of extra node creations to buffer as margin in matrices - int64_t delta_max_pending_changes; // number of pending changed befor RG_Matrix flushed + int64_t delta_max_pending_changes; // number of pending changed before Delta_Matrix flushed Config_on_change cb; // callback function which being called when config param changed bool cmd_info_on; // If true, the GRAPH.INFO is enabled. uint64_t effects_threshold; // replicate via effects when runtime exceeds threshold @@ -636,7 +636,7 @@ static void _Config_SetToDefaults(void) { // no limit on query memory capacity config.query_mem_capacity = QUERY_MEM_CAPACITY_UNLIMITED; - // number of pending changed befor RG_Matrix flushed + // number of pending changed before Delta_Matrix flushed config.delta_max_pending_changes = DELTA_MAX_PENDING_CHANGES_DEFAULT; // the amount of empty space to reserve for node creations in matrices @@ -891,7 +891,7 @@ bool Config_Option_get break; //---------------------------------------------------------------------- - // number of pending changed befor RG_Matrix flushed + // number of pending changed before Delta_Matrix flushed //---------------------------------------------------------------------- case Config_DELTA_MAX_PENDING_CHANGES: { @@ -1138,7 +1138,7 @@ bool Config_Option_set break; //---------------------------------------------------------------------- - // number of pending changed befor RG_Matrix flushed + // number of pending changed befor Delta_Matrix flushed //---------------------------------------------------------------------- case Config_DELTA_MAX_PENDING_CHANGES: { diff --git a/src/configuration/config.h b/src/configuration/config.h index 6acd599d4..b55ee5671 100644 --- a/src/configuration/config.h +++ b/src/configuration/config.h @@ -28,7 +28,7 @@ typedef enum { Config_VKEY_MAX_ENTITY_COUNT = 8, // max number of elements in vkey Config_MAX_QUEUED_QUERIES = 9, // max number of queued queries Config_QUERY_MEM_CAPACITY = 10, // max mem(bytes) that query/thread can utilize at any given time - Config_DELTA_MAX_PENDING_CHANGES = 11, // number of pending changes before RG_Matrix flushed + Config_DELTA_MAX_PENDING_CHANGES = 11, // number of pending changes before Delta_Matrix flushed Config_NODE_CREATION_BUFFER = 12, // size of buffer to maintain as margin in matrices Config_CMD_INFO = 13, // toggle on/off the GRAPH.INFO Config_CMD_INFO_MAX_QUERY_COUNT = 14, // the max number of info queries count diff --git a/src/constraint/constraint.c b/src/constraint/constraint.c index e4bdb41b9..642af3ffc 100644 --- a/src/constraint/constraint.c +++ b/src/constraint/constraint.c @@ -12,7 +12,7 @@ #include "../util/thpool/pools.h" #include "../graph//graphcontext.h" #include "../graph/entities/attribute_set.h" -#include "../graph/rg_matrix/rg_matrix_iter.h" +#include "../graph/delta_matrix/delta_matrix_iter.h" #include @@ -408,12 +408,12 @@ void Constraint_EnforceNodes ASSERT(c != NULL); ASSERT(g != NULL); - RG_MatrixTupleIter it = {0}; // matrix iterator - bool holds = true; // constraint holds - GrB_Index rowIdx = 0; // current row being scanned - int enforced = 0; // #entities in current batch - int schema_id = c->schema_id; // constraint schema ID - int batch_size = 10000; // #entities to enforce + Delta_MatrixTupleIter it = {0}; // matrix iterator + bool holds = true; // constraint holds + GrB_Index rowIdx = 0; // current row being scanned + int enforced = 0; // #entities in current batch + int schema_id = c->schema_id; // constraint schema ID + int batch_size = 10000; // #entities to enforce while(holds) { // lock graph for reading @@ -427,7 +427,7 @@ void Constraint_EnforceNodes break; } - const RG_Matrix m = Graph_GetLabelMatrix(g, schema_id); + const Delta_Matrix m = Graph_GetLabelMatrix(g, schema_id); ASSERT(m != NULL); // reset number of enforce nodes in batch @@ -438,7 +438,7 @@ void Constraint_EnforceNodes //---------------------------------------------------------------------- GrB_Info info; - info = RG_MatrixTupleIter_AttachRange(&it, m, rowIdx, UINT64_MAX); + info = Delta_MatrixTupleIter_AttachRange(&it, m, rowIdx, UINT64_MAX); ASSERT(info == GrB_SUCCESS); //---------------------------------------------------------------------- @@ -447,7 +447,7 @@ void Constraint_EnforceNodes EntityID id; while(enforced < batch_size && - RG_MatrixTupleIter_next_BOOL(&it, &id, NULL, NULL) == GrB_SUCCESS) + Delta_MatrixTupleIter_next_BOOL(&it, &id, NULL, NULL) == GrB_SUCCESS) { Node n; Graph_GetNode(g, id, &n); @@ -471,7 +471,7 @@ void Constraint_EnforceNodes Graph_ReleaseLock(g); // finished current batch - RG_MatrixTupleIter_detach(&it); + Delta_MatrixTupleIter_detach(&it); // continue next batch from row id+1 // this is true because we're iterating over a diagonal matrix @@ -479,7 +479,7 @@ void Constraint_EnforceNodes } } - RG_MatrixTupleIter_detach(&it); + Delta_MatrixTupleIter_detach(&it); // update constraint status ConstraintStatus status = (holds) ? CT_ACTIVE : CT_FAILED; @@ -496,14 +496,14 @@ void Constraint_EnforceEdges Graph *g ) { GrB_Info info; - RG_MatrixTupleIter it = {0}; + MultiEdgeIterator it = {0}; + bool skip = false; bool holds = true; // constraint holds EntityID src_id = 0; // current processed row idx EntityID dest_id = 0; // current processed column idx EntityID edge_id = 0; // current processed edge id - EntityID prev_src_id = 0; // last processed row idx - EntityID prev_dest_id = 0; // last processed column idx + EntityID prev_edge_id = 0; // last processed edge idx int enforced = 0; // # entities enforced in batch int schema_id = c->schema_id; // edge relationship type ID int batch_size = 1000; // max number of entities to enforce @@ -522,67 +522,52 @@ void Constraint_EnforceEdges // reset number of enforced edges in batch enforced = 0; - prev_src_id = src_id; - prev_dest_id = dest_id; + prev_edge_id = edge_id; - // fetch relation matrix ASSERT(Graph_GetMatrixPolicy(g) == SYNC_POLICY_FLUSH_RESIZE); - const RG_Matrix m = Graph_GetRelationMatrix(g, schema_id, false); - ASSERT(m != NULL); + // sync relation matrix + Graph_GetRelationMatrix(g, schema_id, false); + Graph_GetMultiEdgeRelationMatrix(g, schema_id); //---------------------------------------------------------------------- // resume scanning from previous row/col indices //---------------------------------------------------------------------- - info = RG_MatrixTupleIter_AttachRange(&it, m, src_id, UINT64_MAX); - ASSERT(info == GrB_SUCCESS); + MultiEdgeIterator_AttachSourceRange(&it, g->relations + schema_id, src_id, UINT64_MAX, false); // skip previously enforced edges - while((info = RG_MatrixTupleIter_next_UINT64(&it, &src_id, &dest_id, - &edge_id)) == GrB_SUCCESS && - src_id == prev_src_id && - dest_id < prev_dest_id); + while(skip && (info = MultiEdgeIterator_next(&it, &src_id, &dest_id, + &edge_id)) && + edge_id != prev_edge_id); // process only if iterator is on an active entry - if(info != GrB_SUCCESS) { + if(skip && info != GrB_SUCCESS) { break; } + skip = true; + //---------------------------------------------------------------------- // batch enforce edges //---------------------------------------------------------------------- - do { + while(enforced < batch_size && + MultiEdgeIterator_next(&it, &src_id, &dest_id, &edge_id) && + holds) { Edge e; e.src_id = src_id; e.dest_id = dest_id; e.relationID = schema_id; - if(SINGLE_EDGE(edge_id)) { - bool res = Graph_GetEdge(g, edge_id, &e); - assert(res == true); - if(!c->enforce(c, (GraphEntity*)&e, NULL)) { - holds = false; - break; - } - } else { - EdgeID *edgeIds = (EdgeID *)(CLEAR_MSB(edge_id)); - uint edgeCount = array_len(edgeIds); - - for(uint i = 0; i < edgeCount; i++) { - edge_id = edgeIds[i]; - bool res = Graph_GetEdge(g, edge_id, &e); - assert(res == true); - if(!c->enforce(c, (GraphEntity*)&e, NULL)) { - holds = false; - break; - } - } + bool res = Graph_GetEdge(g, edge_id, &e); + assert(res == true); + if(!c->enforce(c, (GraphEntity*)&e, NULL)) { + holds = false; + break; } - enforced++; // single/multi edge are counted similarly - } while(enforced < batch_size && - RG_MatrixTupleIter_next_UINT64(&it, &src_id, &dest_id, &edge_id) - == GrB_SUCCESS && holds); + + enforced++; + } //---------------------------------------------------------------------- // done with current batch @@ -595,12 +580,9 @@ void Constraint_EnforceEdges // finished current batch // release read lock Graph_ReleaseLock(g); - RG_MatrixTupleIter_detach(&it); } } - RG_MatrixTupleIter_detach(&it); - // update constraint status ConstraintStatus status = (holds) ? CT_ACTIVE : CT_FAILED; Constraint_SetStatus(c, status); @@ -638,4 +620,3 @@ void Constraint_Free *c = NULL; } - diff --git a/src/cron/tasks/stream_finished_queries.c b/src/cron/tasks/stream_finished_queries.c index 6359cd756..b6f513ed8 100644 --- a/src/cron/tasks/stream_finished_queries.c +++ b/src/cron/tasks/stream_finished_queries.c @@ -7,6 +7,7 @@ #include "globals.h" #include "cron/cron.h" #include "redismodule.h" +#include "../../util/rmalloc.h" #include "graph/graphcontext.h" #include "configuration/config.h" #include "util/circular_buffer.h" diff --git a/src/execution_plan/ops/op_cond_var_len_traverse.h b/src/execution_plan/ops/op_cond_var_len_traverse.h index 0515f66ea..8d0c783d7 100644 --- a/src/execution_plan/ops/op_cond_var_len_traverse.h +++ b/src/execution_plan/ops/op_cond_var_len_traverse.h @@ -17,7 +17,7 @@ typedef struct { OpBase op; Graph *g; Record r; - RG_Matrix M; /* Traversed matrix if using the SimpleConsume routine. */ + Delta_Matrix M; /* Traversed matrix if using the SimpleConsume routine. */ int edgesIdx; /* Edges set by operation. */ int srcNodeIdx; /* Node set by operation. */ int destNodeIdx; /* Node set by operation. */ diff --git a/src/execution_plan/ops/op_conditional_traverse.c b/src/execution_plan/ops/op_conditional_traverse.c index 39c33a1d0..d704df359 100644 --- a/src/execution_plan/ops/op_conditional_traverse.c +++ b/src/execution_plan/ops/op_conditional_traverse.c @@ -25,7 +25,7 @@ static void CondTraverseToString(const OpBase *ctx, sds *buf) { } static void _populate_filter_matrix(OpCondTraverse *op) { - GrB_Matrix FM = RG_MATRIX_M(op->F); + GrB_Matrix FM = Delta_Matrix_M(op->F); // clear filter matrix GrB_Matrix_clear(FM); @@ -51,8 +51,8 @@ void _traverse(OpCondTraverse *op) { if(op->F == NULL) { // create both filter and result matrices size_t required_dim = Graph_RequiredMatrixDim(op->graph); - RG_Matrix_new(&op->M, GrB_BOOL, op->record_cap, required_dim); - RG_Matrix_new(&op->F, GrB_BOOL, op->record_cap, required_dim); + Delta_Matrix_new(&op->M, GrB_BOOL, op->record_cap, required_dim, false); + Delta_Matrix_new(&op->F, GrB_BOOL, op->record_cap, required_dim, false); // prepend filter matrix to algebraic expression as the leftmost operand AlgebraicExpression_MultiplyToTheLeft(&op->ae, op->F); @@ -67,7 +67,7 @@ void _traverse(OpCondTraverse *op) { // evaluate expression AlgebraicExpression_Eval(op->ae, op->M); - RG_MatrixTupleIter_attach(&op->iter, op->M); + Delta_MatrixTupleIter_attach(&op->iter, op->M); } OpBase *NewCondTraverseOp @@ -147,7 +147,7 @@ static Record CondTraverseConsume while(true) { GrB_Info info = - RG_MatrixTupleIter_next_UINT64(&op->iter, &src_id, &dest_id, NULL); + Delta_MatrixTupleIter_next_BOOL(&op->iter, &src_id, &dest_id, NULL); // managed to get a tuple, break if(info == GrB_SUCCESS) break; @@ -217,10 +217,10 @@ static OpResult CondTraverseReset(OpBase *ctx) { if(op->edge_ctx) EdgeTraverseCtx_Reset(op->edge_ctx); - GrB_Info info = RG_MatrixTupleIter_detach(&op->iter); + GrB_Info info = Delta_MatrixTupleIter_detach(&op->iter); ASSERT(info == GrB_SUCCESS); - if(op->F != NULL) RG_Matrix_clear(op->F); + if(op->F != NULL) Delta_Matrix_clear(op->F); return OP_OK; } @@ -234,16 +234,16 @@ static inline OpBase *CondTraverseClone(const ExecutionPlan *plan, const OpBase static void CondTraverseFree(OpBase *ctx) { OpCondTraverse *op = (OpCondTraverse *)ctx; - GrB_Info info = RG_MatrixTupleIter_detach(&op->iter); + GrB_Info info = Delta_MatrixTupleIter_detach(&op->iter); ASSERT(info == GrB_SUCCESS); if(op->F != NULL) { - RG_Matrix_free(&op->F); + Delta_Matrix_free(&op->F); op->F = NULL; } if(op->M != NULL) { - RG_Matrix_free(&op->M); + Delta_Matrix_free(&op->M); op->M = NULL; } diff --git a/src/execution_plan/ops/op_conditional_traverse.h b/src/execution_plan/ops/op_conditional_traverse.h index b1e9edcfe..b03412ac4 100644 --- a/src/execution_plan/ops/op_conditional_traverse.h +++ b/src/execution_plan/ops/op_conditional_traverse.h @@ -9,7 +9,7 @@ #include "op.h" #include "../execution_plan.h" #include "shared/traverse_functions.h" -#include "../../graph/rg_matrix/rg_matrix_iter.h" +#include "../../graph/delta_matrix/delta_matrix_iter.h" #include "../../arithmetic/algebraic_expression.h" #include "../../../deps/GraphBLAS/Include/GraphBLAS.h" @@ -18,16 +18,16 @@ typedef struct { OpBase op; Graph *graph; AlgebraicExpression *ae; - RG_Matrix F; // Filter matrix. - RG_Matrix M; // Algebraic expression result. - EdgeTraverseCtx *edge_ctx; // Edge collection data if the edge needs to be set. - RG_MatrixTupleIter iter; // Iterator over M. - int srcNodeIdx; // Source node index into record. - int destNodeIdx; // Destination node index into record. - uint64_t record_count; // Number of held records. - uint64_t record_cap; // Max number of records to process. - Record *records; // Array of records. - Record r; // Currently selected record. + Delta_Matrix F; // Filter matrix. + Delta_Matrix M; // Algebraic expression result. + EdgeTraverseCtx *edge_ctx; // Edge collection data if the edge needs to be set. + Delta_MatrixTupleIter iter; // Iterator over M. + int srcNodeIdx; // Source node index into record. + int destNodeIdx; // Destination node index into record. + uint64_t record_count; // Number of held records. + uint64_t record_cap; // Max number of records to process. + Record *records; // Array of records. + Record r; // Currently selected record. } OpCondTraverse; /* Creates a new Traverse operation */ diff --git a/src/execution_plan/ops/op_expand_into.c b/src/execution_plan/ops/op_expand_into.c index 6f455418f..0c7d26365 100644 --- a/src/execution_plan/ops/op_expand_into.c +++ b/src/execution_plan/ops/op_expand_into.c @@ -34,7 +34,7 @@ static void _populate_filter_matrix ( OpExpandInto *op ) { - GrB_Matrix FM = RG_MATRIX_M(op->F); + GrB_Matrix FM = Delta_Matrix_M(op->F); // clear filter matrix GrB_Matrix_clear(FM); @@ -65,8 +65,8 @@ static void _traverse if(op->F == NULL) { // create both filter matrix F and result matrix M size_t required_dim = Graph_RequiredMatrixDim(op->graph); - RG_Matrix_new(&op->M, GrB_BOOL, op->record_cap, required_dim); - RG_Matrix_new(&op->F, GrB_BOOL, op->record_cap, required_dim); + Delta_Matrix_new(&op->M, GrB_BOOL, op->record_cap, required_dim, false); + Delta_Matrix_new(&op->F, GrB_BOOL, op->record_cap, required_dim, false); // prepend the filter matrix to algebraic expression // as the leftmost operand @@ -225,9 +225,9 @@ static Record _handoff NodeID col = ENTITY_GET_ID(destNode); // TODO: in the case of multiple operands ()-[:A]->()-[:B]->() // M is the result of F*A*B, in which case we can switch from - // M being a RG_Matrix to a GrB_Matrix, making the extract element + // M being a Delta_Matrix to a GrB_Matrix, making the extract element // operation a bit cheaper to compute - GrB_Info res = RG_Matrix_extractElement_BOOL(&x, op->M, row, col); + GrB_Info res = Delta_Matrix_extractElement_BOOL(&x, op->M, row, col); // src is not connected to dest, free the current record and continue if(res != GrB_SUCCESS) { @@ -350,14 +350,14 @@ static void ExpandIntoFree OpExpandInto *op = (OpExpandInto *)ctx; if(op->F != NULL) { - RG_Matrix_free(&op->F); + Delta_Matrix_free(&op->F); op->F = NULL; } if(op->ae != NULL) { // M was allocated by us if(op->M != NULL && !op->single_operand) { - RG_Matrix_free(&op->M); + Delta_Matrix_free(&op->M); op->M = NULL; } diff --git a/src/execution_plan/ops/op_expand_into.h b/src/execution_plan/ops/op_expand_into.h index 558789c8d..10d18683e 100644 --- a/src/execution_plan/ops/op_expand_into.h +++ b/src/execution_plan/ops/op_expand_into.h @@ -17,8 +17,8 @@ typedef struct { OpBase op; Graph *graph; AlgebraicExpression *ae; - RG_Matrix F; // filter matrix - RG_Matrix M; // algebraic expression result + Delta_Matrix F; // filter matrix + Delta_Matrix M; // algebraic expression result EdgeTraverseCtx *edge_ctx; // edge collection data if the edge needs to be set int srcNodeIdx; // source node index into record int destNodeIdx; // destination node index into record diff --git a/src/execution_plan/ops/op_node_by_label_scan.c b/src/execution_plan/ops/op_node_by_label_scan.c index 7de8daef2..fe03d8ae5 100644 --- a/src/execution_plan/ops/op_node_by_label_scan.c +++ b/src/execution_plan/ops/op_node_by_label_scan.c @@ -113,7 +113,7 @@ static bool _ConstructIterator } // use matrix iterator - info = RG_MatrixTupleIter_attach(&op->iter, op->L); + info = Delta_MatrixTupleIter_attach(&op->iter, op->L); ASSERT(info == GrB_SUCCESS); return true; @@ -197,7 +197,7 @@ static Record NodeByLabelScanConsume NodeByLabelScan *op = (NodeByLabelScan *)opBase; GrB_Index id; - GrB_Info info = RG_MatrixTupleIter_next_BOOL(&op->iter, &id, NULL, NULL); + GrB_Info info = Delta_MatrixTupleIter_next_BOOL(&op->iter, &id, NULL, NULL); if(info == GxB_EXHAUSTED) return NULL; ASSERT(info == GrB_SUCCESS); @@ -224,7 +224,7 @@ static Record NodeByLabelAndIDScanConsume id = roaring64_iterator_value(op->ID_it); roaring64_iterator_advance(op->ID_it); bool x; - if(RG_Matrix_extractElement_BOOL(&x, op->L, id, id) == GrB_SUCCESS) { + if(Delta_Matrix_extractElement_BOOL(&x, op->L, id, id) == GrB_SUCCESS) { Record r = OpBase_CreateRecord((OpBase *)op); // Populate the Record with the actual node. @@ -247,7 +247,7 @@ static Record NodeByLabelScanConsumeFromChild // try to get new nodeID GrB_Index id; - GrB_Info info = RG_MatrixTupleIter_next_BOOL(&op->iter, &id, NULL, NULL); + GrB_Info info = Delta_MatrixTupleIter_next_BOOL(&op->iter, &id, NULL, NULL); // iterator depleted, try to get a new record while(op->child_record == NULL || @@ -276,7 +276,7 @@ static Record NodeByLabelScanConsumeFromChild } // try to get new NodeID - info = RG_MatrixTupleIter_next_BOOL(&op->iter, &id, NULL, NULL); + info = Delta_MatrixTupleIter_next_BOOL(&op->iter, &id, NULL, NULL); } // we've got a record and NodeID @@ -310,7 +310,7 @@ static Record NodeByLabelAndIDScanConsumeFromChild roaring64_iterator_advance(op->ID_it); // make sure ID is labeled as L - if(RG_Matrix_extractElement_BOOL(&x, op->L, id, id) == GrB_SUCCESS) { + if(Delta_Matrix_extractElement_BOOL(&x, op->L, id, id) == GrB_SUCCESS) { emited = true; break; } @@ -380,7 +380,7 @@ static void NodeByLabelScanFree ) { NodeByLabelScan *op = (NodeByLabelScan *)opBase; - GrB_Info info = RG_MatrixTupleIter_detach(&(op->iter)); + GrB_Info info = Delta_MatrixTupleIter_detach(&(op->iter)); ASSERT(info == GrB_SUCCESS); if(op->child_record) { diff --git a/src/execution_plan/ops/op_node_by_label_scan.h b/src/execution_plan/ops/op_node_by_label_scan.h index a0db925f5..d1b3b4a54 100644 --- a/src/execution_plan/ops/op_node_by_label_scan.h +++ b/src/execution_plan/ops/op_node_by_label_scan.h @@ -12,7 +12,7 @@ #include "../../util/roaring.h" #include "shared/scan_functions.h" #include "../../util/range/range.h" -#include "../../graph/rg_matrix/rg_matrix_iter.h" +#include "../../graph/delta_matrix/delta_matrix_iter.h" // NodeByLabelScan, scans entire label typedef struct { @@ -23,8 +23,8 @@ typedef struct { RangeExpression *ranges; // array of ID range expressions roaring64_bitmap_t *ids; // resolved ids by filters roaring64_iterator_t *ID_it; // ID iterator - RG_Matrix L; // label matrix - RG_MatrixTupleIter iter; // iterator over label matrix + Delta_Matrix L; // label matrix + Delta_MatrixTupleIter iter; // iterator over label matrix Record child_record; // the record this op acts on if it is not a tap } NodeByLabelScan; diff --git a/src/execution_plan/ops/shared/create_functions.c b/src/execution_plan/ops/shared/create_functions.c index f7fca1a8e..ce09cf529 100644 --- a/src/execution_plan/ops/shared/create_functions.c +++ b/src/execution_plan/ops/shared/create_functions.c @@ -123,6 +123,7 @@ static void _CommitEdgesBlueprint // calling Graph_GetRelationMatrix will make sure relationship matrix // is of the right dimensions Graph_GetRelationMatrix(g, Schema_GetID(s), false); + Graph_GetMultiEdgeRelationMatrix(g, Schema_GetID(s)); } // call Graph_GetAdjacencyMatrix will make sure the adjacency matrix diff --git a/src/globals.c b/src/globals.c index 5d64a88f6..9120cfeb4 100644 --- a/src/globals.c +++ b/src/globals.c @@ -5,6 +5,7 @@ */ #include "globals.h" +#include "util/arr.h" #include "util/thpool/pools.h" struct Globals { diff --git a/src/graph/delta_matrix/delta_matrix.h b/src/graph/delta_matrix/delta_matrix.h new file mode 100644 index 000000000..b54a30899 --- /dev/null +++ b/src/graph/delta_matrix/delta_matrix.h @@ -0,0 +1,246 @@ +/* + * Copyright FalkorDB Ltd. 2023 - present + * Licensed under the Server Side Public License v1 (SSPLv1). + */ + +#pragma once + +#include "RG.h" +#include "GraphBLAS.h" + +// forward declaration of Delta_Matrix type +typedef struct _Delta_Matrix _Delta_Matrix; +typedef _Delta_Matrix *Delta_Matrix; + + +//------------------------------------------------------------------------------ +// +// possible combinations +// +//------------------------------------------------------------------------------ +// +// empty +// +// A DP DM +// . . . . . . . . . +// . . . . . . . . . +// . . . . . . . . . +// +//------------------------------------------------------------------------------ +// +// flushed, no pending changes +// +// A DP DM +// . 1 . . . . . . . +// . . . . . . . . . +// . . . . . . . . . +// +//------------------------------------------------------------------------------ +// +// single entry added +// +// A DP DM +// . . . . 1 . . . . +// . . . . . . . . . +// . . . . . . . . . +// +//------------------------------------------------------------------------------ +// +// single entry deleted +// +// A DP DM +// 1 . . . . . 1 . . +// . . . . . . . . . +// . . . . . . . . . +// +//------------------------------------------------------------------------------ +// impossible state +// existing entry deleted and then added back +// +// A DP DM +// 1 . . 1 . . 1 . . +// . . . . . . . . . +// . . . . . . . . . +// +//------------------------------------------------------------------------------ +// +// impossible state +// marked none existing entry for deletion +// +// A DP DM +// . . . . . . 1 . . +// . . . . . . . . . +// . . . . . . . . . +// +//------------------------------------------------------------------------------ +// +// impossible state +// adding to an already existing entry +// should have turned A[0,0] to a multi-value +// +// A DP DM +// 1 . . 1 . . . . . +// . . . . . . . . . +// . . . . . . . . . +// +//------------------------------------------------------------------------------ +// +// impossible state +// deletion of pending entry should have cleared it DP[0,0] +// +// A DP DM +// . . . 1 . . 1 . . +// . . . . . . . . . +// . . . . . . . . . +// +//------------------------------------------------------------------------------ + +GrB_Info Delta_Matrix_new +( + Delta_Matrix *A, // handle of matrix to create + GrB_Type type, // type of matrix to create + GrB_Index nrows, // matrix dimension is nrows-by-ncols + GrB_Index ncols, + bool transpose // if true, create a transpose of the matrix +); + +// returns transposed matrix of C +Delta_Matrix Delta_Matrix_getTranspose +( + const Delta_Matrix C +); + +GrB_Matrix Delta_Matrix_M +( + const Delta_Matrix C +); + +GrB_Info Delta_Matrix_nrows +( + GrB_Index *nrows, + const Delta_Matrix C +); + +GrB_Info Delta_Matrix_ncols +( + GrB_Index *ncols, + const Delta_Matrix C +); + +GrB_Info Delta_Matrix_nvals // get the number of entries in a matrix +( + GrB_Index *nvals, // matrix has nvals entries + const Delta_Matrix A // matrix to query +); + +GrB_Info Delta_Matrix_resize // change the size of a matrix +( + Delta_Matrix C, // matrix to modify + GrB_Index nrows_new, // new number of rows in matrix + GrB_Index ncols_new // new number of columns in matrix +); + +GrB_Info Delta_Matrix_setElement_BOOL // C (i,j) = x +( + Delta_Matrix C, // matrix to modify + GrB_Index i, // row index + GrB_Index j // column index +); + +GrB_Info Delta_Matrix_setElement_UINT64 // C (i,j) = x +( + Delta_Matrix C, // matrix to modify + uint64_t x, // value + GrB_Index i, // row index + GrB_Index j // column index +); + +GrB_Info Delta_Matrix_extractElement_BOOL // x = A(i,j) +( + bool *x, // extracted scalar + const Delta_Matrix A, // matrix to extract a scalar from + GrB_Index i, // row index + GrB_Index j // column index +) ; + +GrB_Info Delta_Matrix_extractElement_UINT64 // x = A(i,j) +( + uint64_t *x, // extracted scalar + const Delta_Matrix A, // matrix to extract a scalar from + GrB_Index i, // row index + GrB_Index j // column index +) ; + +// remove entry at position C[i,j] +GrB_Info Delta_Matrix_removeElement +( + Delta_Matrix C, // matrix to remove entry from + GrB_Index i, // row index + GrB_Index j // column index +); + +GrB_Info Delta_Matrix_removeElements +( + Delta_Matrix C, // matrix to remove entry from + GrB_Matrix m // elements to remove +); + +GrB_Info Delta_mxm // C = A * B +( + Delta_Matrix C, // input/output matrix for results + const GrB_Semiring semiring, // defines '+' and '*' for A*B + const Delta_Matrix A, // first input: matrix A + const Delta_Matrix B // second input: matrix B +); + +GrB_Info Delta_eWiseAdd // C = A + B +( + Delta_Matrix C, // input/output matrix for results + const GrB_Semiring semiring, // defines '+' for T=A+B + const Delta_Matrix A, // first input: matrix A + const Delta_Matrix B // second input: matrix B +); + +GrB_Info Delta_Matrix_clear // clear a matrix of all entries; +( // type and dimensions remain unchanged + Delta_Matrix A // matrix to clear +); + +GrB_Info Delta_Matrix_copy // copy matrix A to matrix C +( + Delta_Matrix C, // output matrix + const Delta_Matrix A // input matrix +); + +// get matrix C without writing to internal matrix +GrB_Info Delta_Matrix_export +( + GrB_Matrix *A, + Delta_Matrix C +); + +// checks to see if matrix has pending operations +GrB_Info Delta_Matrix_pending +( + const Delta_Matrix C, // matrix to query + bool *pending // are there any pending operations +); + +GrB_Info Delta_Matrix_wait +( + Delta_Matrix C, + bool force_sync +); + +void Delta_Matrix_synchronize +( + Delta_Matrix C, + GrB_Index nrows, + GrB_Index ncols +); + +void Delta_Matrix_free +( + Delta_Matrix *C +); + diff --git a/src/graph/delta_matrix/delta_matrix_iter.h b/src/graph/delta_matrix/delta_matrix_iter.h new file mode 100644 index 000000000..b37304d12 --- /dev/null +++ b/src/graph/delta_matrix/delta_matrix_iter.h @@ -0,0 +1,90 @@ +/* + * Copyright Redis Ltd. 2018 - present + * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or + * the Server Side Public License v1 (SSPLv1). + */ + +#pragma once + +#include +#include "delta_matrix.h" +#include "GraphBLAS.h" + +#define RG_ITER_MIN_ROW 0 +#define RG_ITER_MAX_ROW ULLONG_MAX + +// TuplesIter maintains information required +// to iterate over a Delta_Matrix +struct Opaque_Delta_MatrixTupleIter +{ + char _private[432]; +}; + +typedef struct Opaque_Delta_MatrixTupleIter Delta_MatrixTupleIter ; + +// attach iterator to matrix +GrB_Info Delta_MatrixTupleIter_attach +( + Delta_MatrixTupleIter *iter, // iterator to update + const Delta_Matrix A // matrix to scan +); + +// attach iterator to matrix governing the specified range +GrB_Info Delta_MatrixTupleIter_AttachRange +( + Delta_MatrixTupleIter *iter, // iterator to update + const Delta_Matrix A, // matrix to scan + GrB_Index min_row, // minimum row for iteration + GrB_Index max_row // maximum row for iteration +); + +// free iterator internals, keeping the iterator intact +GrB_Info Delta_MatrixTupleIter_detach +( + Delta_MatrixTupleIter *iter // iterator to free +); + +// returns true if iterator is attached to given matrix false otherwise +bool Delta_MatrixTupleIter_is_attached +( + const Delta_MatrixTupleIter *iter, // iterator to check + const Delta_Matrix M // matrix attached to +); + +GrB_Info Delta_MatrixTupleIter_iterate_row +( + Delta_MatrixTupleIter *iter, // iterator to use + GrB_Index rowIdx // row to iterate +); + +GrB_Info Delta_MatrixTupleIter_iterate_range +( + Delta_MatrixTupleIter *iter, // iterator to use + GrB_Index startRowIdx, // row index to start with + GrB_Index endRowIdx // row index to finish with +); + +// advance iterator +GrB_Info Delta_MatrixTupleIter_next_BOOL +( + Delta_MatrixTupleIter *iter, // iterator to consume + GrB_Index *row, // optional output row index + GrB_Index *col, // optional output column index + bool *val // optional value at A[row, col] +); + +// advance iterator +GrB_Info Delta_MatrixTupleIter_next_UINT64 +( + Delta_MatrixTupleIter *iter, // iterator to consume + GrB_Index *row, // optional output row index + GrB_Index *col, // optional output column index + uint64_t *val // optional value at A[row, col] +); + +// reset iterator +GrB_Info Delta_MatrixTupleIter_reset +( + Delta_MatrixTupleIter *iter // iterator to reset +); + diff --git a/src/graph/graph.c b/src/graph/graph.c index 8c2e3b2d9..d1aa86951 100644 --- a/src/graph/graph.c +++ b/src/graph/graph.c @@ -8,14 +8,9 @@ #include "graph.h" #include "../util/arr.h" #include "../util/rmalloc.h" -#include "rg_matrix/rg_matrix_iter.h" +#include "delta_matrix/delta_matrix_iter.h" #include "../util/datablock/oo_datablock.h" -//------------------------------------------------------------------------------ -// Forward declarations -//------------------------------------------------------------------------------ -void _MatrixResizeToCapacity(const Graph *g, RG_Matrix m); - //------------------------------------------------------------------------------ // Synchronization functions //------------------------------------------------------------------------------ @@ -95,42 +90,6 @@ static inline size_t _Graph_NodeCap(const Graph *g) { return g->nodes->itemCap; } -static void _CollectEdgesFromEntry -( - const Graph *g, - NodeID src, - NodeID dest, - RelationID r, - EdgeID edgeId, - Edge **edges -) { - Edge e = {0}; - - e.src_id = src; - e.dest_id = dest; - e.relationID = r; - - if(SINGLE_EDGE(edgeId)) { - e.id = edgeId; - e.attributes = DataBlock_GetItem(g->edges, edgeId); - ASSERT(e.attributes); - array_append(*edges, e); - } else { - // multiple edges connecting src to dest, - // entry is a pointer to an array of edge IDs - EdgeID *edgeIds = (EdgeID *)(CLEAR_MSB(edgeId)); - uint edgeCount = array_len(edgeIds); - - for(uint i = 0; i < edgeCount; i++) { - edgeId = edgeIds[i]; - e.id = edgeId; - e.attributes = DataBlock_GetItem(g->edges, edgeId); - ASSERT(e.attributes); - array_append(*edges, e); - } - } -} - // Locates edges connecting src to destination. void _Graph_GetEdgesConnectingNodes ( @@ -143,18 +102,23 @@ void _Graph_GetEdgesConnectingNodes ASSERT(g); ASSERT(r != GRAPH_NO_RELATION); ASSERT(r < Graph_RelationTypeCount(g)); - ASSERT(src < Graph_RequiredMatrixDim(g)); - ASSERT(dest < Graph_RequiredMatrixDim(g)); + ASSERT(src < _Graph_NodeCap(g)); + ASSERT(dest < _Graph_NodeCap(g)); // relation map, maps (src, dest, r) to edge IDs. - EdgeID id = INVALID_ENTITY_ID; - RG_Matrix M = Graph_GetRelationMatrix(g, r, false); - GrB_Info res = RG_Matrix_extractElement_UINT64(&id, M, src, dest); - - // no entry at [dest, src], src is not connected to dest with relation R - if(res == GrB_NO_VALUE) return; - - _CollectEdgesFromEntry(g, src, dest, r, id, edges); + Graph_GetRelationMatrix(g, r, false); + Graph_GetMultiEdgeRelationMatrix(g, r); + Edge e = {.src_id = src, .dest_id = dest, .relationID = r}; + GrB_Index edge_id; + MultiEdgeIterator it = {0}; + MultiEdgeIterator_AttachSourceDest(&it, g->relations + r, src, dest); + + while(MultiEdgeIterator_next(&it, NULL, NULL, &edge_id)){ + e.id = edge_id; + e.attributes = DataBlock_GetItem(g->edges, edge_id); + ASSERT(e.attributes); + array_append(*edges, e); + } } static inline AttributeSet *_Graph_GetEntity(const DataBlock *entities, EntityID id) { @@ -170,81 +134,31 @@ static inline AttributeSet *_Graph_GetEntity(const DataBlock *entities, EntityID // matrix to execute any pending operations void _MatrixSynchronize ( - const Graph *g, - RG_Matrix m + const Graph *g, // graph the matrix is related to + Delta_Matrix M, // matrix to synchronize + GrB_Index nrows, // # of rows for the resize + GrB_Index ncols // # of columns for the resize ) { - GrB_Info info; - GrB_Index n_rows; - GrB_Index n_cols; - - RG_Matrix_nrows(&n_rows, m); - RG_Matrix_ncols(&n_cols, m); - - bool dirty = RG_Matrix_isDirty(m); - GrB_Index dims = Graph_RequiredMatrixDim(g); - - UNUSED(info); - - // matrix must be resized if its dimensions missmatch required dimensions - bool require_resize = (n_rows != dims || n_cols != dims); - - // matrix fully synced, nothing to do - if(!require_resize && !dirty) { - return; - } - - // lock matrix - RG_Matrix_Lock(m); - - // recheck - RG_Matrix_nrows(&n_rows, m); - RG_Matrix_ncols(&n_cols, m); - dirty = RG_Matrix_isDirty(m); - dims = Graph_RequiredMatrixDim(g); - require_resize = (n_rows != dims || n_cols != dims); - - // some other thread performed sync - if(!require_resize && !dirty) { - goto cleanup; - } - - // resize if required - if(require_resize) { - info = RG_Matrix_resize(m, dims, dims); - ASSERT(info == GrB_SUCCESS); - } - - // flush pending changes if dirty - // we need to call 'RG_Matrix_isDirty' again - // as 'RG_Matrix_resize' might require 'wait' for HyperSparse matrices - if(RG_Matrix_isDirty(m)) { - info = RG_Matrix_wait(m, false); - ASSERT(info == GrB_SUCCESS); - } - - ASSERT(RG_Matrix_isDirty(m) == false); - -cleanup: - // unlock matrix mutex - RG_Matrix_Unlock(m); + Delta_Matrix_synchronize(M, nrows, ncols); } // resize matrix to node capacity void _MatrixResizeToCapacity ( - const Graph *g, - RG_Matrix m + const Graph *g, // graph the matrix is related to + Delta_Matrix M, // matrix to synchronize + GrB_Index nrows, // # of rows for the resize + GrB_Index ncols // # of columns for the resize ) { - GrB_Index nrows; - GrB_Index ncols; - RG_Matrix_ncols(&ncols, m); - RG_Matrix_nrows(&nrows, m); - GrB_Index cap = Graph_RequiredMatrixDim(g); + GrB_Index n_rows; + GrB_Index n_cols; + Delta_Matrix_nrows(&n_rows, M); + Delta_Matrix_ncols(&n_cols, M); // this policy should only be used in a thread-safe context, // so no locking is required - if(nrows != cap || ncols != cap) { - GrB_Info res = RG_Matrix_resize(m, cap, cap); + if(n_rows < nrows || n_cols < ncols) { + GrB_Info res = Delta_Matrix_resize(M, nrows, ncols); ASSERT(res == GrB_SUCCESS); } } @@ -252,8 +166,10 @@ void _MatrixResizeToCapacity // do not update matrices void _MatrixNOP ( - const Graph *g, - RG_Matrix matrix + const Graph *g, // graph the matrix is related to + Delta_Matrix M, // matrix to synchronize + GrB_Index nrows, // # of rows for the resize + GrB_Index ncols // # of columns for the resize ) { return; } @@ -317,8 +233,8 @@ void Graph_ApplyAllPending ) { ASSERT(g != NULL); - uint n = 0; - RG_Matrix M = NULL; + uint n = 0; + Delta_Matrix M = NULL; // set matrix sync policy, backup previous sync policy MATRIX_POLICY policy = Graph_SetMatrixPolicy(g, SYNC_POLICY_FLUSH_RESIZE); @@ -329,28 +245,30 @@ void Graph_ApplyAllPending // sync the adjacency matrix M = Graph_GetAdjacencyMatrix(g, false); - RG_Matrix_wait(M, force_flush); + Delta_Matrix_wait(M, force_flush); // sync node labels matrix M = Graph_GetNodeLabelMatrix(g); - RG_Matrix_wait(M, force_flush); + Delta_Matrix_wait(M, force_flush); // sync the zero matrix M = Graph_GetZeroMatrix(g); - RG_Matrix_wait(M, force_flush); + Delta_Matrix_wait(M, force_flush); // sync each label matrix n = array_len(g->labels); for(int i = 0; i < n; i ++) { M = Graph_GetLabelMatrix(g, i); - RG_Matrix_wait(M, force_flush); + Delta_Matrix_wait(M, force_flush); } // sync each relation matrix n = array_len(g->relations); for(int i = 0; i < n; i ++) { M = Graph_GetRelationMatrix(g, i, false); - RG_Matrix_wait(M, force_flush); + Delta_Matrix_wait(M, force_flush); + M = Graph_GetMultiEdgeRelationMatrix(g, i); + Delta_Matrix_wait(M, force_flush); } // restore previous matrix sync policy @@ -366,16 +284,16 @@ bool Graph_Pending GrB_Info info; UNUSED(info); - uint n = 0; - RG_Matrix M = NULL; - bool pending = false; + uint n = 0; + Delta_Matrix M = NULL; + bool pending = false; //-------------------------------------------------------------------------- // see if ADJ matrix contains pending changes //-------------------------------------------------------------------------- M = g->adjacency_matrix; - info = RG_Matrix_pending(M, &pending); + info = Delta_Matrix_pending(M, &pending); ASSERT(info == GrB_SUCCESS); if(pending) { return true; @@ -386,18 +304,7 @@ bool Graph_Pending //-------------------------------------------------------------------------- M = g->node_labels; - info = RG_Matrix_pending(M, &pending); - ASSERT(info == GrB_SUCCESS); - if(pending) { - return true; - } - - //-------------------------------------------------------------------------- - // see if the zero matrix contains pending changes - //-------------------------------------------------------------------------- - - M = g->_zero_matrix; - info = RG_Matrix_pending(M, &pending); + info = Delta_Matrix_pending(M, &pending); ASSERT(info == GrB_SUCCESS); if(pending) { return true; @@ -410,7 +317,7 @@ bool Graph_Pending n = array_len(g->labels); for(int i = 0; i < n; i ++) { M = g->labels[i]; - info = RG_Matrix_pending(M, &pending); + info = Delta_Matrix_pending(M, &pending); ASSERT(info == GrB_SUCCESS); if(pending) { return true; @@ -423,8 +330,14 @@ bool Graph_Pending n = array_len(g->relations); for(int i = 0; i < n; i ++) { - M = g->relations[i]; - info = RG_Matrix_pending(M, &pending); + M = g->relations[i].R; + info = Delta_Matrix_pending(M, &pending); + ASSERT(info == GrB_SUCCESS); + if(pending) { + return true; + } + M = g->relations[i].E; + info = Delta_Matrix_pending(M, &pending); ASSERT(info == GrB_SUCCESS); if(pending) { return true; @@ -449,17 +362,16 @@ Graph *Graph_New g->nodes = DataBlock_New(node_cap, node_cap, sizeof(AttributeSet), cb); g->edges = DataBlock_New(edge_cap, edge_cap, sizeof(AttributeSet), cb); - g->labels = array_new(RG_Matrix, GRAPH_DEFAULT_LABEL_CAP); - g->relations = array_new(RG_Matrix, GRAPH_DEFAULT_RELATION_TYPE_CAP); + g->labels = array_new(Delta_Matrix, GRAPH_DEFAULT_LABEL_CAP); + g->relations = array_new(MultiEdgeMatrix, GRAPH_DEFAULT_RELATION_TYPE_CAP); GrB_Info info; UNUSED(info); GrB_Index n = Graph_RequiredMatrixDim(g); - RG_Matrix_new(&g->node_labels, GrB_BOOL, n, n); - RG_Matrix_new(&g->adjacency_matrix, GrB_BOOL, n, n); - RG_Matrix_new(&g->adjacency_matrix->transposed, GrB_BOOL, n, n); - RG_Matrix_new(&g->_zero_matrix, GrB_BOOL, n, n); + Delta_Matrix_new(&g->node_labels, GrB_BOOL, n, n, false); + Delta_Matrix_new(&g->adjacency_matrix, GrB_BOOL, n, n, true); + Delta_Matrix_new(&g->_zero_matrix, GrB_BOOL, n, n, false); // init graph statistics GraphStatistics_init(&g->stats); @@ -569,55 +481,6 @@ bool Graph_GetEdge return (e->attributes != NULL); } -RelationID Graph_GetEdgeRelation -( - const Graph *g, - Edge *e -) { - ASSERT(g); - ASSERT(e); - - GrB_Info info; - RelationID rel = GRAPH_NO_RELATION; - EdgeID id = ENTITY_GET_ID(e); - NodeID src_id = Edge_GetSrcNodeID(e); - NodeID dest_id = Edge_GetDestNodeID(e); - - // search for relation mapping matrix M, where M[dest,src] == edge ID - uint n = array_len(g->relations); - for(uint i = 0; i < n; i++) { - EdgeID edgeId = 0; - RG_Matrix M = Graph_GetRelationMatrix(g, i, false); - info = RG_Matrix_extractElement_UINT64(&edgeId, M, src_id, dest_id); - if(info != GrB_SUCCESS) continue; - - if(SINGLE_EDGE(edgeId)) { - EdgeID curEdgeID = edgeId; - if(curEdgeID == id) { - Edge_SetRelationID(e, i); - rel = i; - break; - } - } else { - // multiple edges exists between src and dest - // see if given edge is one of them - EdgeID *edges = (EdgeID *)(CLEAR_MSB(edgeId)); - int edge_count = array_len(edges); - for(int j = 0; j < edge_count; j++) { - if(edges[j] == id) { - Edge_SetRelationID(e, i); - rel = i; - break; - } - } - } - } - - // we must be able to find edge relation - ASSERT(rel != GRAPH_NO_RELATION); - return rel; -} - void Graph_GetEdgesConnectingNodes ( const Graph *g, @@ -723,17 +586,17 @@ void Graph_LabelNode GrB_Info info; UNUSED(info); - RG_Matrix nl = Graph_GetNodeLabelMatrix(g); + Delta_Matrix nl = Graph_GetNodeLabelMatrix(g); for(uint i = 0; i < lbl_count; i++) { LabelID l = lbls[i]; - RG_Matrix L = Graph_GetLabelMatrix(g, l); + Delta_Matrix L = Graph_GetLabelMatrix(g, l); // set matrix at position [id, id] - info = RG_Matrix_setElement_BOOL(L, id, id); + info = Delta_Matrix_setElement_BOOL(L, id, id); ASSERT(info == GrB_SUCCESS); // map this label in this node's set of labels - info = RG_Matrix_setElement_BOOL(nl, id, l); + info = Delta_Matrix_setElement_BOOL(nl, id, l); ASSERT(info == GrB_SUCCESS); // update labels statistics @@ -753,8 +616,8 @@ bool Graph_IsNodeLabeled bool x; // consult with labels matrix - RG_Matrix nl = Graph_GetNodeLabelMatrix(g); - GrB_Info info = RG_Matrix_extractElement_BOOL(&x, nl, id, l); + Delta_Matrix nl = Graph_GetNodeLabelMatrix(g); + GrB_Info info = Delta_Matrix_extractElement_BOOL(&x, nl, id, l); ASSERT(info == GrB_SUCCESS || info == GrB_NO_VALUE); return info == GrB_SUCCESS; } @@ -775,17 +638,17 @@ void Graph_RemoveNodeLabels GrB_Info info; UNUSED(info); - RG_Matrix nl = Graph_GetNodeLabelMatrix(g); + Delta_Matrix nl = Graph_GetNodeLabelMatrix(g); for(uint i = 0; i < lbl_count; i++) { LabelID l = lbls[i]; - RG_Matrix M = Graph_GetLabelMatrix(g, l); + Delta_Matrix M = Graph_GetLabelMatrix(g, l); // remove matrix at position [id, id] - info = RG_Matrix_removeElement_BOOL(M, id, id); + info = Delta_Matrix_removeElement(M, id, id); ASSERT(info == GrB_SUCCESS); // remove this label from node's set of labels - info = RG_Matrix_removeElement_BOOL(nl, id, l); + info = Delta_Matrix_removeElement(nl, id, l); ASSERT(info == GrB_SUCCESS); // a label was removed from node, update statistics @@ -793,7 +656,7 @@ void Graph_RemoveNodeLabels } } -bool Graph_FormConnection +void Graph_FormConnection ( Graph *g, NodeID src, @@ -805,22 +668,20 @@ bool Graph_FormConnection GrB_Info info; UNUSED(info); - RG_Matrix M = Graph_GetRelationMatrix(g, r, false); - RG_Matrix adj = Graph_GetAdjacencyMatrix(g, false); + // sync matrices + Graph_GetRelationMatrix(g, r, false); + Graph_GetMultiEdgeRelationMatrix(g, r); + + Delta_Matrix adj = Graph_GetAdjacencyMatrix(g, false); // rows represent source nodes, columns represent destination nodes - info = RG_Matrix_setElement_BOOL(adj, src, dest); - // incase of decoding it is possible to write outside of matrix bounds - // exit early - if(info != GrB_SUCCESS) return false; + info = Delta_Matrix_setElement_BOOL(adj, src, dest); + ASSERT(info == GrB_SUCCESS); - info = RG_Matrix_setElement_UINT64(M, edge_id, src, dest); - if(info != GrB_SUCCESS) return false; + MultiEdgeMatrix_FormConnection(g->relations + r, src, dest, edge_id); // an edge of type r has just been created, update statistics GraphStatistics_IncEdgeCount(&g->stats, r, 1); - - return true; } void Graph_CreateEdge @@ -854,9 +715,40 @@ void Graph_CreateEdge Graph_FormConnection(g, src, dest, id, r); } -// retrieves all either incoming or outgoing edges -// to/from given node N, depending on given direction -void Graph_GetNodeEdges +void _GetOutgoingNodeEdges +( + const Graph *g, // graph to collect edges from + const Node *n, // either source or destination node + RelationID edgeType, // relationship type + Edge **edges // [output] array of edges +) { + ASSERT(g); + ASSERT(n); + ASSERT(edges); + ASSERT(edgeType != GRAPH_NO_RELATION && edgeType != GRAPH_UNKNOWN_RELATION); + + GrB_Info info; + MultiEdgeIterator it = {0}; + NodeID src_id = ENTITY_GET_ID(n); + NodeID dest_id = INVALID_ENTITY_ID; + EdgeID edge_id = INVALID_ENTITY_ID; + UNUSED(info); + + Graph_GetRelationMatrix(g, edgeType, false); + Graph_GetMultiEdgeRelationMatrix(g, edgeType); + + Edge e = {.src_id = src_id, .relationID = edgeType}; + MultiEdgeIterator_AttachSourceRange(&it, g->relations + edgeType, src_id, src_id, false); + while(MultiEdgeIterator_next(&it, NULL, &dest_id, &edge_id)) { + e.dest_id = dest_id; + e.id = edge_id; + e.attributes = DataBlock_GetItem(g->edges, edge_id); + ASSERT(e.attributes); + array_append(*edges, e); + } +} + +void _GetIncomingNodeEdges ( const Graph *g, // graph to collect edges from const Node *n, // either source or destination node @@ -867,17 +759,44 @@ void Graph_GetNodeEdges ASSERT(g); ASSERT(n); ASSERT(edges); + ASSERT(edgeType != GRAPH_NO_RELATION && edgeType != GRAPH_UNKNOWN_RELATION); - GrB_Type t; GrB_Info info; - RG_MatrixTupleIter it = {0}; - RG_Matrix M = NULL; - RG_Matrix TM = NULL; - NodeID srcID = ENTITY_GET_ID(n); - NodeID destID = INVALID_ENTITY_ID; - EdgeID edgeID = INVALID_ENTITY_ID; + MultiEdgeIterator it = {0}; + NodeID src_id = INVALID_ENTITY_ID; + NodeID dest_id = ENTITY_GET_ID(n); + EdgeID edge_id = INVALID_ENTITY_ID; UNUSED(info); + Graph_GetRelationMatrix(g, edgeType, false); + Graph_GetRelationMatrix(g, edgeType, true); + Graph_GetMultiEdgeRelationMatrix(g, edgeType); + + Edge e = {.dest_id = dest_id, .relationID = edgeType}; + MultiEdgeIterator_AttachSourceRange(&it, g->relations + edgeType, dest_id, dest_id, true); + while(MultiEdgeIterator_next(&it, &src_id, NULL, &edge_id)) { + e.src_id = src_id; + e.id = edge_id; + e.attributes = DataBlock_GetItem(g->edges, edge_id); + ASSERT(e.attributes); + array_append(*edges, e); + } +} + +// retrieves all either incoming or outgoing edges +// to/from given node N, depending on given direction +void Graph_GetNodeEdges +( + const Graph *g, // graph to collect edges from + const Node *n, // either source or destination node + GRAPH_EDGE_DIR dir, // edge direction ->, <-, <-> + RelationID edgeType, // relationship type + Edge **edges // [output] array of edges +) { + ASSERT(g); + ASSERT(n); + ASSERT(edges); + if(edgeType == GRAPH_UNKNOWN_RELATION) return; bool outgoing = (dir == GRAPH_EDGE_DIR_OUTGOING || @@ -886,59 +805,28 @@ void Graph_GetNodeEdges bool incoming = (dir == GRAPH_EDGE_DIR_INCOMING || dir == GRAPH_EDGE_DIR_BOTH); - // if a relationship type is specified, - // retrieve the appropriate relation matrix - // otherwise use the overall adjacency matrix - M = Graph_GetRelationMatrix(g, edgeType, false); - if(outgoing) { - info = RG_Matrix_type(&t, M); - ASSERT(info == GrB_SUCCESS); - ASSERT(t == GrB_UINT64 || t == GrB_BOOL); - // construct an iterator to traverse over the source node row, - // containing all outgoing edges - RG_MatrixTupleIter_AttachRange(&it, M, srcID, srcID); - if(t == GrB_UINT64) { - while(RG_MatrixTupleIter_next_UINT64(&it, NULL, &destID, &edgeID) == GrB_SUCCESS) { - // collect all edges (src)->(dest) - _CollectEdgesFromEntry(g, srcID, destID, edgeType, edgeID, edges); - } + if(edgeType != GRAPH_NO_RELATION) { + _GetOutgoingNodeEdges(g, n, edgeType, edges); } else { - while(RG_MatrixTupleIter_next_BOOL(&it, NULL, &destID, NULL) == GrB_SUCCESS) { - Graph_GetEdgesConnectingNodes(g, srcID, destID, edgeType, edges); + // relation type missing, scan through each edge type + int relationCount = Graph_RelationTypeCount(g); + for(int i = 0; i < relationCount; i++) { + _GetOutgoingNodeEdges(g, n, i, edges); } } - RG_MatrixTupleIter_detach(&it); } if(incoming) { - // if a relationship type is specified, retrieve the appropriate - // transposed relation matrix, - // otherwise use the transposed adjacency matrix - TM = Graph_GetRelationMatrix(g, edgeType, true); - - info = RG_Matrix_type(&t, M); - ASSERT(info == GrB_SUCCESS); - ASSERT(t == GrB_UINT64 || t == GrB_BOOL); - - // construct an iterator to traverse over the source node row, - // containing all incoming edges - RG_MatrixTupleIter_AttachRange(&it, TM, srcID, srcID); - - if(t == GrB_UINT64) { - while(RG_MatrixTupleIter_next_UINT64(&it, NULL, &destID, NULL) == GrB_SUCCESS) { - RG_Matrix_extractElement_UINT64(&edgeID, M, destID, srcID); - if(dir == GRAPH_EDGE_DIR_BOTH && srcID == destID) continue; - // collect all edges connecting destId to srcId - _CollectEdgesFromEntry(g, destID, srcID, edgeType, edgeID, edges); - } + if(edgeType != GRAPH_NO_RELATION) { + _GetIncomingNodeEdges(g, n, dir, edgeType, edges); } else { - while(RG_MatrixTupleIter_next_BOOL(&it, NULL, &destID, NULL) == GrB_SUCCESS) { - if(dir == GRAPH_EDGE_DIR_BOTH && srcID == destID) continue; - Graph_GetEdgesConnectingNodes(g, destID, srcID, edgeType, edges); + // relation type missing, scan through each edge type + int relationCount = Graph_RelationTypeCount(g); + for(int i = 0; i < relationCount; i++) { + _GetIncomingNodeEdges(g, n, dir, i, edges); } } - RG_MatrixTupleIter_detach(&it); } } @@ -953,13 +841,10 @@ uint64_t Graph_GetNodeDegree ASSERT(g != NULL); ASSERT(n != NULL); - NodeID srcID = ENTITY_GET_ID(n); - NodeID destID = INVALID_ENTITY_ID; - EdgeID edgeID = INVALID_ENTITY_ID; - uint64_t edge_count = 0; - RG_Matrix M = NULL; - RG_Matrix TM = NULL; - RG_MatrixTupleIter it = {0}; + NodeID srcID = ENTITY_GET_ID(n); + NodeID destID = INVALID_ENTITY_ID; + EdgeID edgeID = INVALID_ENTITY_ID; + uint64_t edge_count = 0; if(edgeType == GRAPH_UNKNOWN_RELATION) { return 0; // no edges @@ -987,32 +872,23 @@ uint64_t Graph_GetNodeDegree // for each relationship type to consider for(edgeType = start_rel; edgeType < end_rel; edgeType++) { - M = Graph_GetRelationMatrix(g, edgeType, false); - //---------------------------------------------------------------------- // outgoing edges //---------------------------------------------------------------------- - // TODO: revisit once we get rid of MULTI-EDGE hack + Graph_GetRelationMatrix(g, edgeType, false); + Graph_GetMultiEdgeRelationMatrix(g, edgeType); + if(outgoing) { + MultiEdgeIterator it = {0}; // construct an iterator to traverse over the source node row, // containing all outgoing edges - RG_MatrixTupleIter_AttachRange(&it, M, srcID, srcID); + MultiEdgeIterator_AttachSourceRange(&it, g->relations + edgeType, srcID, srcID, false); + // scan row - while(RG_MatrixTupleIter_next_UINT64(&it, NULL, &destID, &edgeID) - == GrB_SUCCESS) { - - // check for edge type single/multi - if(SINGLE_EDGE(edgeID)) { - edge_count++; - } else { - // multiple edges connecting src to dest - // entry is a pointer to an array of edge IDs - EdgeID *multi_edge = (EdgeID *)(CLEAR_MSB(edgeID)); - edge_count += array_len(multi_edge); - } + while(MultiEdgeIterator_next(&it, NULL, NULL, &edgeID)) { + edge_count++; } - RG_MatrixTupleIter_detach(&it); } //---------------------------------------------------------------------- @@ -1020,27 +896,16 @@ uint64_t Graph_GetNodeDegree //---------------------------------------------------------------------- if(incoming) { - // transposed relation matrix - TM = Graph_GetRelationMatrix(g, edgeType, true); - + Graph_GetRelationMatrix(g, edgeType, true); + MultiEdgeIterator it = {0}; // construct an iterator to traverse over the source node row, // containing all incoming edges - RG_MatrixTupleIter_AttachRange(&it, TM, srcID, srcID); - while(RG_MatrixTupleIter_next_BOOL(&it, NULL, &destID, NULL) - == GrB_SUCCESS) { - - // check for edge type single/multi - RG_Matrix_extractElement_UINT64(&edgeID, M, destID, srcID); - if(SINGLE_EDGE(edgeID)) { - edge_count++; - } else { - // multiple edges connecting src to dest - // entry is a pointer to an array of edge IDs - EdgeID *multi_edge = (EdgeID *)(CLEAR_MSB(edgeID)); - edge_count += array_len(multi_edge); - } + MultiEdgeIterator_AttachSourceRange(&it, g->relations + edgeType, srcID, srcID, true); + + // scan row + while(MultiEdgeIterator_next(&it, NULL, NULL, &edgeID)) { + edge_count++; } - RG_MatrixTupleIter_detach(&it); } } @@ -1063,98 +928,28 @@ uint Graph_GetNodeLabels GrB_Info res; UNUSED(res); - // GrB_Col_extract will iterate over the range of the output size - RG_Matrix M = Graph_GetNodeLabelMatrix(g); + Delta_Matrix M = Graph_GetNodeLabelMatrix(g); EntityID id = ENTITY_GET_ID(n); - RG_MatrixTupleIter iter = {0}; - res = RG_MatrixTupleIter_AttachRange(&iter, M, id, id); + Delta_MatrixTupleIter iter = {0}; + res = Delta_MatrixTupleIter_AttachRange(&iter, M, id, id); ASSERT(res == GrB_SUCCESS); uint i = 0; for(; i < label_count; i++) { GrB_Index col; - res = RG_MatrixTupleIter_next_BOOL(&iter, NULL, &col, NULL); + res = Delta_MatrixTupleIter_next_BOOL(&iter, NULL, &col, NULL); labels[i] = col; if(res == GxB_EXHAUSTED) break; } - RG_MatrixTupleIter_detach(&iter); + Delta_MatrixTupleIter_detach(&iter); return i; } -// removes edges from Graph and updates graph relevant matrices -void Graph_DeleteEdges -( - Graph *g, - Edge *edges, - uint64_t n -) { - ASSERT(g != NULL); - ASSERT(n > 0); - ASSERT(edges != NULL); - - uint64_t x; - RG_Matrix R; - RG_Matrix M; - GrB_Info info; - bool entry_deleted; - - MATRIX_POLICY policy = Graph_SetMatrixPolicy(g, SYNC_POLICY_NOP); - - for (uint i = 0; i < n; i++) { - Edge *e = edges + i; - int r = Edge_GetRelationID(e); - NodeID src_id = Edge_GetSrcNodeID(e); - NodeID dest_id = Edge_GetDestNodeID(e); - - ASSERT(!DataBlock_ItemIsDeleted((void *)e->attributes)); - - // an edge of type r has just been deleted, update statistics - GraphStatistics_DecEdgeCount(&g->stats, r, 1); - - R = Graph_GetRelationMatrix(g, r, false); - - // single edge of type R connecting src to dest, delete entry - info = RG_Matrix_removeEntry_UINT64(R, src_id, dest_id, ENTITY_GET_ID(e), &entry_deleted); - ASSERT(info == GrB_SUCCESS); - - if(entry_deleted) { - // TODO: consider making ADJ UINT64_T where ADJ[i,j] = #connections - // drop the entry once it reaches 0 - // - // see if source is connected to destination with additional edges - bool connected = false; - int relationCount = Graph_RelationTypeCount(g); - for(int i = 0; i < relationCount; i++) { - if(i == r) continue; - M = Graph_GetRelationMatrix(g, i, false); - info = RG_Matrix_extractElement_UINT64(&x, M, src_id, dest_id); - if(info == GrB_SUCCESS) { - connected = true; - break; - } - } - - // there are no additional edges connecting source to destination - // remove edge from THE adjacency matrix - if(!connected) { - M = Graph_GetAdjacencyMatrix(g, false); - info = RG_Matrix_removeElement_BOOL(M, src_id, dest_id); - ASSERT(info == GrB_SUCCESS); - } - } - - // free and remove edges from datablock. - DataBlock_DeleteItem(g->edges, ENTITY_GET_ID(e)); - } - - Graph_SetMatrixPolicy(g, policy); -} - inline bool Graph_EntityIsDeleted ( const GraphEntity *e @@ -1172,7 +967,9 @@ static void _Graph_FreeRelationMatrices const Graph *g ) { uint relationCount = Graph_RelationTypeCount(g); - for(uint i = 0; i < relationCount; i++) RG_Matrix_free(&g->relations[i]); + for(uint i = 0; i < relationCount; i++) { + MultiEdgeMatrix_free(g->relations + i); + } } DataBlockIterator *Graph_ScanNodes(const Graph *g) { @@ -1191,13 +988,12 @@ LabelID Graph_AddLabel ) { ASSERT(g != NULL); - RG_Matrix m; + Delta_Matrix m; GrB_Info info; size_t n = Graph_RequiredMatrixDim(g); - RG_Matrix_new(&m, GrB_BOOL, n, n); + Delta_Matrix_new(&m, GrB_BOOL, n, n, false); array_append(g->labels, m); - // adding a new label, update the stats structures to support it GraphStatistics_IntroduceLabel(&g->stats); @@ -1215,12 +1011,12 @@ void Graph_RemoveLabel #ifdef RG_DEBUG GrB_Index nvals; - GrB_Info info = RG_Matrix_nvals(&nvals, g->labels[label_id]); + GrB_Info info = Delta_Matrix_nvals(&nvals, g->labels[label_id]); ASSERT(info == GrB_SUCCESS); ASSERT(nvals == 0); #endif - RG_Matrix_free(&g->labels[label_id]); + Delta_Matrix_free(&g->labels[label_id]); g->labels = array_del(g->labels, label_id); } @@ -1230,13 +1026,13 @@ RelationID Graph_AddRelationType ) { ASSERT(g); - RG_Matrix m; + MultiEdgeMatrix r; size_t n = Graph_RequiredMatrixDim(g); + size_t edge_cap = g->edges->itemCap; - RG_Matrix_new(&m, GrB_UINT64, n, n); - - array_append(g->relations, m); + MultiEdgeMatrix_init(&r, n, n, edge_cap, edge_cap); + array_append(g->relations, r); // adding a new relationship type, update the stats structures to support it GraphStatistics_IntroduceRelationship(&g->stats); @@ -1253,15 +1049,15 @@ void Graph_RemoveRelation ASSERT(relation_id == Graph_RelationTypeCount(g) - 1); #ifdef RG_DEBUG GrB_Index nvals; - GrB_Info info = RG_Matrix_nvals(&nvals, g->relations[relation_id]); + GrB_Info info = Delta_Matrix_nvals(&nvals, g->relations[relation_id].R); ASSERT(info == GrB_SUCCESS); ASSERT(nvals == 0); #endif - RG_Matrix_free(&g->relations[relation_id]); + MultiEdgeMatrix_free(g->relations + relation_id); g->relations = array_del(g->relations, relation_id); } -RG_Matrix Graph_GetLabelMatrix +Delta_Matrix Graph_GetLabelMatrix ( const Graph *g, LabelID label_idx @@ -1272,13 +1068,14 @@ RG_Matrix Graph_GetLabelMatrix // return zero matrix if label_idx is out of range if(label_idx < 0) return Graph_GetZeroMatrix(g); - RG_Matrix m = g->labels[label_idx]; - g->SynchronizeMatrix(g, m); + Delta_Matrix m = g->labels[label_idx]; + size_t n = Graph_RequiredMatrixDim(g); + g->SynchronizeMatrix(g, m, n, n); return m; } -RG_Matrix Graph_GetRelationMatrix +Delta_Matrix Graph_GetRelationMatrix ( const Graph *g, RelationID relation_idx, @@ -1288,22 +1085,40 @@ RG_Matrix Graph_GetRelationMatrix ASSERT(relation_idx == GRAPH_NO_RELATION || relation_idx < Graph_RelationTypeCount(g)); - RG_Matrix m = GrB_NULL; + Delta_Matrix m = GrB_NULL; if(relation_idx == GRAPH_NO_RELATION) { m = g->adjacency_matrix; } else { - m = g->relations[relation_idx]; + m = g->relations[relation_idx].R; } - g->SynchronizeMatrix(g, m); + size_t n = Graph_RequiredMatrixDim(g); + g->SynchronizeMatrix(g, m, n, n); + + if(transposed) m = Delta_Matrix_getTranspose(m); + + return m; +} + +Delta_Matrix Graph_GetMultiEdgeRelationMatrix +( + const Graph *g, + RelationID relation_idx +) { + ASSERT(g); + ASSERT(relation_idx != GRAPH_NO_RELATION && + relation_idx < Graph_RelationTypeCount(g)); + + Delta_Matrix m = g->relations[relation_idx].E; - if(transposed) m = RG_Matrix_getTranspose(m); + size_t edge_cap = g->edges->itemCap; + g->SynchronizeMatrix(g, m, edge_cap, edge_cap); return m; } -RG_Matrix Graph_GetAdjacencyMatrix +Delta_Matrix Graph_GetAdjacencyMatrix ( const Graph *g, bool transposed @@ -1320,38 +1135,40 @@ bool Graph_RelationshipContainsMultiEdge bool transpose ) { ASSERT(Graph_RelationTypeCount(g) > r); + GrB_Index nvals; - // A relationship matrix contains multi-edge if nvals < number of edges with type r. - RG_Matrix R = Graph_GetRelationMatrix(g, r, transpose); - RG_Matrix_nvals(&nvals, R); + Delta_Matrix R = Graph_GetMultiEdgeRelationMatrix(g, r); + Delta_Matrix_nvals(&nvals, R); - return (Graph_RelationEdgeCount(g, r) > nvals); + return nvals > 0; } -RG_Matrix Graph_GetNodeLabelMatrix +Delta_Matrix Graph_GetNodeLabelMatrix ( const Graph *g ) { ASSERT(g != NULL); - RG_Matrix m = g->node_labels; + Delta_Matrix m = g->node_labels; - g->SynchronizeMatrix(g, m); + size_t n = Graph_RequiredMatrixDim(g); + g->SynchronizeMatrix(g, m, n, n); return m; } -RG_Matrix Graph_GetZeroMatrix +Delta_Matrix Graph_GetZeroMatrix ( const Graph *g ) { - RG_Matrix z = g->_zero_matrix; - g->SynchronizeMatrix(g, z); + Delta_Matrix z = g->_zero_matrix; + size_t n = Graph_RequiredMatrixDim(g); + g->SynchronizeMatrix(g, z, n, n); #if RG_DEBUG // make sure zero matrix is indeed empty GrB_Index nvals; - RG_Matrix_nvals(&nvals, z); + Delta_Matrix_nvals(&nvals, z); ASSERT(nvals == 0); #endif @@ -1368,17 +1185,17 @@ static void _Graph_Free AttributeSet *set; DataBlockIterator *it; - RG_Matrix_free(&g->_zero_matrix); - RG_Matrix_free(&g->adjacency_matrix); + Delta_Matrix_free(&g->_zero_matrix); + Delta_Matrix_free(&g->adjacency_matrix); _Graph_FreeRelationMatrices(g); array_free(g->relations); GraphStatistics_FreeInternals(&g->stats); uint32_t labelCount = array_len(g->labels); - for(int i = 0; i < labelCount; i++) RG_Matrix_free(&g->labels[i]); + for(int i = 0; i < labelCount; i++) Delta_Matrix_free(&g->labels[i]); array_free(g->labels); - RG_Matrix_free(&g->node_labels); + Delta_Matrix_free(&g->node_labels); it = is_full_graph ? Graph_ScanNodes(g) : DataBlock_FullScan(g->nodes); while((set = (AttributeSet *)DataBlockIterator_Next(it, NULL)) != NULL) { diff --git a/src/graph/graph.h b/src/graph/graph.h index 13a63ac30..651663ca3 100644 --- a/src/graph/graph.h +++ b/src/graph/graph.h @@ -9,14 +9,15 @@ #include #include "rax.h" +#include "GraphBLAS.h" #include "entities/node.h" #include "entities/edge.h" #include "../redismodule.h" #include "graph_statistics.h" -#include "rg_matrix/rg_matrix.h" +#include "multi_edge_matrix.h" +#include "delta_matrix/delta_matrix.h" #include "../util/datablock/datablock.h" #include "../util/datablock/datablock_iterator.h" -#include "../../deps/GraphBLAS/Include/GraphBLAS.h" #define GRAPH_DEFAULT_RELATION_TYPE_CAP 16 // default number of different relationship types a graph can hold before resizing. #define GRAPH_DEFAULT_LABEL_CAP 16 // default number of different labels a graph can hold before resizing. @@ -41,17 +42,17 @@ typedef enum { // forward declaration of Graph struct typedef struct Graph Graph; // typedef for synchronization function pointer -typedef void (*SyncMatrixFunc)(const Graph *, RG_Matrix); +typedef void (*SyncMatrixFunc)(const Graph *, Delta_Matrix, GrB_Index, GrB_Index); struct Graph { int reserved_node_count; // number of nodes not commited yet DataBlock *nodes; // graph nodes stored in blocks DataBlock *edges; // graph edges stored in blocks - RG_Matrix adjacency_matrix; // adjacency matrix, holds all graph connections - RG_Matrix *labels; // label matrices - RG_Matrix node_labels; // mapping of all node IDs to all labels possessed by each node - RG_Matrix *relations; // relation matrices - RG_Matrix _zero_matrix; // zero matrix + Delta_Matrix adjacency_matrix; // adjacency matrix, holds all graph connections + Delta_Matrix *labels; // label matrices + Delta_Matrix node_labels; // mapping of all node IDs to all labels possessed by each node + MultiEdgeMatrix *relations; // relation matrices + Delta_Matrix _zero_matrix; // zero matrix pthread_rwlock_t _rwlock; // read-write lock scoped to this specific graph bool _writelocked; // true if the read-write lock was acquired by a writer SyncMatrixFunc SynchronizeMatrix; // function pointer to matrix synchronization routine @@ -335,14 +336,6 @@ bool Graph_GetEdge Edge *e ); -// retrieves edge relation type -// returns GRAPH_NO_RELATION if edge has no relation type -RelationID Graph_GetEdgeRelation -( - const Graph *g, - Edge *e -); - // retrieves edges connecting source to destination, // relation is optional, pass GRAPH_NO_RELATION if you do not care // about edge type @@ -385,7 +378,7 @@ uint Graph_GetNodeLabels // retrieves the adjacency matrix // matrix is resized if its size doesn't match graph's node count -RG_Matrix Graph_GetAdjacencyMatrix +Delta_Matrix Graph_GetAdjacencyMatrix ( const Graph *g, bool transposed @@ -393,7 +386,7 @@ RG_Matrix Graph_GetAdjacencyMatrix // retrieves a label matrix // matrix is resized if its size doesn't match graph's node count -RG_Matrix Graph_GetLabelMatrix +Delta_Matrix Graph_GetLabelMatrix ( const Graph *g, // graph from which to get adjacency matrix int label // label described by matrix @@ -401,16 +394,24 @@ RG_Matrix Graph_GetLabelMatrix // retrieves a typed adjacency matrix // matrix is resized if its size doesn't match graph's node count -RG_Matrix Graph_GetRelationMatrix +Delta_Matrix Graph_GetRelationMatrix ( - const Graph *g, // graph from which to get adjacency matrix - int relation, // relation described by matrix + const Graph *g, // graph from which to get adjacency matrix + RelationID relation_idx, // relation described by matrix bool transposed ); +// retrieves a typed multi-edge matrix +// matrix is resized if its size doesn't match graph's node count +Delta_Matrix Graph_GetMultiEdgeRelationMatrix +( + const Graph *g, // graph from which to get multi-edge matrix + RelationID relation_idx // relation described by matrix +); + // retrieves the node-label mapping matrix, // matrix is resized if its size doesn't match graph's node count. -RG_Matrix Graph_GetNodeLabelMatrix +Delta_Matrix Graph_GetNodeLabelMatrix ( const Graph *g ); @@ -418,17 +419,11 @@ RG_Matrix Graph_GetNodeLabelMatrix // retrieves the zero matrix // the function will resize it to match all other // internal matrices, caller mustn't modify it in any way -RG_Matrix Graph_GetZeroMatrix +Delta_Matrix Graph_GetZeroMatrix ( const Graph *g ); -RG_Matrix Graph_GetLabelRGMatrix -( - const Graph *g, - int label_idx -); - // free partial graph void Graph_PartialFree ( diff --git a/src/graph/graph_delete_edges.c b/src/graph/graph_delete_edges.c new file mode 100644 index 000000000..6c4bbde8a --- /dev/null +++ b/src/graph/graph_delete_edges.c @@ -0,0 +1,149 @@ +/* + * Copyright FalkorDB Ltd. 2023 - present + * Licensed under the Server Side Public License v1 (SSPLv1). + */ + +#include "RG.h" +#include "graph.h" +#include "../util/arr.h" +#include "delta_matrix/delta_matrix_iter.h" + +// removes edges from Graph and updates graph relevant matrices +// +// edge deletion is performed in two steps +// 1. simple edge deletion +// each edge is removed from the relation matrix if it is the +// only edge check if need to remove from the adjacency matrix +// otherwise delete it from the multi-edge matrix +// 2. update multi-edge state +// each edge that was connected as multi edge check if we can +// transform it to single edge or delete it completly +void Graph_DeleteEdges +( + Graph *g, + Edge *edges, + uint64_t n +) { + ASSERT(g != NULL); + ASSERT(n > 0); + ASSERT(edges != NULL); + + GrB_Info info; + Delta_Matrix M; + Delta_Matrix E; + + MATRIX_POLICY policy = Graph_SetMatrixPolicy(g, SYNC_POLICY_NOP); + + // delete edges without considering multi edge state changes + for (uint i = 0; i < n; i++) { + Edge *e = edges + i; + int r = Edge_GetRelationID(e); + NodeID src_id = Edge_GetSrcNodeID(e); + NodeID dest_id = Edge_GetDestNodeID(e); + EdgeID edge_id = ENTITY_GET_ID(e); + + ASSERT(!DataBlock_ItemIsDeleted((void *)e->attributes)); + + // an edge of type r has just been deleted, update statistics + GraphStatistics_DecEdgeCount(&g->stats, r, 1); + + M = Graph_GetRelationMatrix(g, r, false); + + GrB_Index me_id; + info = Delta_Matrix_extractElement_UINT64(&me_id, M, src_id, dest_id); + ASSERT(info == GrB_SUCCESS); + + if(SINGLE_EDGE(me_id)) { + info = Delta_Matrix_removeElement(M, src_id, dest_id); + ASSERT(info == GrB_SUCCESS); + ASSERT(me_id == edge_id); + + // see if source is connected to destination with additional edges + bool connected = false; + int relationCount = Graph_RelationTypeCount(g); + for(int j = 0; j < relationCount; j++) { + if(j == r) continue; + Delta_Matrix r = Graph_GetRelationMatrix(g, j, false); + info = Delta_Matrix_extractElement_BOOL(NULL, r, src_id, dest_id); + if(info == GrB_SUCCESS) { + connected = true; + break; + } + } + + // there are no additional edges connecting source to destination + // remove edge from THE adjacency matrix + if(!connected) { + Delta_Matrix adj = Graph_GetAdjacencyMatrix(g, false); + info = Delta_Matrix_removeElement(adj, src_id, dest_id); + ASSERT(info == GrB_SUCCESS); + } + } else { + E = Graph_GetMultiEdgeRelationMatrix(g, r); + me_id = CLEAR_MSB(me_id); + info = Delta_Matrix_removeElement(E, me_id, edge_id); + ASSERT(info == GrB_SUCCESS); + } + + // free and remove edges from datablock. + DataBlock_DeleteItem(g->edges, edge_id); + } + + // check if multi edge can be transformed to single edge or deleted completely + for (uint i = 0; i < n; i++) { + Edge *e = edges + i; + int r = Edge_GetRelationID(e); + NodeID src_id = Edge_GetSrcNodeID(e); + NodeID dest_id = Edge_GetDestNodeID(e); + EdgeID edge_id = ENTITY_GET_ID(e); + + M = Graph_GetRelationMatrix(g, r, false); + + GrB_Index id; + info = Delta_Matrix_extractElement_UINT64(&id, M, src_id, dest_id); + if(info != GrB_SUCCESS || SINGLE_EDGE(id)) continue; + + E = Graph_GetMultiEdgeRelationMatrix(g, r); + id = CLEAR_MSB(id); + Delta_MatrixTupleIter it = {0}; + Delta_MatrixTupleIter_AttachRange(&it, E, id, id); + GrB_Index last_edge_id; + uint count = 0; + while (Delta_MatrixTupleIter_next_BOOL(&it, NULL, &last_edge_id, NULL) == GrB_SUCCESS) { + count++; + if(count == 2) break; + } + + if(count == 0) { + info = Delta_Matrix_removeElement(M, src_id, dest_id); + ASSERT(info == GrB_SUCCESS); + + // see if source is connected to destination with additional edges + bool connected = false; + int relationCount = Graph_RelationTypeCount(g); + for(int j = 0; j < relationCount; j++) { + if(j == r) continue; + Delta_Matrix r = Graph_GetRelationMatrix(g, j, false); + info = Delta_Matrix_extractElement_BOOL(NULL, r, src_id, dest_id); + if(info == GrB_SUCCESS) { + connected = true; + break; + } + } + + // there are no additional edges connecting source to destination + // remove edge from THE adjacency matrix + if(!connected) { + Delta_Matrix adj = Graph_GetAdjacencyMatrix(g, false); + info = Delta_Matrix_removeElement(adj, src_id, dest_id); + ASSERT(info == GrB_SUCCESS); + } + } else if(count == 1) { + Delta_Matrix_removeElement(E, id, last_edge_id); + Delta_Matrix_setElement_UINT64(M, last_edge_id, src_id, dest_id); + array_append(g->relations[r].freelist, id); + } + } + + Graph_SetMatrixPolicy(g, policy); +} diff --git a/src/graph/graph_delete_nodes.c b/src/graph/graph_delete_nodes.c index 6e3ba73eb..dca8833b7 100644 --- a/src/graph/graph_delete_nodes.c +++ b/src/graph/graph_delete_nodes.c @@ -6,7 +6,8 @@ #include "RG.h" #include "graph.h" -#include "rg_matrix/rg_matrix_iter.h" +#include "../util/arr.h" +#include "delta_matrix/delta_matrix_iter.h" // deletes nodes from the graph // @@ -58,33 +59,26 @@ void Graph_DeleteNodes // update label matrices //-------------------------------------------------------------------------- - GrB_Index j; // iterated entry col idx - GrB_Scalar s; // empty scalar - GrB_Matrix M; // delta M - GrB_Matrix DP; // delta plus - GrB_Matrix DM; // delta minus - GrB_Info info; // GraphBLAS return code - GrB_Index nrows; // lbls row count - GrB_Index ncols; // lbls col count - GrB_Matrix lbls_mask; // lbls mask - RG_MatrixTupleIter it; // matrix iterator - - // create empty scalar - GrB_Scalar_new(&s, GrB_BOOL); + GrB_Index j; // iterated entry col idx + GrB_Info info; // GraphBLAS return code + GrB_Index nrows; // lbls row count + GrB_Index ncols; // lbls col count + GrB_Matrix elems; // elements to delete + Delta_MatrixTupleIter it; // matrix iterator // get labels matrix - RG_Matrix lbls = Graph_GetNodeLabelMatrix(g); + Delta_Matrix lbls = Graph_GetNodeLabelMatrix(g); // create lbls mask - info = RG_Matrix_nrows(&nrows, lbls); + info = Delta_Matrix_nrows(&nrows, lbls); ASSERT(info == GrB_SUCCESS); - info = RG_Matrix_ncols(&ncols, lbls); + info = Delta_Matrix_ncols(&ncols, lbls); ASSERT(info == GrB_SUCCESS); - info = GrB_Matrix_new(&lbls_mask, GrB_BOOL, nrows, ncols); + info = GrB_Matrix_new(&elems, GrB_BOOL, nrows, ncols); ASSERT(info == GrB_SUCCESS); // attach iterator to lbls matrix - RG_MatrixTupleIter_attach(&it, lbls); + Delta_MatrixTupleIter_attach(&it, lbls); //-------------------------------------------------------------------------- // phase one @@ -96,18 +90,18 @@ void Graph_DeleteNodes Node *n = nodes + i; EntityID id = ENTITY_GET_ID(n); - info = RG_MatrixTupleIter_iterate_row(&it, id); + info = Delta_MatrixTupleIter_iterate_row(&it, id); ASSERT(info == GrB_SUCCESS); // for each deleted node label - while(RG_MatrixTupleIter_next_BOOL(&it, NULL, &j, NULL) == GrB_SUCCESS) { + while(Delta_MatrixTupleIter_next_BOOL(&it, NULL, &j, NULL) == GrB_SUCCESS) { // populate lbls mask - info = GrB_Matrix_setElement_BOOL(lbls_mask, true, id, j); + info = GrB_Matrix_setElement_BOOL(elems, true, id, j); ASSERT(info == GrB_SUCCESS); // clear label matrix j at position [id,id] - RG_Matrix L = Graph_GetLabelMatrix(g, j); - info = RG_Matrix_removeElement_BOOL(L, id, id); + Delta_Matrix L = Graph_GetLabelMatrix(g, j); + info = Delta_Matrix_removeElement(L, id, id); ASSERT(info == GrB_SUCCESS); // a label was removed from node, update statistics @@ -122,27 +116,11 @@ void Graph_DeleteNodes // phase two //-------------------------------------------------------------------------- - // update labels matrix - M = RG_MATRIX_M(lbls); - DP = RG_MATRIX_DELTA_PLUS(lbls); - DM = RG_MATRIX_DELTA_MINUS(lbls); - - info = GrB_Matrix_assign_Scalar(DP, lbls_mask, NULL, s, GrB_ALL, nrows, - GrB_ALL, ncols, GrB_DESC_S); - ASSERT(info == GrB_SUCCESS); - - info = GrB_Matrix_assign(DM, lbls_mask, NULL, M, GrB_ALL, nrows, GrB_ALL, - ncols, GrB_DESC_S); - ASSERT(info == GrB_SUCCESS); - - // mark labels matrix as dirty - RG_Matrix_setDirty(lbls); + Delta_Matrix_removeElements(lbls, elems); // restore matrix sync policy Graph_SetMatrixPolicy(g, policy); - // clean up - GrB_free(&s); - GrB_free(&lbls_mask); + GrB_free(&elems); } diff --git a/src/graph/graph_hub.c b/src/graph/graph_hub.c index 88c35d596..01acbd6f3 100644 --- a/src/graph/graph_hub.c +++ b/src/graph/graph_hub.c @@ -332,7 +332,7 @@ void UpdateNodeLabels // sync matrix // make sure label matrix is of the right dimensions if(schema_created) { - RG_Matrix m = Graph_GetLabelMatrix(gc->g, schema_id); + Delta_Matrix m = Graph_GetLabelMatrix(gc->g, schema_id); } // append label id add_labels_ids[add_labels_index++] = schema_id; diff --git a/src/graph/graph_statistics.c b/src/graph/graph_statistics.c index 9a1c592e1..2ff0da68b 100644 --- a/src/graph/graph_statistics.c +++ b/src/graph/graph_statistics.c @@ -70,4 +70,3 @@ void GraphStatistics_FreeInternals if(stats->node_count) array_free(stats->node_count); if(stats->edge_count) array_free(stats->edge_count); } - diff --git a/src/graph/graph_statistics.h b/src/graph/graph_statistics.h index f17a6270f..061f9755f 100644 --- a/src/graph/graph_statistics.h +++ b/src/graph/graph_statistics.h @@ -99,4 +99,3 @@ void GraphStatistics_FreeInternals ( GraphStatistics *stats ); - diff --git a/src/graph/multi_edge_matrix.c b/src/graph/multi_edge_matrix.c new file mode 100644 index 000000000..c2cc2f24c --- /dev/null +++ b/src/graph/multi_edge_matrix.c @@ -0,0 +1,242 @@ +/* + * Copyright FalkorDB Ltd. 2023 - present + * Licensed under the Server Side Public License v1 (SSPLv1). + */ + +#include "RG.h" +#include "util/arr.h" +#include "multi_edge_matrix.h" +#include "delta_matrix/delta_matrix_iter.h" + +bool _DepletedIter +( + MultiEdgeIterator *it, + NodeID *src, + NodeID *dest, + EdgeID *edge_id +) { + ASSERT(it != NULL); + + return false; +} + +bool _SourceTransposeIter +( + MultiEdgeIterator *it, + NodeID *src, + NodeID *dest, + EdgeID *edge_id +) { + ASSERT(it != NULL); + + if(Delta_MatrixTupleIter_is_attached(&it->e_it, it->M->E)) { + GrB_Info info = Delta_MatrixTupleIter_next_BOOL(&it->e_it, NULL, edge_id, NULL); + if(info == GrB_SUCCESS) { + if(src) *src = it->src; + if(dest) *dest = it->dest; + return true; + } + Delta_MatrixTupleIter_detach(&it->e_it); + } + + GrB_Info info = Delta_MatrixTupleIter_next_BOOL(&it->r_it, &it->dest, &it->src, NULL); + if(info == GrB_SUCCESS) { + if(src) *src = it->src; + if(dest) *dest = it->dest; + Delta_Matrix_extractElement_UINT64(edge_id, it->M->R, it->src, it->dest); + if(!SINGLE_EDGE(*edge_id)) { + Delta_MatrixTupleIter_AttachRange(&it->e_it, it->M->E, CLEAR_MSB(*edge_id), CLEAR_MSB(*edge_id)); + GrB_Info info = Delta_MatrixTupleIter_next_BOOL(&it->e_it, NULL, edge_id, NULL); + ASSERT(info == GrB_SUCCESS); + } + return true; + } + it->iter_func = _DepletedIter; + return false; +} + +bool _SourceIter +( + MultiEdgeIterator *it, + NodeID *src, + NodeID *dest, + EdgeID *edge_id +) { + ASSERT(it != NULL); + + if(Delta_MatrixTupleIter_is_attached(&it->e_it, it->M->E)) { + GrB_Info info = Delta_MatrixTupleIter_next_BOOL(&it->e_it, NULL, edge_id, NULL); + if(info == GrB_SUCCESS) { + if(src) *src = it->src; + if(dest) *dest = it->dest; + return true; + } + Delta_MatrixTupleIter_detach(&it->e_it); + } + + GrB_Info info = Delta_MatrixTupleIter_next_UINT64(&it->r_it, &it->src, &it->dest, edge_id); + if(info == GrB_SUCCESS) { + if(src) *src = it->src; + if(dest) *dest = it->dest; + if(!SINGLE_EDGE(*edge_id)) { + Delta_MatrixTupleIter_AttachRange(&it->e_it, it->M->E, CLEAR_MSB(*edge_id), CLEAR_MSB(*edge_id)); + info = Delta_MatrixTupleIter_next_BOOL(&it->e_it, NULL, edge_id, NULL); + ASSERT(info == GrB_SUCCESS); + } + return true; + } + it->iter_func = _DepletedIter; + return false; +} + +bool _SourceDestSingleEdgeIter +( + MultiEdgeIterator *it, + NodeID *src, + NodeID *dest, + EdgeID *edge_id +) { + ASSERT(it != NULL); + + *edge_id = it->edge_id; + it->iter_func = _DepletedIter; + return true; +} + +bool _SourceDestMultiEdgeIter +( + MultiEdgeIterator *it, + NodeID *src, + NodeID *dest, + EdgeID *edge_id +) { + ASSERT(it != NULL); + + GrB_Info info = Delta_MatrixTupleIter_next_BOOL(&it->e_it, NULL, edge_id, NULL); + return info == GrB_SUCCESS; +} + +void MultiEdgeIterator_AttachSourceRange +( + MultiEdgeIterator *it, + MultiEdgeMatrix *M, + NodeID min_src_id, + NodeID max_src_id, + bool transposed +) { + ASSERT(it != NULL); + ASSERT(M != NULL); + + it->M = M; + if(transposed) { + Delta_MatrixTupleIter_AttachRange(&it->r_it, Delta_Matrix_getTranspose(M->R), min_src_id, max_src_id); + it->iter_func = _SourceTransposeIter; + } else { + Delta_MatrixTupleIter_AttachRange(&it->r_it, M->R, min_src_id, max_src_id); + it->iter_func = _SourceIter; + } +} + +void MultiEdgeIterator_AttachSourceDest +( + MultiEdgeIterator *it, + MultiEdgeMatrix *M, + NodeID src_id, + NodeID dest_id +) { + ASSERT(it != NULL); + ASSERT(M != NULL); + + it->M = M; + GrB_Info res = Delta_Matrix_extractElement_UINT64(&it->edge_id, it->M->R, src_id, dest_id); + if(res == GrB_SUCCESS) { + if(SINGLE_EDGE(it->edge_id)) { + it->iter_func = _SourceDestSingleEdgeIter; + } else { + Delta_MatrixTupleIter_AttachRange(&it->e_it, it->M->E, CLEAR_MSB(it->edge_id), CLEAR_MSB(it->edge_id)); + it->iter_func = _SourceDestMultiEdgeIter; + } + } else { + it->iter_func = _DepletedIter; + } +} + +bool MultiEdgeIterator_next +( + MultiEdgeIterator *it, + NodeID *src, + NodeID *dest, + EdgeID *edge_id +) { + ASSERT(it != NULL); + + return it->iter_func(it, src, dest, edge_id); +} + +bool MultiEdgeIterator_is_attached +( + MultiEdgeIterator *it, + MultiEdgeMatrix *M +) { + ASSERT(it != NULL); + ASSERT(M != NULL); + + return it->M == M; +} + +void MultiEdgeMatrix_init +( + MultiEdgeMatrix *M, + GrB_Index nrows, + GrB_Index ncols, + GrB_Index me_nrows, + GrB_Index me_ncols +) { + ASSERT(M != NULL); + + Delta_Matrix_new(&M->R, GrB_UINT64, nrows, ncols, true); + Delta_Matrix_new(&M->E, GrB_BOOL, me_nrows, me_ncols, false); + M->row_id = 0; + M->freelist = array_new(uint64_t, 0); +} + +void MultiEdgeMatrix_FormConnection +( + MultiEdgeMatrix *M, + NodeID src, + NodeID dest, + EdgeID edge_id +) { + ASSERT(M != NULL); + + GrB_Index current_edge; + GrB_Info info = Delta_Matrix_extractElement_UINT64(¤t_edge, M->R, src, dest); + if(info == GrB_NO_VALUE) { + info = Delta_Matrix_setElement_UINT64(M->R, edge_id, src, dest); + ASSERT(info == GrB_SUCCESS); + } else if(SINGLE_EDGE(current_edge)) { + GrB_Index meid = array_len(M->freelist) > 0 + ? array_pop(M->freelist) + : M->row_id++; + info = Delta_Matrix_setElement_UINT64(M->R, SET_MSB(meid), src, dest); + ASSERT(info == GrB_SUCCESS); + info = Delta_Matrix_setElement_BOOL(M->E, meid, current_edge); + ASSERT(info == GrB_SUCCESS); + info = Delta_Matrix_setElement_BOOL(M->E, meid, edge_id); + ASSERT(info == GrB_SUCCESS); + } else { + info = Delta_Matrix_setElement_BOOL(M->E, CLEAR_MSB(current_edge), edge_id); + ASSERT(info == GrB_SUCCESS); + } +} + +void MultiEdgeMatrix_free +( + MultiEdgeMatrix *M +) { + ASSERT(M != NULL); + + Delta_Matrix_free(&M->R); + Delta_Matrix_free(&M->E); + array_free(M->freelist); +} \ No newline at end of file diff --git a/src/graph/multi_edge_matrix.h b/src/graph/multi_edge_matrix.h new file mode 100644 index 000000000..e900b125d --- /dev/null +++ b/src/graph/multi_edge_matrix.h @@ -0,0 +1,98 @@ +/* + * Copyright FalkorDB Ltd. 2023 - present + * Licensed under the Server Side Public License v1 (SSPLv1). + */ + +#pragma once + +#include "entities/node.h" +#include "entities/edge.h" +#include "delta_matrix/delta_matrix.h" +#include "delta_matrix/delta_matrix_iter.h" + +// Checks if X represents edge ID +#define SINGLE_EDGE(x) !((x) & MSB_MASK) + +typedef struct MultiEdgeIterator MultiEdgeIterator; +typedef bool (*IterFunc)(MultiEdgeIterator *, NodeID *, NodeID *, EdgeID *); + +// A relation type is defined via two matrices: +// 1. uint64 connecting source nodes to destination nodes +// 2. multi-edge, O[meid,e] = true +typedef struct { + Delta_Matrix R; // relation matrix + Delta_Matrix E; // multi-edge matrix + uint64_t row_id; // multi-edge id + uint64_t *freelist; // multi-edge deleted ids +} MultiEdgeMatrix; + +// Multi edge matrix iterator +struct MultiEdgeIterator { + MultiEdgeMatrix *M; // multi-edge matrix + Delta_MatrixTupleIter r_it; // relation matrix iterator + Delta_MatrixTupleIter e_it; // multi-edge matrix iterator + EdgeID edge_id; // edge id + NodeID src; // src id + NodeID dest; // dest id + IterFunc iter_func; // iteration strategy +}; + +// attach iterator by source range +void MultiEdgeIterator_AttachSourceRange +( + MultiEdgeIterator *it, // multi-edge iterator + MultiEdgeMatrix *M, // multi-edge matrix + NodeID min_src_id, // minimum source id + NodeID max_src_id, // maximum source id + bool transposed // transpose to traverse incoming edges +); + +// attach iterator by source and destination +void MultiEdgeIterator_AttachSourceDest +( + MultiEdgeIterator *it, // multi-edge iterator + MultiEdgeMatrix *M, // multi-edge matrix + NodeID src_id, // source id + NodeID dest_id // dest id +); + +// get the next edge +bool MultiEdgeIterator_next +( + MultiEdgeIterator *it, // multi-edge iterator + NodeID *src, // [out] source id + NodeID *dest, // [out] dest id + EdgeID *edge_id // [out] edge id +); + +// whether iterator is attached to a matrix +bool MultiEdgeIterator_is_attached +( + MultiEdgeIterator *it, // multi-edge iterator + MultiEdgeMatrix *M // multi-edge matrix +); + +// init new multi-edge matrix +void MultiEdgeMatrix_init +( + MultiEdgeMatrix *M, // multi-edge matrix + GrB_Index nrows, // # of rows + GrB_Index ncols, // # of columns + GrB_Index me_nrows, // # of multi-edge rows + GrB_Index me_ncols // # of multi-edge columns +); + +// create edge between src and dest +void MultiEdgeMatrix_FormConnection +( + MultiEdgeMatrix *M, // multi-edge matrix + NodeID src, // source id + NodeID dest, // dest id + EdgeID edge_id // edge id +); + +// free multi-edge matrix +void MultiEdgeMatrix_free +( + MultiEdgeMatrix *M // multi-edge matrix +); \ No newline at end of file diff --git a/src/graph/rg_matrix/rg_add.c b/src/graph/rg_matrix/rg_add.c deleted file mode 100644 index b1d9b0013..000000000 --- a/src/graph/rg_matrix/rg_add.c +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ - -#include "RG.h" -#include "rg_matrix.h" - -GrB_Info RG_eWiseAdd // C = A + B -( - RG_Matrix C, // input/output matrix for results - const GrB_Semiring semiring, // defines '+' for T=A+B - const RG_Matrix A, // first input: matrix A - const RG_Matrix B // second input: matrix B -) { - ASSERT(A != NULL); - ASSERT(B != NULL); - ASSERT(C != NULL); - ASSERT(semiring != NULL); - - GrB_Info info; - GrB_Index nrows; - GrB_Index ncols; - GrB_Index DM_nvals; - GrB_Index DP_nvals; - - GrB_Matrix _A = NULL; - GrB_Matrix _B = NULL; - GrB_Matrix _C = RG_MATRIX_M(C); - GrB_Matrix AM = RG_MATRIX_M(A); - GrB_Matrix BM = RG_MATRIX_M(B); - GrB_Matrix ADP = RG_MATRIX_DELTA_PLUS(A); - GrB_Matrix ADM = RG_MATRIX_DELTA_MINUS(A); - GrB_Matrix BDP = RG_MATRIX_DELTA_PLUS(B); - GrB_Matrix BDM = RG_MATRIX_DELTA_MINUS(B); - - // TODO: check A, B and C are compatible - - GrB_Matrix_nvals(&DM_nvals, ADM); - GrB_Matrix_nvals(&DP_nvals, ADP); - if(DM_nvals > 0 || DP_nvals > 0) { - info = RG_Matrix_export(&_A, A); - ASSERT(info == GrB_SUCCESS); - } else { - _A = AM; - } - - GrB_Matrix_nvals(&DM_nvals, BDM); - GrB_Matrix_nvals(&DP_nvals, BDP); - if(DM_nvals > 0 || DP_nvals > 0) { - info = RG_Matrix_export(&_B, B); - ASSERT(info == GrB_SUCCESS); - } else { - _B = BM; - } - - //-------------------------------------------------------------------------- - // C = A + B - //-------------------------------------------------------------------------- - - info = GrB_Matrix_eWiseAdd_Semiring(_C, NULL, NULL, semiring, _A, _B, NULL); - ASSERT(info == GrB_SUCCESS); - - if(_A != AM) GrB_free(&_A); - if(_B != BM) GrB_free(&_B); - - return info; -} - diff --git a/src/graph/rg_matrix/rg_copy.c b/src/graph/rg_matrix/rg_copy.c deleted file mode 100644 index d182b597b..000000000 --- a/src/graph/rg_matrix/rg_copy.c +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ - -#include "RG.h" -#include "rg_utils.h" -#include "rg_matrix.h" -#include "../../util/rmalloc.h" - -static void _copyMatrix -( - const GrB_Matrix in, - GrB_Matrix out -) { - GrB_Index nvals; - GrB_Info info = GrB_SUCCESS; - - UNUSED(info); - - info = GrB_Matrix_nvals(&nvals, in); - ASSERT(info == GrB_SUCCESS); - - if(nvals > 0) { - info = GrB_Matrix_apply(out, NULL, NULL, GrB_IDENTITY_BOOL, in, - GrB_DESC_R); - } - else { - GrB_Matrix_clear(out); - } - - ASSERT(info == GrB_SUCCESS); -} - -GrB_Info RG_Matrix_copy -( - RG_Matrix C, - const RG_Matrix A -) { - RG_Matrix_checkCompatible(C, A); - - GrB_Matrix in_m = RG_MATRIX_M(A); - GrB_Matrix out_m = RG_MATRIX_M(C); - GrB_Matrix in_delta_plus = RG_MATRIX_DELTA_PLUS(A); - GrB_Matrix in_delta_minus = RG_MATRIX_DELTA_MINUS(A); - GrB_Matrix out_delta_plus = RG_MATRIX_DELTA_PLUS(C); - GrB_Matrix out_delta_minus = RG_MATRIX_DELTA_MINUS(C); - - _copyMatrix(in_m, out_m); - _copyMatrix(in_delta_plus, out_delta_plus); - _copyMatrix(in_delta_minus, out_delta_minus); - - return GrB_SUCCESS; -} - diff --git a/src/graph/rg_matrix/rg_export.c b/src/graph/rg_matrix/rg_export.c deleted file mode 100644 index dec65a4e7..000000000 --- a/src/graph/rg_matrix/rg_export.c +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ - -#include "RG.h" -#include "rg_matrix.h" -#include "../../util/rmalloc.h" - -GrB_Info RG_Matrix_export -( - GrB_Matrix *A, - RG_Matrix C -) { - ASSERT(C != NULL); - ASSERT(A != NULL); - - GrB_Type t; - GrB_Index nrows; - GrB_Index ncols; - GrB_Index dp_nvals; - GrB_Index dm_nvals; - GrB_Matrix a = NULL; - GrB_Matrix m = RG_MATRIX_M(C); - GrB_Info info = GrB_SUCCESS; - GrB_Matrix dp = RG_MATRIX_DELTA_PLUS(C); - GrB_Matrix dm = RG_MATRIX_DELTA_MINUS(C); - - info = GxB_Matrix_type(&t, m); - ASSERT(info == GrB_SUCCESS); - - info = GrB_Matrix_nrows(&nrows, m); - ASSERT(info == GrB_SUCCESS); - - info = GrB_Matrix_ncols(&ncols, m); - ASSERT(info == GrB_SUCCESS); - - info = GrB_Matrix_new(&a, t, nrows, ncols); - ASSERT(info == GrB_SUCCESS); - - info = GrB_wait(dp, GrB_MATERIALIZE); - ASSERT(info == GrB_SUCCESS); - - info = GrB_wait(dm, GrB_MATERIALIZE); - ASSERT(info == GrB_SUCCESS); - - info = GrB_Matrix_nvals(&dp_nvals, dp); - ASSERT(info == GrB_SUCCESS); - info = GrB_Matrix_nvals(&dm_nvals, dm); - ASSERT(info == GrB_SUCCESS); - - bool additions = dp_nvals > 0; - bool deletions = dm_nvals > 0; - - //-------------------------------------------------------------------------- - // perform copy and deletions if needed - //-------------------------------------------------------------------------- - - // in case there are items to delete use mask otherwise just copy - GrB_Matrix mask = deletions ? dm : NULL; - GrB_Descriptor desc = deletions ? GrB_DESC_RSCT0 : GrB_DESC_RT0; - info = GrB_transpose(a, mask, NULL, m, desc); - ASSERT(info == GrB_SUCCESS); - - //-------------------------------------------------------------------------- - // perform additions - //-------------------------------------------------------------------------- - - if(additions) { - GrB_Semiring s; - s = (t == GrB_BOOL) ? GxB_ANY_PAIR_BOOL : GxB_ANY_PAIR_UINT64; - info = GrB_Matrix_eWiseAdd_Semiring(a, NULL, NULL, s, a, dp, - NULL); - ASSERT(info == GrB_SUCCESS); - } - - *A = a; - - return info; -} - diff --git a/src/graph/rg_matrix/rg_extract.c b/src/graph/rg_matrix/rg_extract.c deleted file mode 100644 index 665dc9355..000000000 --- a/src/graph/rg_matrix/rg_extract.c +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ - -#include "RG.h" -#include "rg_matrix.h" - -GrB_Info RG_Matrix_extractElement_BOOL // x = A(i,j) -( - bool *x, // extracted scalar - const RG_Matrix A, // matrix to extract a scalar from - GrB_Index i, // row index - GrB_Index j // column index -) { - ASSERT(x != NULL); - ASSERT(A != NULL); - - GrB_Info info; - GrB_Matrix m = RG_MATRIX_M(A); - GrB_Matrix dp = RG_MATRIX_DELTA_PLUS(A); - GrB_Matrix dm = RG_MATRIX_DELTA_MINUS(A); - - // if 'delta-plus' exists return dp[i,j] - info = GrB_Matrix_extractElement(x, dp, i, j); - if(info == GrB_SUCCESS) { - return info; - } - - // if dm[i,j] exists, return no value - info = GrB_Matrix_extractElement(x, dm, i, j); - if(info == GrB_SUCCESS) { - // entry marked for deletion - return GrB_NO_VALUE; - } - - // entry isn't marked for deletion, see if it exists in 'm' - info = GrB_Matrix_extractElement(x, m, i, j); - return info; -} - -GrB_Info RG_Matrix_extractElement_UINT64 // x = A(i,j) -( - uint64_t *x, // extracted scalar - const RG_Matrix A, // matrix to extract a scalar from - GrB_Index i, // row index - GrB_Index j // column index -) { - ASSERT(x != NULL); - ASSERT(A != NULL); - - GrB_Info info; - GrB_Matrix m = RG_MATRIX_M(A); - GrB_Matrix dp = RG_MATRIX_DELTA_PLUS(A); - GrB_Matrix dm = RG_MATRIX_DELTA_MINUS(A); - - // if dp[i,j] exists return it - info = GrB_Matrix_extractElement(x, dp, i, j); - if(info == GrB_SUCCESS) { - return info; - } - - // if dm[i,j] exists, return no value - info = GrB_Matrix_extractElement(x, dm, i, j); - if(info == GrB_SUCCESS) { - // entry marked for deletion - return GrB_NO_VALUE; - } - - // entry isn't marked for deletion, see if it exists in 'm' - info = GrB_Matrix_extractElement(x, m, i, j); - return info; -} - diff --git a/src/graph/rg_matrix/rg_free.c b/src/graph/rg_matrix/rg_free.c deleted file mode 100644 index 6d240b233..000000000 --- a/src/graph/rg_matrix/rg_free.c +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ - -#include "RG.h" -#include "rg_matrix.h" -#include "../../util/arr.h" -#include "../../util/rmalloc.h" -#include "../entities/graph_entity.h" - -// free multi-edge arrays GraphBLAS unary operation -static GrB_UnaryOp free_multi_edge_op = NULL; - -// unary GraphBLAS operation which frees all multi-edge array entries -// within a matrix -static void free_multiedge_array(void *out, const void *in) { - EdgeID *_out = (EdgeID *)out; - const EdgeID *id = (const EdgeID *)in; - - if(!(SINGLE_EDGE(*id))) { - // entry is a pointer to dynamic array, free it - EdgeID *ids = (EdgeID *)(CLEAR_MSB(*id)); - array_free(ids); - } - - // set out to 0 - *_out = 0; -} - -// free RG_Matrix's internal matrices: -// M, delta-plus, delta-minus and transpose -void RG_Matrix_free -( - RG_Matrix *C -) { - ASSERT(C != NULL); - RG_Matrix M = *C; - - GrB_Info info; - UNUSED(info); - - if(RG_MATRIX_MAINTAIN_TRANSPOSE(M)) RG_Matrix_free(&M->transposed); - - GrB_Matrix m = RG_MATRIX_M(M); - GrB_Matrix dp = RG_MATRIX_DELTA_PLUS(M); - - // free edges - if(RG_MATRIX_MULTI_EDGE(M)) { - if(free_multi_edge_op == NULL) { - // create unary operation - info = GrB_UnaryOp_new(&free_multi_edge_op, free_multiedge_array, - GrB_UINT64, GrB_UINT64); - ASSERT(info == GrB_SUCCESS); - } - - // frees multi-edge arrays - info = GrB_Matrix_apply(m, NULL, NULL, free_multi_edge_op, m, NULL); - ASSERT(info == GrB_SUCCESS); - info = GrB_Matrix_apply(dp, NULL, NULL, free_multi_edge_op, dp, NULL); - ASSERT(info == GrB_SUCCESS); - } - - info = GrB_Matrix_free(&M->matrix); - ASSERT(info == GrB_SUCCESS); - - info = GrB_Matrix_free(&M->delta_plus); - ASSERT(info == GrB_SUCCESS); - - info = GrB_Matrix_free(&M->delta_minus); - ASSERT(info == GrB_SUCCESS); - - pthread_mutex_destroy(&M->mutex); - - rm_free(M); - - *C = NULL; -} - diff --git a/src/graph/rg_matrix/rg_matrix.c b/src/graph/rg_matrix/rg_matrix.c deleted file mode 100644 index 2caa87811..000000000 --- a/src/graph/rg_matrix/rg_matrix.c +++ /dev/null @@ -1,186 +0,0 @@ -/* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ - -#include "RG.h" -#include "rg_matrix.h" -#include "../../util/rmalloc.h" - -void RG_Matrix_setDirty -( - RG_Matrix C -) { - ASSERT(C); - C->dirty = true; - if(RG_MATRIX_MAINTAIN_TRANSPOSE(C)) C->transposed->dirty = true; -} - -RG_Matrix RG_Matrix_getTranspose -( - const RG_Matrix C -) { - ASSERT(C != NULL); - return C->transposed; -} - -bool RG_Matrix_isDirty -( - const RG_Matrix C -) { - ASSERT(C); - - if(C->dirty) { - return true; - } - - bool pending_M; - bool pending_DP; - bool pending_DM; - - GxB_Matrix_Pending(RG_MATRIX_M(C), &pending_M); - GxB_Matrix_Pending(RG_MATRIX_DELTA_PLUS(C), &pending_DP); - GxB_Matrix_Pending(RG_MATRIX_DELTA_MINUS(C), &pending_DM); - - return (pending_M | pending_DM | pending_DP); -} - -// checks if C is fully synced -// a synced delta matrix does not contains any entries in -// either its delta-plus and delta-minus internal matrices -bool RG_Matrix_Synced -( - const RG_Matrix C // matrix to inquery -) { - ASSERT(C); - - // quick indication, if the matrix is marked as dirty that means - // entires exists in either DP or DM - if(C->dirty) { - return false; - } - - GrB_Index dp_nvals; - GrB_Index dm_nvals; - GrB_Matrix_nvals(&dp_nvals, RG_MATRIX_DELTA_PLUS(C)); - GrB_Matrix_nvals(&dm_nvals, RG_MATRIX_DELTA_MINUS(C)); - - return ((dp_nvals + dm_nvals) == 0); -} - -// locks the matrix -void RG_Matrix_Lock -( - RG_Matrix C -) { - ASSERT(C); - pthread_mutex_lock(&C->mutex); -} - -// unlocks the matrix -void RG_Matrix_Unlock -( - RG_Matrix C -) { - ASSERT(C); - pthread_mutex_unlock(&C->mutex); -} - -GrB_Info RG_Matrix_nrows -( - GrB_Index *nrows, - const RG_Matrix C -) { - ASSERT(C); - ASSERT(nrows); - - GrB_Matrix m = RG_MATRIX_M(C); - return GrB_Matrix_nrows(nrows, m); -} - -GrB_Info RG_Matrix_ncols -( - GrB_Index *ncols, - const RG_Matrix C -) { - ASSERT(C); - ASSERT(ncols); - - GrB_Matrix m = RG_MATRIX_M(C); - return GrB_Matrix_ncols(ncols, m); -} - -GrB_Info RG_Matrix_nvals // get the number of entries in a matrix -( - GrB_Index *nvals, // matrix has nvals entries - const RG_Matrix A // matrix to query -) { - ASSERT(A != NULL); - ASSERT(nvals != NULL); - - GrB_Matrix m; - GrB_Matrix dp; - GrB_Matrix dm; - GrB_Info info; - - GrB_Index m_nvals = 0; - GrB_Index dp_nvals = 0; - GrB_Index dm_nvals = 0; - - // nvals = nvals(M) + nvals(DP) - nvals(DM) - - m = RG_MATRIX_M(A); - dp = RG_MATRIX_DELTA_PLUS(A); - dm = RG_MATRIX_DELTA_MINUS(A); - - info = GrB_Matrix_nvals(&m_nvals, m); - ASSERT(info == GrB_SUCCESS); - info = GrB_Matrix_nvals(&dp_nvals, dp); - ASSERT(info == GrB_SUCCESS); - info = GrB_Matrix_nvals(&dm_nvals, dm); - ASSERT(info == GrB_SUCCESS); - - *nvals = m_nvals + dp_nvals - dm_nvals; - return info; -} - -GrB_Info RG_Matrix_clear -( - RG_Matrix A -) { - ASSERT(A != NULL); - - GrB_Matrix m = RG_MATRIX_M(A); - GrB_Info info = GrB_SUCCESS; - GrB_Matrix delta_plus = RG_MATRIX_DELTA_PLUS(A); - GrB_Matrix delta_minus = RG_MATRIX_DELTA_MINUS(A); - - info = GrB_Matrix_clear(m); - ASSERT(info == GrB_SUCCESS); - - info = GrB_Matrix_clear(m); - ASSERT(info == GrB_SUCCESS); - - info = GrB_Matrix_clear(m); - ASSERT(info == GrB_SUCCESS); - - A->dirty = false; - if(RG_MATRIX_MAINTAIN_TRANSPOSE(A)) A->transposed->dirty = false; - - return info; -} - -GrB_Info RG_Matrix_type -( - GrB_Type *type, - RG_Matrix A -) { - ASSERT(A != NULL); - ASSERT(type != NULL); - - GrB_Matrix M = RG_MATRIX_M(A); - GrB_Info info = GxB_Matrix_type(type, M); - ASSERT(info == GrB_SUCCESS) - return info; -} diff --git a/src/graph/rg_matrix/rg_matrix.h b/src/graph/rg_matrix/rg_matrix.h deleted file mode 100644 index d930ab546..000000000 --- a/src/graph/rg_matrix/rg_matrix.h +++ /dev/null @@ -1,314 +0,0 @@ -/* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ - -#pragma once - -#include "RG.h" -#include "GraphBLAS.h" - -#include - -// forward declaration of RG_Matrix type -typedef struct _RG_Matrix _RG_Matrix; -typedef _RG_Matrix *RG_Matrix; - -// Checks if X represents edge ID. -#define SINGLE_EDGE(x) !((x) & MSB_MASK) - -#define RG_MATRIX_M(C) (C)->matrix -#define RG_MATRIX_DELTA_PLUS(C) (C)->delta_plus -#define RG_MATRIX_DELTA_MINUS(C) (C)->delta_minus - -#define RG_MATRIX_TM(C) (C)->transposed->matrix -#define RG_MATRIX_TDELTA_PLUS(C) (C)->transposed->delta_plus -#define RG_MATRIX_TDELTA_MINUS(C) (C)->transposed->delta_minus - -#define RG_MATRIX_MAINTAIN_TRANSPOSE(C) (C)->transposed != NULL - -#define RG_MATRIX_MULTI_EDGE(M) __extension__({ \ - GrB_Type t; \ - GrB_Matrix m = RG_MATRIX_M(M); \ - GxB_Matrix_type(&t, m); \ - (t == GrB_UINT64); \ -}) - - -//------------------------------------------------------------------------------ -// -// possible combinations -// -//------------------------------------------------------------------------------ -// -// empty -// -// A DP DM -// . . . . . . . . . -// . . . . . . . . . -// . . . . . . . . . -// -//------------------------------------------------------------------------------ -// -// flushed, no pending changes -// -// A DP DM -// . 1 . . . . . . . -// . . . . . . . . . -// . . . . . . . . . -// -//------------------------------------------------------------------------------ -// -// single entry added -// -// A DP DM -// . . . . 1 . . . . -// . . . . . . . . . -// . . . . . . . . . -// -//------------------------------------------------------------------------------ -// -// single entry deleted -// -// A DP DM -// 1 . . . . . 1 . . -// . . . . . . . . . -// . . . . . . . . . -// -//------------------------------------------------------------------------------ -// impossible state -// existing entry deleted and then added back -// -// A DP DM -// 1 . . 1 . . 1 . . -// . . . . . . . . . -// . . . . . . . . . -// -//------------------------------------------------------------------------------ -// -// impossible state -// marked none existing entry for deletion -// -// A DP DM -// . . . . . . 1 . . -// . . . . . . . . . -// . . . . . . . . . -// -//------------------------------------------------------------------------------ -// -// impossible state -// adding to an already existing entry -// should have turned A[0,0] to a multi-value -// -// A DP DM -// 1 . . 1 . . . . . -// . . . . . . . . . -// . . . . . . . . . -// -//------------------------------------------------------------------------------ -// -// impossible state -// deletion of pending entry should have cleared it DP[0,0] -// -// A DP DM -// . . . 1 . . 1 . . -// . . . . . . . . . -// . . . . . . . . . -// -//------------------------------------------------------------------------------ - -struct _RG_Matrix { - volatile bool dirty; // Indicates if matrix requires sync - GrB_Matrix matrix; // Underlying GrB_Matrix - GrB_Matrix delta_plus; // Pending additions - GrB_Matrix delta_minus; // Pending deletions - RG_Matrix transposed; // Transposed matrix - pthread_mutex_t mutex; // Lock -}; - -GrB_Info RG_Matrix_new -( - RG_Matrix *A, // handle of matrix to create - GrB_Type type, // type of matrix to create - GrB_Index nrows, // matrix dimension is nrows-by-ncols - GrB_Index ncols -); - -// returns transposed matrix of C -RG_Matrix RG_Matrix_getTranspose -( - const RG_Matrix C -); - -// mark matrix as dirty -void RG_Matrix_setDirty -( - RG_Matrix C -); - -bool RG_Matrix_isDirty -( - const RG_Matrix C -); - -// checks if C is fully synced -// a synced delta matrix does not contains any entries in -// either its delta-plus and delta-minus internal matrices -bool RG_Matrix_Synced -( - const RG_Matrix C // matrix to inquery -); - -// locks the matrix -void RG_Matrix_Lock -( - RG_Matrix C -); - -// unlocks the matrix -void RG_Matrix_Unlock -( - RG_Matrix C -); - -GrB_Info RG_Matrix_nrows -( - GrB_Index *nrows, - const RG_Matrix C -); - -GrB_Info RG_Matrix_ncols -( - GrB_Index *ncols, - const RG_Matrix C -); - -GrB_Info RG_Matrix_nvals // get the number of entries in a matrix -( - GrB_Index *nvals, // matrix has nvals entries - const RG_Matrix A // matrix to query -); - -GrB_Info RG_Matrix_resize // change the size of a matrix -( - RG_Matrix C, // matrix to modify - GrB_Index nrows_new, // new number of rows in matrix - GrB_Index ncols_new // new number of columns in matrix -); - -GrB_Info RG_Matrix_setElement_BOOL // C (i,j) = x -( - RG_Matrix C, // matrix to modify - GrB_Index i, // row index - GrB_Index j // column index -); - -GrB_Info RG_Matrix_setElement_UINT64 // C (i,j) = x -( - RG_Matrix C, // matrix to modify - uint64_t x, // scalar to assign to C(i,j) - GrB_Index i, // row index - GrB_Index j // column index -); - -GrB_Info RG_Matrix_extractElement_BOOL // x = A(i,j) -( - bool *x, // extracted scalar - const RG_Matrix A, // matrix to extract a scalar from - GrB_Index i, // row index - GrB_Index j // column index -) ; - -GrB_Info RG_Matrix_extractElement_UINT64 // x = A(i,j) -( - uint64_t *x, // extracted scalar - const RG_Matrix A, // matrix to extract a scalar from - GrB_Index i, // row index - GrB_Index j // column index -) ; - -// remove entry at position C[i,j] -GrB_Info RG_Matrix_removeElement_BOOL -( - RG_Matrix C, // matrix to remove entry from - GrB_Index i, // row index - GrB_Index j // column index -); - -GrB_Info RG_Matrix_removeElement_UINT64 -( - RG_Matrix C, // matrix to remove entry from - GrB_Index i, // row index - GrB_Index j // column index -); - -// remove value 'v' from multi-value entry at position C[i,j] -GrB_Info RG_Matrix_removeEntry_UINT64 -( - RG_Matrix C, // matrix to remove entry from - GrB_Index i, // row index - GrB_Index j, // column index - uint64_t v, // value to remove - bool *entry_deleted // is entry deleted -); - -GrB_Info RG_mxm // C = A * B -( - RG_Matrix C, // input/output matrix for results - const GrB_Semiring semiring, // defines '+' and '*' for A*B - const RG_Matrix A, // first input: matrix A - const RG_Matrix B // second input: matrix B -); - -GrB_Info RG_eWiseAdd // C = A + B -( - RG_Matrix C, // input/output matrix for results - const GrB_Semiring semiring, // defines '+' for T=A+B - const RG_Matrix A, // first input: matrix A - const RG_Matrix B // second input: matrix B -); - -GrB_Info RG_Matrix_clear // clear a matrix of all entries; -( // type and dimensions remain unchanged - RG_Matrix A // matrix to clear -); - -GrB_Info RG_Matrix_copy // copy matrix A to matrix C -( - RG_Matrix C, // output matrix - const RG_Matrix A // input matrix -); - -// get matrix C without writing to internal matrix -GrB_Info RG_Matrix_export -( - GrB_Matrix *A, - RG_Matrix C -); - -// checks to see if matrix has pending operations -GrB_Info RG_Matrix_pending -( - const RG_Matrix C, // matrix to query - bool *pending // are there any pending operations -); - -GrB_Info RG_Matrix_wait -( - RG_Matrix C, - bool force_sync -); - -// get the type of the M matrix -GrB_Info RG_Matrix_type -( - GrB_Type *type, - RG_Matrix A -); - -void RG_Matrix_free -( - RG_Matrix *C -); - diff --git a/src/graph/rg_matrix/rg_matrix_iter.c b/src/graph/rg_matrix/rg_matrix_iter.c deleted file mode 100644 index 60402ba77..000000000 --- a/src/graph/rg_matrix/rg_matrix_iter.c +++ /dev/null @@ -1,348 +0,0 @@ -/* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ - -#include "RG.h" -#include "./rg_matrix_iter.h" -#include "../../util/rmalloc.h" - -// returns true if iterator is detached from a matrix -#define IS_DETACHED(iter) ((iter) == NULL || (iter)->A == NULL) - -static inline void _set_iter_range -( - GxB_Iterator it, - GrB_Index min_row, - GrB_Index max_row, - bool *depleted -) { - GrB_Info info = GxB_rowIterator_seekRow (it, min_row) ; - - switch (info) - { - case GxB_EXHAUSTED: - // no values to iterate on - *depleted = true ; - break ; - case GrB_NO_VALUE: - // in sparse matrix no value in the current row - // seek to first none empty row - while (info == GrB_NO_VALUE && GxB_rowIterator_getRowIndex(it) < max_row) { - info = GxB_rowIterator_nextRow (it) ; - } - - *depleted = (info != GrB_SUCCESS || - GxB_rowIterator_getRowIndex(it) > max_row) ; - break ; - case GrB_SUCCESS: - // in hypersparse matrix iterator move to the next row with values - // make sure seekRow didn't over-reached - *depleted = GxB_rowIterator_getRowIndex (it) > max_row; - break ; - default: - ASSERT(false); - break; - } -} - -static inline void _init_iter -( - GxB_Iterator it, - GrB_Matrix m, - GrB_Index min_row, - GrB_Index max_row, - bool *depleted -) { - ASSERT(it != NULL) ; - ASSERT(m != NULL) ; - ASSERT(min_row <= max_row) ; - ASSERT(depleted != NULL) ; - - *depleted = true ; // default - - GrB_Info info ; - UNUSED(info) ; - - info = GxB_rowIterator_attach(it, m, NULL) ; - ASSERT(info == GrB_SUCCESS) ; - _set_iter_range(it, min_row, max_row, depleted) ; -} - -GrB_Info RG_MatrixTupleIter_iterate_row -( - RG_MatrixTupleIter *iter, - GrB_Index rowIdx -) { - if(IS_DETACHED(iter)) return GrB_NULL_POINTER ; - - iter->min_row = rowIdx ; - iter->max_row = rowIdx ; - - _set_iter_range(&iter->m_it, iter->min_row, iter->max_row, &iter->m_depleted) ; - _set_iter_range(&iter->dp_it, iter->min_row, iter->max_row, &iter->dp_depleted) ; - - return GrB_SUCCESS ; -} - -GrB_Info RG_MatrixTupleIter_iterate_range -( - RG_MatrixTupleIter *iter, // iterator to use - GrB_Index startRowIdx, // row index to start with - GrB_Index endRowIdx // row index to finish with -) { - if(IS_DETACHED(iter)) return GrB_NULL_POINTER ; - - iter->min_row = startRowIdx ; - iter->max_row = endRowIdx ; - - _set_iter_range(&iter->m_it, iter->min_row, iter->max_row, &iter->m_depleted) ; - _set_iter_range(&iter->dp_it, iter->min_row, iter->max_row, &iter->dp_depleted) ; - - return GrB_SUCCESS ; -} - -static void _iter_next -( - GxB_Iterator it, - GrB_Index max_row, - bool *depleted -) { - GrB_Info info ; - - info = GxB_rowIterator_nextCol (it) ; - if (info != GrB_SUCCESS) { - info = GxB_rowIterator_nextRow (it) ; - // in-case iterator maintains number of yield values, we can use nvals here - // for a quick return! - while(info == GrB_NO_VALUE && GxB_rowIterator_getRowIndex(it) < max_row) { - info = GxB_rowIterator_nextRow (it) ; - } - - // prep for next call to `_next_m_iter` - *depleted = info != GrB_SUCCESS || GxB_rowIterator_getRowIndex(it) > max_row ; - } -} - -// iterate over M matrix -static GrB_Info _next_m_iter_bool -( - RG_MatrixTupleIter *iter, // iterator scanning M - const GrB_Matrix DM, // delta-minus, masked entries - GrB_Index *row, // optional extracted row index - GrB_Index *col, // optional extracted column index - bool *val, // optional extracted value - bool *depleted // [output] true if iterator depleted -) { - ASSERT(iter != NULL) ; - ASSERT(DM != NULL) ; - ASSERT(depleted != NULL) ; - - GrB_Index _row ; - GrB_Index _col ; - - GxB_Iterator m_it = &iter->m_it ; - - do { - // iterator depleted, return - if(*depleted) return GrB_NO_VALUE ; - - _row = GxB_rowIterator_getRowIndex (m_it) ; - _col = GxB_rowIterator_getColIndex (m_it) ; - if(val) *val = GxB_Iterator_get_BOOL (m_it) ; - - // prep value for next iteration - _iter_next(m_it, iter->max_row, depleted); - - bool x ; - GrB_Info delete_info = GrB_Matrix_extractElement_BOOL(&x, DM, _row, _col) ; - if(delete_info == GrB_NO_VALUE) break ; // entry isn't deleted, return - } while (true) ; - - if(row) *row = _row ; - if(col) *col = _col ; - - return GrB_SUCCESS ; -} - -// advance iterator -GrB_Info RG_MatrixTupleIter_next_BOOL -( - RG_MatrixTupleIter *iter, // iterator to consume - GrB_Index *row, // optional output row index - GrB_Index *col, // optional output column index - bool *val // optional value at A[row, col] -) { - if(IS_DETACHED(iter)) return GrB_NULL_POINTER ; - - GrB_Info info = GrB_SUCCESS ; - GrB_Matrix DM = RG_MATRIX_DELTA_MINUS(iter->A) ; - GxB_Iterator dp_it = &iter->dp_it ; - - if(!iter->m_depleted) { - info = _next_m_iter_bool(iter, DM, row, col, val, &iter->m_depleted) ; - if(info == GrB_SUCCESS) return GrB_SUCCESS ; - } - - if(iter->dp_depleted) { - return GxB_EXHAUSTED ; - } - - if(row) *row = GxB_rowIterator_getRowIndex (dp_it) ; - if(col) *col = GxB_rowIterator_getColIndex (dp_it) ; - if(val) *val = GxB_Iterator_get_BOOL (dp_it) ; - - // prep value for next iteration - _iter_next(dp_it, iter->max_row, &iter->dp_depleted); - - return GrB_SUCCESS ; -} - -// iterate over M matrix -static GrB_Info _next_m_iter_uint64 -( - RG_MatrixTupleIter *iter, // iterator scanning M - const GrB_Matrix DM, // delta-minus, masked entries - GrB_Index *row, // optional extracted row index - GrB_Index *col, // optional extracted column index - uint64_t *val, // optional extracted value - bool *depleted // [output] true if iterator depleted -) { - ASSERT(iter != NULL) ; - ASSERT(DM != NULL) ; - ASSERT(depleted != NULL) ; - - GrB_Index _row ; - GrB_Index _col ; - - GxB_Iterator m_it = &iter->m_it ; - - do { - // iterator depleted, return - if(*depleted) return GrB_NO_VALUE; - - _row = GxB_rowIterator_getRowIndex (m_it) ; - _col = GxB_rowIterator_getColIndex (m_it) ; - if(val) *val = GxB_Iterator_get_UINT64 (m_it) ; - - // prep value for next iteration - _iter_next(m_it, iter->max_row, depleted); - - bool x ; - GrB_Info delete_info = GrB_Matrix_extractElement_BOOL(&x, DM, _row, _col) ; - if(delete_info == GrB_NO_VALUE) break ; // entry isn't deleted, return - } while (true) ; - - if(row) *row = _row ; - if(col) *col = _col ; - - return GrB_SUCCESS ; -} - -// advance iterator -GrB_Info RG_MatrixTupleIter_next_UINT64 -( - RG_MatrixTupleIter *iter, // iterator to consume - GrB_Index *row, // optional output row index - GrB_Index *col, // optional output column index - uint64_t *val // optional value at A[row, col] -) { - if(IS_DETACHED(iter)) return GrB_NULL_POINTER ; - - GrB_Info info = GrB_SUCCESS ; - GrB_Matrix DM = RG_MATRIX_DELTA_MINUS(iter->A) ; - GxB_Iterator dp_it = &iter->dp_it ; - - if(!iter->m_depleted) { - info = _next_m_iter_uint64(iter, DM, row, col, val, &iter->m_depleted) ; - if(info == GrB_SUCCESS) return GrB_SUCCESS ; - } - - if(iter->dp_depleted) { - return GxB_EXHAUSTED ; - } - - if(row) *row = GxB_rowIterator_getRowIndex (dp_it) ; - if(col) *col = GxB_rowIterator_getColIndex (dp_it) ; - if(val) *val = GxB_Iterator_get_UINT64 (dp_it) ; - - // prep value for next iteration - _iter_next(dp_it, iter->max_row, &iter->dp_depleted); - - return GrB_SUCCESS ; -} - -// reset iterator, assumes the iterator is valid -GrB_Info RG_MatrixTupleIter_reset -( - RG_MatrixTupleIter *iter // iterator to reset -) { - GrB_Info info = GrB_SUCCESS; - - if(IS_DETACHED(iter)) return GrB_NULL_POINTER ; - - _set_iter_range(&iter->m_it, iter->min_row, iter->max_row, &iter->m_depleted) ; - _set_iter_range(&iter->dp_it, iter->min_row, iter->max_row, &iter->dp_depleted) ; - - return info ; -} - -// returns true if iterator is attached to given matrix false otherwise -bool RG_MatrixTupleIter_is_attached -( - const RG_MatrixTupleIter *iter, // iterator to check - const RG_Matrix M // matrix attached to -) { - ASSERT(iter != NULL); - - return iter->A == M; -} - -// update iterator to scan given matrix -GrB_Info RG_MatrixTupleIter_attach -( - RG_MatrixTupleIter *iter, // iterator to update - const RG_Matrix A // matrix to scan -) { - return RG_MatrixTupleIter_AttachRange(iter, A, RG_ITER_MIN_ROW, - RG_ITER_MAX_ROW); -} - -// update iterator to scan given matrix -GrB_Info RG_MatrixTupleIter_AttachRange -( - RG_MatrixTupleIter *iter, // iterator to update - const RG_Matrix A, // matrix to scan - GrB_Index min_row, // minimum row for iteration - GrB_Index max_row // maximum row for iteration -) { - if(A == NULL) return GrB_NULL_POINTER ; - if(iter == NULL) return GrB_NULL_POINTER ; - - GrB_Matrix M = RG_MATRIX_M(A) ; - GrB_Matrix DP = RG_MATRIX_DELTA_PLUS(A) ; - - iter->A = A ; - iter->min_row = min_row ; - iter->max_row = max_row ; - - _init_iter(&iter->m_it, M, iter->min_row, iter->max_row, &iter->m_depleted) ; - _init_iter(&iter->dp_it, DP, iter->min_row, iter->max_row, &iter->dp_depleted) ; - - return GrB_SUCCESS ; -} - -// free iterator data -GrB_Info RG_MatrixTupleIter_detach -( - RG_MatrixTupleIter *iter // iterator to free -) { - ASSERT(iter != NULL) ; - - iter->A = NULL ; - iter->m_depleted = true ; - iter->dp_depleted = true ; - - return GrB_SUCCESS ; -} diff --git a/src/graph/rg_matrix/rg_matrix_iter.h b/src/graph/rg_matrix/rg_matrix_iter.h deleted file mode 100644 index 81b10ba03..000000000 --- a/src/graph/rg_matrix/rg_matrix_iter.h +++ /dev/null @@ -1,93 +0,0 @@ -/* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ - -#pragma once - -#include -#include "./rg_matrix.h" -#include "../../deps/GraphBLAS/Include/GraphBLAS.h" - -#define RG_ITER_MIN_ROW 0 -#define RG_ITER_MAX_ROW ULLONG_MAX - -// TuplesIter maintains information required -// to iterate over a RG_Matrix -typedef struct -{ - RG_Matrix A; // matrix iterated - struct GB_Iterator_opaque m_it; // internal m iterator - struct GB_Iterator_opaque dp_it; // internal delta plus iterator - bool m_depleted; // is m iterator depleted - bool dp_depleted; // is dp iterator depleted - GrB_Index min_row; // minimum row for iteration - GrB_Index max_row; // maximum row for iteration -} RG_MatrixTupleIter ; - -// attach iterator to matrix -GrB_Info RG_MatrixTupleIter_attach -( - RG_MatrixTupleIter *iter, // iterator to update - const RG_Matrix A // matrix to scan -); - -// attach iterator to matrix governing the specified range -GrB_Info RG_MatrixTupleIter_AttachRange -( - RG_MatrixTupleIter *iter, // iterator to update - const RG_Matrix A, // matrix to scan - GrB_Index min_row, // minimum row for iteration - GrB_Index max_row // maximum row for iteration -); - -// free iterator internals, keeping the iterator intact -GrB_Info RG_MatrixTupleIter_detach -( - RG_MatrixTupleIter *iter // iterator to free -); - -// returns true if iterator is attached to given matrix false otherwise -bool RG_MatrixTupleIter_is_attached -( - const RG_MatrixTupleIter *iter, // iterator to check - const RG_Matrix M // matrix attached to -); - -GrB_Info RG_MatrixTupleIter_iterate_row -( - RG_MatrixTupleIter *iter, // iterator to use - GrB_Index rowIdx // row to iterate -); - -GrB_Info RG_MatrixTupleIter_iterate_range -( - RG_MatrixTupleIter *iter, // iterator to use - GrB_Index startRowIdx, // row index to start with - GrB_Index endRowIdx // row index to finish with -); - -// advance iterator -GrB_Info RG_MatrixTupleIter_next_BOOL -( - RG_MatrixTupleIter *iter, // iterator to consume - GrB_Index *row, // optional output row index - GrB_Index *col, // optional output column index - bool *val // optional value at A[row, col] -); - -GrB_Info RG_MatrixTupleIter_next_UINT64 -( - RG_MatrixTupleIter *iter, // iterator to consume - GrB_Index *row, // optional output row index - GrB_Index *col, // optional output column index - uint64_t *val // optional value at A[row, col] -); - -// reset iterator -GrB_Info RG_MatrixTupleIter_reset -( - RG_MatrixTupleIter *iter // iterator to reset -); - diff --git a/src/graph/rg_matrix/rg_mxm.c b/src/graph/rg_matrix/rg_mxm.c deleted file mode 100644 index 549f66951..000000000 --- a/src/graph/rg_matrix/rg_mxm.c +++ /dev/null @@ -1,106 +0,0 @@ -/* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ - -#include "RG.h" -#include "rg_matrix.h" - -GrB_Info RG_mxm // C = A * B -( - RG_Matrix C, // input/output matrix for results - const GrB_Semiring semiring, // defines '+' and '*' for A*B - const RG_Matrix A, // first input: matrix A - const RG_Matrix B // second input: matrix B -) { - ASSERT(C != NULL); - ASSERT(A != NULL); - ASSERT(B != NULL); - - // multiply RG_Matrix by RG_Matrix - // A * B - // where A is fully synced! - // - // it is possible for either 'delta-plus' or 'delta-minus' to be empty - // this operation performs: A * B by computing: - // (A * (M + 'delta-plus')) - - // validate A doesn't contains entries in either delta-plus or delta-minus - ASSERT(RG_Matrix_Synced(A)); - - // validate C doesn't contains entries in either delta-plus or delta-minus - ASSERT(RG_Matrix_Synced(C)); - - GrB_Info info; - GrB_Index nrows; // number of rows in result matrix - GrB_Index ncols; // number of columns in result matrix - GrB_Index dp_nvals; // number of entries in A * 'dp' - GrB_Index dm_nvals; // number of entries in A * 'dm' - - GrB_Matrix _A = RG_MATRIX_M(A); - GrB_Matrix _B = RG_MATRIX_M(B); - GrB_Matrix _C = RG_MATRIX_M(C); - GrB_Matrix dp = RG_MATRIX_DELTA_PLUS(B); - GrB_Matrix dm = RG_MATRIX_DELTA_MINUS(B); - GrB_Matrix mask = NULL; // entities removed - GrB_Matrix accum = NULL; // entities added - - RG_Matrix_nrows(&nrows, C); - RG_Matrix_ncols(&ncols, C); - GrB_Matrix_nvals(&dp_nvals, dp); - GrB_Matrix_nvals(&dm_nvals, dm); - - if(dm_nvals > 0) { - // compute A * 'delta-minus' - info = GrB_Matrix_new(&mask, GrB_BOOL, nrows, ncols); - ASSERT(info == GrB_SUCCESS); - - info = GrB_mxm(mask, NULL, NULL, GxB_ANY_PAIR_BOOL, _A, dm, NULL); - ASSERT(info == GrB_SUCCESS); - - // update 'dm_nvals' - info = GrB_Matrix_nvals(&dm_nvals, mask); - ASSERT(info == GrB_SUCCESS); - } - - if(dp_nvals > 0) { - // compute A * 'delta-plus' - info = GrB_Matrix_new(&accum, GrB_BOOL, nrows, ncols); - ASSERT(info == GrB_SUCCESS); - - info = GrB_mxm(accum, NULL, NULL, semiring, _A, dp, NULL); - ASSERT(info == GrB_SUCCESS); - - // update 'dp_nvals' - info = GrB_Matrix_nvals(&dp_nvals, accum); - ASSERT(info == GrB_SUCCESS); - } - - GrB_Descriptor desc = NULL; - bool additions = dp_nvals > 0; - bool deletions = dm_nvals > 0; - - if (deletions) { - desc = GrB_DESC_RSC; - } else { - GrB_free(&mask); - mask = NULL; - } - - // compute (A * B) - info = GrB_mxm(_C, mask, NULL, semiring, _A, _B, desc); - ASSERT(info == GrB_SUCCESS); - - if(additions) { - info = GrB_eWiseAdd(_C, NULL, NULL, GxB_ANY_PAIR_BOOL, _C, accum, NULL); - ASSERT(info == GrB_SUCCESS); - } - - // clean up - if(mask) GrB_free(&mask); - if(accum) GrB_free(&accum); - - return info; -} - diff --git a/src/graph/rg_matrix/rg_new.c b/src/graph/rg_matrix/rg_new.c deleted file mode 100644 index 2f95213d2..000000000 --- a/src/graph/rg_matrix/rg_new.c +++ /dev/null @@ -1,93 +0,0 @@ -/* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ - -#include "RG.h" -#include "rg_matrix.h" -#include "../../util/rmalloc.h" - -static GrB_Info _RG_Matrix_init -( - RG_Matrix A, - GrB_Type type, - GrB_Index nrows, - GrB_Index ncols -) { - GrB_Info info; - A->dirty = false; - - //-------------------------------------------------------------------------- - // create m, delta-plus and delta-minus - //-------------------------------------------------------------------------- - - //-------------------------------------------------------------------------- - // m, can be either hypersparse or sparse - //-------------------------------------------------------------------------- - info = GrB_Matrix_new(&A->matrix, type, nrows, ncols); - ASSERT(info == GrB_SUCCESS); - info = GxB_set(A->matrix, GxB_SPARSITY_CONTROL, GxB_SPARSE | GxB_HYPERSPARSE); - ASSERT(info == GrB_SUCCESS); - - //-------------------------------------------------------------------------- - // delta-plus, always hypersparse - //-------------------------------------------------------------------------- - info = GrB_Matrix_new(&A->delta_plus, type, nrows, ncols); - ASSERT(info == GrB_SUCCESS); - info = GxB_set(A->delta_plus, GxB_SPARSITY_CONTROL, GxB_HYPERSPARSE); - ASSERT(info == GrB_SUCCESS); - info = GxB_set(A->delta_plus, GxB_HYPER_SWITCH, GxB_ALWAYS_HYPER); - ASSERT(info == GrB_SUCCESS); - - //-------------------------------------------------------------------------- - // delta-minus, always hypersparse - //-------------------------------------------------------------------------- - info = GrB_Matrix_new(&A->delta_minus, GrB_BOOL, nrows, ncols); - ASSERT(info == GrB_SUCCESS); - info = GxB_set(A->delta_minus, GxB_SPARSITY_CONTROL, GxB_HYPERSPARSE); - ASSERT(info == GrB_SUCCESS); - info = GxB_set(A->delta_minus, GxB_HYPER_SWITCH, GxB_ALWAYS_HYPER); - ASSERT(info == GrB_SUCCESS); - - return info; -} - -// creates a new matrix -GrB_Info RG_Matrix_new -( - RG_Matrix *A, - GrB_Type type, - GrB_Index nrows, - GrB_Index ncols -) { - GrB_Info info; - RG_Matrix matrix = rm_calloc(1, sizeof(_RG_Matrix)); - - //-------------------------------------------------------------------------- - // input validations - //-------------------------------------------------------------------------- - - // supported types: boolean and uint64 - ASSERT(type == GrB_BOOL || type == GrB_UINT64); - - info = _RG_Matrix_init(matrix, type, nrows, ncols); - ASSERT(info == GrB_SUCCESS); - - //-------------------------------------------------------------------------- - // create transpose matrix if required - //-------------------------------------------------------------------------- - - if(type == GrB_UINT64) { - matrix->transposed = rm_calloc(1, sizeof(_RG_Matrix)); - info = _RG_Matrix_init(matrix->transposed, GrB_BOOL, ncols, nrows); - ASSERT(info == GrB_SUCCESS); - } - - int mutex_res = pthread_mutex_init(&matrix->mutex, NULL); - ASSERT(mutex_res == 0); - - *A = matrix; - return info; -} - diff --git a/src/graph/rg_matrix/rg_pending.c b/src/graph/rg_matrix/rg_pending.c deleted file mode 100644 index cfb112dcb..000000000 --- a/src/graph/rg_matrix/rg_pending.c +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ - -#include "RG.h" -#include "rg_matrix.h" - -GrB_Info RG_Matrix_pending -( - const RG_Matrix C, // matrix to query - bool *pending // are there any pending operations -) { - ASSERT(C != NULL); - ASSERT(pending != NULL); - - GrB_Info info; - bool p = false; - bool res = false; - GrB_Matrix M = RG_MATRIX_M(C); - GrB_Matrix DP = RG_MATRIX_DELTA_PLUS(C); - GrB_Matrix DM = RG_MATRIX_DELTA_MINUS(C); - - if(RG_MATRIX_MAINTAIN_TRANSPOSE(C)) { - info = RG_Matrix_pending(C->transposed, &res); - ASSERT(info == GrB_SUCCESS); - if(res == true) { - *pending = true; - return GrB_SUCCESS; - } - } - - // check if M contains pending changes - info = GxB_Matrix_Pending(M, &p); - ASSERT(info == GrB_SUCCESS); - res |= p; - - // check if delta-plus contains pending changes - info = GxB_Matrix_Pending(DP, &p); - ASSERT(info == GrB_SUCCESS); - res |= p; - - // check if delta-plus contains pending changes - info = GxB_Matrix_Pending(DM, &p); - ASSERT(info == GrB_SUCCESS); - res |= p; - - // set output - *pending = res; - - return info; -} - diff --git a/src/graph/rg_matrix/rg_remove_element.c b/src/graph/rg_matrix/rg_remove_element.c deleted file mode 100644 index 1b66e6d6e..000000000 --- a/src/graph/rg_matrix/rg_remove_element.c +++ /dev/null @@ -1,166 +0,0 @@ -/* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ - -#include "RG.h" -#include "rg_matrix.h" -#include "rg_utils.h" -#include "../../util/arr.h" -#include "../../util/rmalloc.h" - -GrB_Info RG_Matrix_removeElement_BOOL -( - RG_Matrix C, // matrix to remove entry from - GrB_Index i, // row index - GrB_Index j // column index -) { - ASSERT(C); - RG_Matrix_checkBounds(C, i, j); - - bool m_x; - bool dm_x; - bool dp_x; - GrB_Info info; - GrB_Type type; - bool in_m = false; - bool in_dp = false; - bool in_dm = false; - GrB_Matrix m = RG_MATRIX_M(C); - GrB_Matrix dp = RG_MATRIX_DELTA_PLUS(C); - GrB_Matrix dm = RG_MATRIX_DELTA_MINUS(C); - -#ifdef RG_DEBUG - info = GxB_Matrix_type(&type, m); - ASSERT(info == GrB_SUCCESS); - ASSERT(type == GrB_BOOL); - - info = GrB_Matrix_extractElement(&dm_x, dm, i, j); - ASSERT(info == GrB_NO_VALUE); -#endif - - if(RG_MATRIX_MAINTAIN_TRANSPOSE(C)) { - info = RG_Matrix_removeElement_BOOL(C->transposed, j, i); - if(info != GrB_SUCCESS) { - return info; - } - } - - //-------------------------------------------------------------------------- - // entry exists in 'M' - //-------------------------------------------------------------------------- - - info = GrB_Matrix_extractElement(&m_x, m, i, j); - in_m = (info == GrB_SUCCESS); - - if(in_m) { - // mark deletion in delta minus - info = GrB_Matrix_setElement(dm, true, i, j); - ASSERT(info == GrB_SUCCESS); - RG_Matrix_setDirty(C); - return info; - } - - //-------------------------------------------------------------------------- - // entry exists in 'delta-plus' - //-------------------------------------------------------------------------- - - - // remove entry from 'dp' - info = GrB_Matrix_removeElement(dp, i, j); - ASSERT(info == GrB_SUCCESS); - RG_Matrix_setDirty(C); - return info; -} - -GrB_Info RG_Matrix_removeElement_UINT64 -( - RG_Matrix C, // matrix to remove entry from - GrB_Index i, // row index - GrB_Index j // column index -) { - ASSERT(C); - RG_Matrix_checkBounds(C, i, j); - - uint64_t m_x; - uint64_t dm_x; - uint64_t dp_x; - GrB_Info info; - GrB_Type type; - bool in_m = false; - bool in_dp = false; - bool in_dm = false; - GrB_Matrix m = RG_MATRIX_M(C); - GrB_Matrix dp = RG_MATRIX_DELTA_PLUS(C); - GrB_Matrix dm = RG_MATRIX_DELTA_MINUS(C); - -#ifdef RG_DEBUG - info = GxB_Matrix_type(&type, m); - ASSERT(info == GrB_SUCCESS); - ASSERT(type == GrB_UINT64); -#endif - - if(RG_MATRIX_MAINTAIN_TRANSPOSE(C)) { - info = RG_Matrix_removeElement_BOOL(C->transposed, j, i); - if(info != GrB_SUCCESS) { - return info; - } - } - - info = GrB_Matrix_extractElement(&m_x, m, i, j); - in_m = (info == GrB_SUCCESS); - - info = GrB_Matrix_extractElement(&dp_x, dp, i, j); - in_dp = (info == GrB_SUCCESS); - - info = GrB_Matrix_extractElement(&dm_x, dm, i, j); - in_dm = (info == GrB_SUCCESS); - - // mask 'in_m' incase it is marked for deletion - in_m = in_m && !(in_dm); - - // entry missing from both 'm' and 'dp' - if(!(in_m || in_dp)) { - return GrB_NO_VALUE; - } - - // entry can't exists in both 'm' and 'dp' - ASSERT(in_m != in_dp); - - //-------------------------------------------------------------------------- - // entry exists in 'M' - //-------------------------------------------------------------------------- - - if(in_m) { - // free multi-edge entry, leave M[i,j] dirty - if((SINGLE_EDGE(m_x)) == false) { - m_x = CLEAR_MSB(m_x); - array_free((uint64_t *)m_x); - } - - // mark deletion in delta minus - info = GrB_Matrix_setElement(dm, true, i, j); - ASSERT(info == GrB_SUCCESS); - } - - //-------------------------------------------------------------------------- - // entry exists in 'delta-plus' - //-------------------------------------------------------------------------- - - if(in_dp) { - // free multi-edge entry - if((SINGLE_EDGE(dp_x)) == false) { - dp_x = CLEAR_MSB(dp_x); - array_free((uint64_t *)dp_x); - } - - // remove entry from 'dp' - info = GrB_Matrix_removeElement(dp, i, j); - ASSERT(info == GrB_SUCCESS); - } - - RG_Matrix_setDirty(C); - return info; -} - diff --git a/src/graph/rg_matrix/rg_remove_entry.c b/src/graph/rg_matrix/rg_remove_entry.c deleted file mode 100644 index a30d9ccae..000000000 --- a/src/graph/rg_matrix/rg_remove_entry.c +++ /dev/null @@ -1,154 +0,0 @@ -/* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ - -#include "RG.h" -#include "rg_utils.h" -#include "rg_matrix.h" -#include "../../util/arr.h" -#include "../../util/rmalloc.h" - -static bool _removeEntryFromMultiValArr -( - uint64_t **entries, // multi-value array - uint64_t entry // element to remove output new value -) { - ASSERT(*entries != NULL); - - uint i = 0; - uint n = array_len(*entries); - - // search for entry - for(; i < n; i++) { - if((*entries)[i] == entry) { - break; - } - } - - ASSERT(i < n); - - // remove located entry - // migrate last element and reduce array size - array_del_fast(*entries, i); - - // incase we're left with a single entry revert back to scalar - if(array_len(*entries) == 1) { - entry = (*entries)[0]; - array_free(*entries); - *entries = (uint64_t *)entry; - return true; - } - - return false; -} - -static GrB_Info _removeElementMultiVal -( - GrB_Matrix A, // matrix to remove entry from - GrB_Index i, // row index - GrB_Index j, // column index - uint64_t v // value to remove -) { - ASSERT(A); - - uint64_t x; - uint64_t tx; - GrB_Info info; - - info = GrB_Matrix_extractElement(&x, A, i, j); - ASSERT(info == GrB_SUCCESS); - ASSERT((SINGLE_EDGE(x)) == false); - - // remove entry from multi-value - x = CLEAR_MSB(x); - uint64_t *entries = (uint64_t *)x; - if(_removeEntryFromMultiValArr(&entries, v)) { - // update entry - x = (uint64_t)entries; - info = GrB_Matrix_setElement(A, x, i, j); - } - - return info; -} - -GrB_Info RG_Matrix_removeEntry_UINT64 -( - RG_Matrix C, // matrix to remove entry from - GrB_Index i, // row index - GrB_Index j, // column index - uint64_t v, // value to remove - bool *entry_deleted // is entry deleted -) { - ASSERT(C); - ASSERT(entry_deleted != NULL); - RG_Matrix_checkBounds(C, i, j); - - uint64_t m_x; - uint64_t dp_x; - GrB_Info info; - GrB_Type type; - bool in_m = false; - GrB_Matrix m = RG_MATRIX_M(C); - GrB_Matrix dp = RG_MATRIX_DELTA_PLUS(C); - GrB_Matrix dm = RG_MATRIX_DELTA_MINUS(C); - - *entry_deleted = false; - - -#ifdef RG_DEBUG - info = GxB_Matrix_type(&type, m); - ASSERT(info == GrB_SUCCESS); - ASSERT(type == GrB_UINT64); - - bool dm_x; - info = GrB_Matrix_extractElement(&dm_x, dm, i, j); - ASSERT(info == GrB_NO_VALUE); -#endif - - // entry should exists in either delta-plus or main - // locate entry - info = GrB_Matrix_extractElement(&m_x, m, i, j); - in_m = (info == GrB_SUCCESS); - - //-------------------------------------------------------------------------- - // entry exists in 'M' - //-------------------------------------------------------------------------- - - if(in_m) { - if(SINGLE_EDGE(m_x)) { - *entry_deleted = true; - // mark deletion in delta minus - info = GrB_Matrix_setElement(dm, true, i, j); - ASSERT(info == GrB_SUCCESS); - info = RG_Matrix_removeElement_BOOL(C->transposed, j, i); - ASSERT(info == GrB_SUCCESS) - RG_Matrix_setDirty(C); - } else { - info = _removeElementMultiVal(m, i, j, v); - ASSERT(info == GrB_SUCCESS); - } - return info; - } - - //-------------------------------------------------------------------------- - // entry exists in 'delta-plus' - //-------------------------------------------------------------------------- - - info = GrB_Matrix_extractElement(&dp_x, dp, i, j); - if(info != GrB_SUCCESS) return info; - - if(SINGLE_EDGE(dp_x)) { - *entry_deleted = true; - info = GrB_Matrix_removeElement(dp, i, j); - ASSERT(info == GrB_SUCCESS); - info = RG_Matrix_removeElement_BOOL(C->transposed, j, i); - ASSERT(info == GrB_SUCCESS) - RG_Matrix_setDirty(C); - } else { - info = _removeElementMultiVal(dp, i, j, v); - ASSERT(info == GrB_SUCCESS); - } - return info; -} diff --git a/src/graph/rg_matrix/rg_resize.c b/src/graph/rg_matrix/rg_resize.c deleted file mode 100644 index cab625c09..000000000 --- a/src/graph/rg_matrix/rg_resize.c +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ - -#include "RG.h" -#include "rg_matrix.h" - -GrB_Info RG_Matrix_resize // change the size of a matrix -( - RG_Matrix C, // matrix to modify - GrB_Index nrows_new, // new number of rows in matrix - GrB_Index ncols_new // new number of columns in matrix -) { - ASSERT(C != NULL); - GrB_Info info; - - if(RG_MATRIX_MAINTAIN_TRANSPOSE(C)) { - info = RG_Matrix_resize(C->transposed, ncols_new, nrows_new); - ASSERT(info == GrB_SUCCESS); - } - - GrB_Matrix m = RG_MATRIX_M(C); - GrB_Matrix delta_plus = RG_MATRIX_DELTA_PLUS(C); - GrB_Matrix delta_minus = RG_MATRIX_DELTA_MINUS(C); - - info = GrB_Matrix_resize(m, nrows_new, ncols_new); - ASSERT(info == GrB_SUCCESS); - - info = GrB_Matrix_resize(delta_plus, nrows_new, ncols_new); - ASSERT(info == GrB_SUCCESS); - - info = GrB_Matrix_resize(delta_minus, nrows_new, ncols_new); - ASSERT(info == GrB_SUCCESS); - - return info; -} - diff --git a/src/graph/rg_matrix/rg_set_element_bool.c b/src/graph/rg_matrix/rg_set_element_bool.c deleted file mode 100644 index 3c1a996e3..000000000 --- a/src/graph/rg_matrix/rg_set_element_bool.c +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ - -#include "RG.h" -#include "rg_utils.h" -#include "rg_matrix.h" - -GrB_Info RG_Matrix_setElement_BOOL // C (i,j) = x -( - RG_Matrix C, // matrix to modify - GrB_Index i, // row index - GrB_Index j // column index -) { - ASSERT(C != NULL); - ASSERT(!RG_MATRIX_MULTI_EDGE(C)); - RG_Matrix_checkBounds(C, i, j); - - bool v; - GrB_Info info; - - GrB_Matrix m = RG_MATRIX_M(C); - GrB_Matrix dp = RG_MATRIX_DELTA_PLUS(C); - GrB_Matrix dm = RG_MATRIX_DELTA_MINUS(C); - - bool already_allocated = false; // M[i,j] exists - bool marked_for_deletion = false; // dm[i,j] exists - - if(RG_MATRIX_MAINTAIN_TRANSPOSE(C)) { - info = RG_Matrix_setElement_BOOL(C->transposed, j, i); - ASSERT(info == GrB_SUCCESS); - } - - info = GrB_Matrix_extractElement(&v, dm, i, j); - marked_for_deletion = (info == GrB_SUCCESS); - - if(marked_for_deletion) { - // unset delta-minus m already assign to true - info = GrB_Matrix_removeElement(dm, i, j); - ASSERT(info == GrB_SUCCESS); - } else { - info = GrB_Matrix_extractElement(&v, m, i, j); - already_allocated = (info == GrB_SUCCESS); - - if(!already_allocated) { - // update entry to dp[i, j] - info = GrB_Matrix_setElement_BOOL(dp, true, i, j); - ASSERT(info == GrB_SUCCESS); - } - } - - RG_Matrix_setDirty(C); - - return info; -} - diff --git a/src/graph/rg_matrix/rg_set_element_uint64.c b/src/graph/rg_matrix/rg_set_element_uint64.c deleted file mode 100644 index 37f61da5b..000000000 --- a/src/graph/rg_matrix/rg_set_element_uint64.c +++ /dev/null @@ -1,133 +0,0 @@ -/* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ - -#include "RG.h" -#include "rg_utils.h" -#include "rg_matrix.h" -#include "../../util/arr.h" - -static GrB_BinaryOp _graph_edge_accum = NULL; - -void _edge_accum(void *_z, const void *_x, const void *_y) { - uint64_t *ids; - uint64_t *z = (uint64_t *) _z; - const uint64_t *x = (const uint64_t *) _x; - const uint64_t *y = (const uint64_t *) _y; - - // single edge ID, - // switching from single edge ID to multiple IDs - if(SINGLE_EDGE(*x)) { - ids = array_new(uint64_t, 2); - array_append(ids, *x); - array_append(ids, *y); - } else { - // multiple edges, adding another edge - ids = (uint64_t *)(CLEAR_MSB(*x)); - array_append(ids, *y); - } - - *z = (uint64_t)SET_MSB(ids); -} - -// dealing with multi-value entries -static GrB_Info setMultiEdgeEntry -( - GrB_Matrix A, // matrix to modify - uint64_t x, // scalar to assign to A(i,j) - GrB_Index i, // row index - GrB_Index j // column index -) { - GrB_Info info; - - // create edge accumulator binary function - // TODO: remove if condition, initialize binary operation at module load - if(!_graph_edge_accum) { - info = GrB_BinaryOp_new(&_graph_edge_accum, _edge_accum, GrB_UINT64, - GrB_UINT64, GrB_UINT64); - ASSERT(info == GrB_SUCCESS); - } - - info = GxB_Matrix_subassign_UINT64(A, NULL, _graph_edge_accum, - x, &i, 1, &j, 1, NULL); - ASSERT(info == GrB_SUCCESS); - - return info; -} - -GrB_Info RG_Matrix_setElement_UINT64 // C (i,j) = x -( - RG_Matrix C, // matrix to modify - uint64_t x, // scalar to assign to C(i,j) - GrB_Index i, // row index - GrB_Index j // column index -) { - ASSERT(C != NULL); - RG_Matrix_checkBounds(C, i, j); - - uint64_t v; - GrB_Info info; - bool entry_exists = false; // M[i,j] exists - bool mark_for_deletion = false; // dm[i,j] exists - - if(RG_MATRIX_MAINTAIN_TRANSPOSE(C)) { - info = RG_Matrix_setElement_BOOL(C->transposed, j, i); - if(info != GrB_SUCCESS) { - return info; - } - } - - GrB_Matrix m = RG_MATRIX_M(C); - GrB_Matrix dp = RG_MATRIX_DELTA_PLUS(C); - GrB_Matrix dm = RG_MATRIX_DELTA_MINUS(C); - -#if RG_DEBUG - //-------------------------------------------------------------------------- - // validate type - //-------------------------------------------------------------------------- - - GrB_Type t; - info = GxB_Matrix_type(&t, m); - ASSERT(info == GrB_SUCCESS); - ASSERT(t == GrB_UINT64); -#endif - - //-------------------------------------------------------------------------- - // check deleted - //-------------------------------------------------------------------------- - - info = GrB_Matrix_extractElement(&v, dm, i, j); - mark_for_deletion = (info == GrB_SUCCESS); - - if(mark_for_deletion) { // m contains single edge, simple replace - // clear dm[i,j] - info = GrB_Matrix_removeElement(dm, i, j); - ASSERT(info == GrB_SUCCESS); - - // overwrite m[i,j] - info = GrB_Matrix_setElement(m, x, i, j); - ASSERT(info == GrB_SUCCESS); - } else { - // entry isn't marked for deletion - // see if entry already exists in 'm' - // we'll prefer setting entry in 'm' incase it already exists - // otherwise we'll set the entry in 'delta-plus' - info = GrB_Matrix_extractElement_UINT64(&v, m, i, j); - entry_exists = (info == GrB_SUCCESS); - - if(entry_exists) { - // update entry at m[i,j] - info = setMultiEdgeEntry(m, x, i, j); - } else { - // update entry at dp[i,j] - info = setMultiEdgeEntry(dp, x, i, j); - } - } - - RG_Matrix_setDirty(C); - - return info; -} - diff --git a/src/graph/rg_matrix/rg_utils.c b/src/graph/rg_matrix/rg_utils.c deleted file mode 100644 index 1e1366f99..000000000 --- a/src/graph/rg_matrix/rg_utils.c +++ /dev/null @@ -1,118 +0,0 @@ -/* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ - -#include "RG.h" -#include "rg_matrix.h" - -// check if i and j are within matrix boundries -// i < nrows -// j < ncols -void RG_Matrix_checkBounds -( - const RG_Matrix C, - GrB_Index i, - GrB_Index j -) { -#if RG_DEBUG - GrB_Matrix m = RG_MATRIX_M(C); - // check bounds - GrB_Index nrows; - GrB_Index ncols; - GrB_Matrix_nrows(&nrows, m); - GrB_Matrix_ncols(&ncols, m); - ASSERT(i < nrows); - ASSERT(j < ncols); -#endif -} - -// check 2 matrices have same type nrows and ncols -void RG_Matrix_checkCompatible -( - const RG_Matrix M, - const RG_Matrix N -) { -#if RG_DEBUG - GrB_Matrix m = RG_MATRIX_M(M); - GrB_Matrix n = RG_MATRIX_M(N); - - GrB_Type m_type; - GrB_Type n_type; - GxB_Matrix_type(&m_type, m); - GxB_Matrix_type(&n_type, n); - ASSERT(m_type == n_type); - - GrB_Index m_nrows; - GrB_Index m_ncols; - GrB_Index n_nrows; - GrB_Index n_ncols; - GrB_Matrix_nrows(&m_nrows, m); - GrB_Matrix_ncols(&m_ncols, m); - GrB_Matrix_nrows(&n_nrows, n); - GrB_Matrix_ncols(&n_ncols, n); - ASSERT(m_nrows == n_nrows); - ASSERT(m_ncols == n_ncols); -#endif -} - -void RG_Matrix_validateState -( - const RG_Matrix C, - GrB_Index i, - GrB_Index j -) { -#ifdef RG_DEBUG - bool x_m = false; - bool x_dp = false; - bool x_dm = false; - bool existing_entry = false; - bool pending_addition = false; - bool pending_deletion = false; - GrB_Info info_m = GrB_SUCCESS; - GrB_Info info_dp = GrB_SUCCESS; - GrB_Info info_dm = GrB_SUCCESS; - GrB_Matrix m = RG_MATRIX_M(C); - GrB_Matrix dp = RG_MATRIX_DELTA_PLUS(C); - GrB_Matrix dm = RG_MATRIX_DELTA_MINUS(C); - - // find out which entries exists - info_m = GrB_Matrix_extractElement(&x_m, m, i, j); - info_dp = GrB_Matrix_extractElement(&x_dp, dp, i, j); - info_dm = GrB_Matrix_extractElement(&x_dm, dm, i, j); - - UNUSED(existing_entry); - UNUSED(pending_addition); - UNUSED(pending_deletion); - - existing_entry = info_m == GrB_SUCCESS; - pending_addition = info_dp == GrB_SUCCESS; - pending_deletion = info_dm == GrB_SUCCESS; - - //-------------------------------------------------------------------------- - // impossible states - //-------------------------------------------------------------------------- - - // matrix disjoint - ASSERT(!(existing_entry && - pending_addition && - pending_deletion)); - - // deletion only - ASSERT(!(!existing_entry && - !pending_addition && - pending_deletion)); - - // addition to already existing entry - ASSERT(!(existing_entry && - pending_addition && - !pending_deletion)); - - // pending deletion and pending addition - ASSERT(!(!existing_entry && - pending_addition && - pending_deletion)); -#endif -} - diff --git a/src/graph/rg_matrix/rg_utils.h b/src/graph/rg_matrix/rg_utils.h deleted file mode 100644 index 2c3b30b06..000000000 --- a/src/graph/rg_matrix/rg_utils.h +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ - -#pragma once - -#include "rg_matrix.h" - -void RG_Matrix_checkBounds -( - const RG_Matrix C, - GrB_Index i, - GrB_Index j -); - -void RG_Matrix_checkCompatible -( - const RG_Matrix M, - const RG_Matrix N -); - -// validate 'C' isn't in an invalid state -void RG_Matrix_validateState -( - const RG_Matrix C, - GrB_Index i, - GrB_Index j -); - diff --git a/src/graph/rg_matrix/rg_wait.c b/src/graph/rg_matrix/rg_wait.c deleted file mode 100644 index bb3092236..000000000 --- a/src/graph/rg_matrix/rg_wait.c +++ /dev/null @@ -1,145 +0,0 @@ -/* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ - -#include "RG.h" -#include "rg_matrix.h" -#include "../../util/rmalloc.h" -#include "configuration/config.h" - -static inline void _SetUndirty -( - RG_Matrix C -) { - ASSERT(C); - - C->dirty = false; - - if(RG_MATRIX_MAINTAIN_TRANSPOSE(C)) { - C->transposed->dirty = false; - } -} - -static void RG_Matrix_sync_deletions -( - RG_Matrix C -) { - ASSERT(C != NULL); - - GrB_Matrix m = RG_MATRIX_M(C); - GrB_Matrix dm = RG_MATRIX_DELTA_MINUS(C); - - GrB_Info info; - - info = GrB_transpose(m, dm, GrB_NULL, m, GrB_DESC_RSCT0); - ASSERT(info == GrB_SUCCESS); - - // clear delta minus - info = GrB_Matrix_clear(dm); - ASSERT(info == GrB_SUCCESS); -} - -static void RG_Matrix_sync_additions -( - RG_Matrix C -) { - ASSERT(C != NULL); - - GrB_Matrix m = RG_MATRIX_M(C); - GrB_Matrix dp = RG_MATRIX_DELTA_PLUS(C); - - GrB_Info info; - GrB_Index nrows; - GrB_Index ncols; - - info = GrB_Matrix_nrows(&nrows, m); - ASSERT(info == GrB_SUCCESS); - info = GrB_Matrix_ncols(&ncols, m); - ASSERT(info == GrB_SUCCESS); - - info = GrB_Matrix_assign(m, dp, NULL, dp, GrB_ALL, nrows, GrB_ALL, ncols, - GrB_DESC_S); - ASSERT(info == GrB_SUCCESS); - - // clear delta plus - info = GrB_Matrix_clear(dp); - ASSERT(info == GrB_SUCCESS); -} - -static void RG_Matrix_sync -( - RG_Matrix C, - bool force_sync, - uint64_t delta_max_pending_changes -) { - ASSERT(C != NULL); - - GrB_Matrix m = RG_MATRIX_M(C); - GrB_Matrix dp = RG_MATRIX_DELTA_PLUS(C); - GrB_Matrix dm = RG_MATRIX_DELTA_MINUS(C); - - if(force_sync) { - RG_Matrix_sync_deletions(C); - RG_Matrix_sync_additions(C); - } else { - GrB_Index dp_nvals; - GrB_Index dm_nvals; - - //---------------------------------------------------------------------- - // determin change set - //---------------------------------------------------------------------- - - GrB_Matrix_nvals(&dp_nvals, dp); - GrB_Matrix_nvals(&dm_nvals, dm); - - //---------------------------------------------------------------------- - // perform deletions - //---------------------------------------------------------------------- - - if(dm_nvals >= delta_max_pending_changes) { - RG_Matrix_sync_deletions(C); - } - - //---------------------------------------------------------------------- - // perform additions - //---------------------------------------------------------------------- - - if(dp_nvals >= delta_max_pending_changes) { - RG_Matrix_sync_additions(C); - } - } - - // wait on all 3 matrices - GrB_Info info = GrB_wait(m, GrB_MATERIALIZE); - ASSERT(info == GrB_SUCCESS); - - info = GrB_wait(dm, GrB_MATERIALIZE); - ASSERT(info == GrB_SUCCESS); - - info = GrB_wait(dp, GrB_MATERIALIZE); - ASSERT(info == GrB_SUCCESS); -} - -GrB_Info RG_Matrix_wait -( - RG_Matrix A, - bool force_sync -) { - ASSERT(A != NULL); - if(RG_MATRIX_MAINTAIN_TRANSPOSE(A)) { - RG_Matrix_wait(A->transposed, force_sync); - } - - uint64_t delta_max_pending_changes; - Config_Option_get(Config_DELTA_MAX_PENDING_CHANGES, - &delta_max_pending_changes); - - RG_Matrix_sync(A, force_sync, delta_max_pending_changes); - - _SetUndirty(A); - - return GrB_SUCCESS; -} - diff --git a/src/index/index_construct.c b/src/index/index_construct.c index 563fbbab6..64764899d 100644 --- a/src/index/index_construct.c +++ b/src/index/index_construct.c @@ -6,7 +6,7 @@ #include "RG.h" #include "index.h" -#include "../graph/rg_matrix/rg_matrix_iter.h" +#include "../graph/delta_matrix/delta_matrix_iter.h" #include @@ -30,7 +30,7 @@ static void _Index_PopulateNodeIndex GrB_Index rowIdx = 0; int indexed = 0; // #entities in current batch int batch_size = 10000; // max #entities to index in one go - RG_MatrixTupleIter it = {0}; + Delta_MatrixTupleIter it = {0}; while(true) { // lock graph for reading @@ -48,7 +48,7 @@ static void _Index_PopulateNodeIndex indexed = 0; // fetch label matrix - const RG_Matrix m = Graph_GetLabelMatrix(g, Index_GetLabelID(idx)); + const Delta_Matrix m = Graph_GetLabelMatrix(g, Index_GetLabelID(idx)); ASSERT(m != NULL); //---------------------------------------------------------------------- @@ -56,9 +56,9 @@ static void _Index_PopulateNodeIndex //---------------------------------------------------------------------- GrB_Info info; - info = RG_MatrixTupleIter_attach(&it, m); + info = Delta_MatrixTupleIter_attach(&it, m); ASSERT(info == GrB_SUCCESS); - info = RG_MatrixTupleIter_iterate_range(&it, rowIdx, UINT64_MAX); + info = Delta_MatrixTupleIter_iterate_range(&it, rowIdx, UINT64_MAX); ASSERT(info == GrB_SUCCESS); //---------------------------------------------------------------------- @@ -67,7 +67,7 @@ static void _Index_PopulateNodeIndex EntityID id; while(indexed < batch_size && - RG_MatrixTupleIter_next_BOOL(&it, &id, NULL, NULL) == GrB_SUCCESS) + Delta_MatrixTupleIter_next_BOOL(&it, &id, NULL, NULL) == GrB_SUCCESS) { Node n; Graph_GetNode(g, id, &n); @@ -87,7 +87,7 @@ static void _Index_PopulateNodeIndex Graph_ReleaseLock(g); // finished current batch - RG_MatrixTupleIter_detach(&it); + Delta_MatrixTupleIter_detach(&it); // continue next batch from row id+1 // this is true because we're iterating over a diagonal matrix @@ -97,7 +97,7 @@ static void _Index_PopulateNodeIndex // release read lock Graph_ReleaseLock(g); - RG_MatrixTupleIter_detach(&it); + Delta_MatrixTupleIter_detach(&it); } // index edges in an asynchronous manner @@ -118,14 +118,15 @@ static void _Index_PopulateEdgeIndex ASSERT(idx != NULL); GrB_Info info; - EntityID src_id = 0; // current processed row idx - EntityID dest_id = 0; // current processed column idx - EntityID edge_id = 0; // current processed edge id - EntityID prev_src_id = 0; // last processed row idx - EntityID prev_dest_id = 0; // last processed column idx - int indexed = 0; // number of entities indexed in current batch - int batch_size = 1000; // max number of entities to index in one go - RG_MatrixTupleIter it = {0}; + bool skip = false; + EntityID src_id = 0; // current processed row idx + EntityID dest_id = 0; // current processed column idx + EntityID edge_id = 0; // current processed edge id + EntityID prev_edge_id = 0; // last processed edge idx + int indexed = 0; // number of entities indexed in current batch + int schema_id = Index_GetLabelID(idx); // index relationship type ID + int batch_size = 1000; // max number of entities to index in one go + MultiEdgeIterator it = {0}; while(true) { // lock graph for reading @@ -141,61 +142,46 @@ static void _Index_PopulateEdgeIndex // reset number of indexed edges in batch indexed = 0; - prev_src_id = src_id; - prev_dest_id = dest_id; + prev_edge_id = edge_id; // fetch relation matrix - const RG_Matrix m = Graph_GetRelationMatrix(g, Index_GetLabelID(idx), - false); - ASSERT(m != NULL); + Graph_GetRelationMatrix(g, Index_GetLabelID(idx), false); + Graph_GetMultiEdgeRelationMatrix(g, Index_GetLabelID(idx)); //---------------------------------------------------------------------- // resume scanning from previous row/col indices //---------------------------------------------------------------------- - info = RG_MatrixTupleIter_attach(&it, m); - ASSERT(info == GrB_SUCCESS); - info = RG_MatrixTupleIter_iterate_range(&it, src_id, UINT64_MAX); - ASSERT(info == GrB_SUCCESS); + MultiEdgeIterator_AttachSourceRange(&it, g->relations + schema_id, src_id, UINT64_MAX, false); // skip previously indexed edges - while((info = RG_MatrixTupleIter_next_UINT64(&it, &src_id, &dest_id, - &edge_id)) == GrB_SUCCESS && - src_id == prev_src_id && - dest_id < prev_dest_id); + while(skip && (info = MultiEdgeIterator_next(&it, &src_id, &dest_id, + &edge_id)) && + edge_id == prev_edge_id); // process only if iterator is on an active entry - if(info != GrB_SUCCESS) { + if(skip && info != GrB_SUCCESS) { break; } + skip = true; + //---------------------------------------------------------------------- // batch index edges //---------------------------------------------------------------------- - do { + while(indexed < batch_size && + MultiEdgeIterator_next(&it, &src_id, &dest_id, &edge_id)) { Edge e; e.src_id = src_id; e.dest_id = dest_id; e.relationID = Index_GetLabelID(idx); - if(SINGLE_EDGE(edge_id)) { - Graph_GetEdge(g, edge_id, &e); - Index_IndexEdge(idx, &e); - } else { - EdgeID *edgeIds = (EdgeID *)(CLEAR_MSB(edge_id)); - uint edgeCount = array_len(edgeIds); - - for(uint i = 0; i < edgeCount; i++) { - edge_id = edgeIds[i]; - Graph_GetEdge(g, edge_id, &e); - Index_IndexEdge(idx, &e); - } - } - indexed++; // single/multi edge are counted similarly - } while(indexed < batch_size && - RG_MatrixTupleIter_next_UINT64(&it, &src_id, &dest_id, &edge_id) - == GrB_SUCCESS); + Graph_GetEdge(g, edge_id, &e); + Index_IndexEdge(idx, &e); + + indexed++; + } //---------------------------------------------------------------------- // done with current batch @@ -208,13 +194,11 @@ static void _Index_PopulateEdgeIndex // finished current batch // release read lock Graph_ReleaseLock(g); - RG_MatrixTupleIter_detach(&it); } } // release read lock Graph_ReleaseLock(g); - RG_MatrixTupleIter_detach(&it); } // constructs index @@ -237,4 +221,3 @@ void Index_Populate _Index_PopulateEdgeIndex(idx, g); } } - diff --git a/src/index/index_edge.c b/src/index/index_edge.c index 75baf895c..a15307ce9 100644 --- a/src/index/index_edge.c +++ b/src/index/index_edge.c @@ -9,7 +9,6 @@ #include "../query_ctx.h" #include "../graph/graphcontext.h" #include "../graph/entities/edge.h" -#include "../graph/rg_matrix/rg_matrix_iter.h" extern RSDoc *Index_IndexGraphEntity(Index idx,const GraphEntity *e, const void *key, size_t key_len, uint *doc_field_count); diff --git a/src/index/index_node.c b/src/index/index_node.c index 6daeeccd6..9f8b07e0d 100644 --- a/src/index/index_node.c +++ b/src/index/index_node.c @@ -9,7 +9,6 @@ #include "../value.h" #include "../query_ctx.h" #include "../graph/graphcontext.h" -#include "../graph/rg_matrix/rg_matrix_iter.h" extern RSDoc *Index_IndexGraphEntity(Index idx, const GraphEntity *e, const void *key, size_t key_len, uint *doc_field_count); diff --git a/src/index/indexer.c b/src/index/indexer.c index 55b7f44b2..d37beb398 100644 --- a/src/index/indexer.c +++ b/src/index/indexer.c @@ -6,6 +6,7 @@ #include "indexer.h" #include "../redismodule.h" +#include "../util/rmalloc.h" #include "../util/circular_buffer.h" #include #include diff --git a/src/procedures/proc_bfs.c b/src/procedures/proc_bfs.c index a8fcd2bc9..6e555fb4e 100644 --- a/src/procedures/proc_bfs.c +++ b/src/procedures/proc_bfs.c @@ -97,14 +97,14 @@ static ProcedureResult Proc_BFS_Invoke GraphContext *gc = QueryCtx_GetGraphCtx(); if(reltype == NULL) { - RG_Matrix_export(&R, Graph_GetAdjacencyMatrix(gc->g, false)); + Delta_Matrix_export(&R, Graph_GetAdjacencyMatrix(gc->g, false)); } else { Schema *s = GraphContext_GetSchema(gc, reltype, SCHEMA_EDGE); // failed to find schema, first step will return NULL if(!s) return PROCEDURE_OK; bfs_ctx->reltype_id = s->id; - RG_Matrix_export(&R, Graph_GetRelationMatrix(gc->g, s->id, false)); + Delta_Matrix_export(&R, Graph_GetRelationMatrix(gc->g, s->id, false)); } // if we're not collecting edges, pass a NULL parent pointer diff --git a/src/procedures/proc_pagerank.c b/src/procedures/proc_pagerank.c index 92c0406ec..13d21f150 100644 --- a/src/procedures/proc_pagerank.c +++ b/src/procedures/proc_pagerank.c @@ -109,7 +109,7 @@ ProcedureResult Proc_PagerankInvoke s = GraphContext_GetSchema(gc, label, SCHEMA_NODE); // unknown label, quickly return if(!s) return PROCEDURE_OK; - RG_Matrix_export(&l, Graph_GetLabelMatrix(g, s->id)); + Delta_Matrix_export(&l, Graph_GetLabelMatrix(g, s->id)); } // get relation matrix @@ -117,14 +117,14 @@ ProcedureResult Proc_PagerankInvoke s = GraphContext_GetSchema(gc, relation, SCHEMA_EDGE); // unknown relation, quickly return if(!s) return PROCEDURE_OK; - RG_Matrix_export(&r, Graph_GetRelationMatrix(g, s->id, false)); + Delta_Matrix_export(&r, Graph_GetRelationMatrix(g, s->id, false)); // convert the values to true info = GrB_Matrix_apply(r, NULL, NULL, GxB_ONE_BOOL, r, GrB_DESC_R); ASSERT(info == GrB_SUCCESS); } else { // relation isn't specified, 'r' is the adjacency matrix - RG_Matrix_export(&r, Graph_GetAdjacencyMatrix(g, false)); + Delta_Matrix_export(&r, Graph_GetAdjacencyMatrix(g, false)); } // if label is specified: // filter 'r' to contain only rows and columns associated with diff --git a/src/serializers/decoders/current/v14/decode_graph.c b/src/serializers/decoders/current/v14/decode_graph.c index 613e74496..fe75ea175 100644 --- a/src/serializers/decoders/current/v14/decode_graph.c +++ b/src/serializers/decoders/current/v14/decode_graph.c @@ -223,8 +223,8 @@ GraphContext *RdbLoadGraphContext_latest // update the node statistics, enable node indices for(uint i = 0; i < label_count; i++) { GrB_Index nvals; - RG_Matrix L = Graph_GetLabelMatrix(g, i); - RG_Matrix_nvals(&nvals, L); + Delta_Matrix L = Graph_GetLabelMatrix(g, i); + Delta_Matrix_nvals(&nvals, L); GraphStatistics_IncNodeCount(&g->stats, i, nvals); Index idx; @@ -255,4 +255,3 @@ GraphContext *RdbLoadGraphContext_latest return gc; } - diff --git a/src/serializers/decoders/current/v14/decode_graph_entities.c b/src/serializers/decoders/current/v14/decode_graph_entities.c index 2c2cd6bf1..e70b44cf9 100644 --- a/src/serializers/decoders/current/v14/decode_graph_entities.c +++ b/src/serializers/decoders/current/v14/decode_graph_entities.c @@ -201,9 +201,8 @@ void RdbLoadEdges_v14 NodeID destId = SerializerIO_ReadUnsigned(rdb); uint64_t relation = SerializerIO_ReadUnsigned(rdb); - Serializer_Graph_SetEdge(gc->g, - gc->decoding_context->multi_edge[relation], edgeId, srcId, - destId, relation, &e); + Serializer_Graph_SetEdge(gc->g, gc->decoding_context->multi_edge[relation], + edgeId, srcId, destId, relation, &e); _RdbLoadEntity(rdb, gc, (GraphEntity *)&e); // index edge diff --git a/src/serializers/decoders/prev/v10/decode_graph.c b/src/serializers/decoders/prev/v10/decode_graph.c index 4ef5b307b..787669209 100644 --- a/src/serializers/decoders/prev/v10/decode_graph.c +++ b/src/serializers/decoders/prev/v10/decode_graph.c @@ -202,8 +202,8 @@ GraphContext *RdbLoadGraphContext_v10(RedisModuleIO *rdb) { // update the node statistics, enable node indices for(uint i = 0; i < label_count; i++) { GrB_Index nvals; - RG_Matrix L = Graph_GetLabelMatrix(g, i); - RG_Matrix_nvals(&nvals, L); + Delta_Matrix L = Graph_GetLabelMatrix(g, i); + Delta_Matrix_nvals(&nvals, L); GraphStatistics_IncNodeCount(&g->stats, i, nvals); Index idx; diff --git a/src/serializers/decoders/prev/v10/decode_graph_entities.c b/src/serializers/decoders/prev/v10/decode_graph_entities.c index 2100b194d..59b70e733 100644 --- a/src/serializers/decoders/prev/v10/decode_graph_entities.c +++ b/src/serializers/decoders/prev/v10/decode_graph_entities.c @@ -142,9 +142,8 @@ void RdbLoadEdges_v10(RedisModuleIO *rdb, GraphContext *gc, uint64_t edge_count) NodeID srcId = RedisModule_LoadUnsigned(rdb); NodeID destId = RedisModule_LoadUnsigned(rdb); uint64_t relation = RedisModule_LoadUnsigned(rdb); - Serializer_Graph_SetEdge(gc->g, - gc->decoding_context->multi_edge[relation], edgeId, srcId, - destId, relation, &e); + Serializer_Graph_SetEdge(gc->g, gc->decoding_context->multi_edge[relation], + edgeId, srcId, destId, relation, &e); _RdbLoadEntity(rdb, gc, (GraphEntity *)&e); // index edge diff --git a/src/serializers/decoders/prev/v11/decode_graph.c b/src/serializers/decoders/prev/v11/decode_graph.c index 97f838232..9baa703e9 100644 --- a/src/serializers/decoders/prev/v11/decode_graph.c +++ b/src/serializers/decoders/prev/v11/decode_graph.c @@ -209,8 +209,8 @@ GraphContext *RdbLoadGraphContext_v11 // update the node statistics, enable node indices for(uint i = 0; i < label_count; i++) { GrB_Index nvals; - RG_Matrix L = Graph_GetLabelMatrix(g, i); - RG_Matrix_nvals(&nvals, L); + Delta_Matrix L = Graph_GetLabelMatrix(g, i); + Delta_Matrix_nvals(&nvals, L); GraphStatistics_IncNodeCount(&g->stats, i, nvals); Index idx; diff --git a/src/serializers/decoders/prev/v11/decode_graph_entities.c b/src/serializers/decoders/prev/v11/decode_graph_entities.c index df20581d0..140b6cc79 100644 --- a/src/serializers/decoders/prev/v11/decode_graph_entities.c +++ b/src/serializers/decoders/prev/v11/decode_graph_entities.c @@ -167,9 +167,8 @@ void RdbLoadEdges_v11 NodeID srcId = RedisModule_LoadUnsigned(rdb); NodeID destId = RedisModule_LoadUnsigned(rdb); uint64_t relation = RedisModule_LoadUnsigned(rdb); - Serializer_Graph_SetEdge(gc->g, - gc->decoding_context->multi_edge[relation], edgeId, srcId, - destId, relation, &e); + Serializer_Graph_SetEdge(gc->g, gc->decoding_context->multi_edge[relation], + edgeId, srcId, destId, relation, &e); _RdbLoadEntity(rdb, gc, (GraphEntity *)&e); // index edge diff --git a/src/serializers/decoders/prev/v12/decode_graph.c b/src/serializers/decoders/prev/v12/decode_graph.c index 335a04865..09852ab33 100644 --- a/src/serializers/decoders/prev/v12/decode_graph.c +++ b/src/serializers/decoders/prev/v12/decode_graph.c @@ -217,8 +217,8 @@ GraphContext *RdbLoadGraphContext_v12 // update the node statistics, enable node indices for(uint i = 0; i < label_count; i++) { GrB_Index nvals; - RG_Matrix L = Graph_GetLabelMatrix(g, i); - RG_Matrix_nvals(&nvals, L); + Delta_Matrix L = Graph_GetLabelMatrix(g, i); + Delta_Matrix_nvals(&nvals, L); GraphStatistics_IncNodeCount(&g->stats, i, nvals); Index idx; diff --git a/src/serializers/decoders/prev/v12/decode_graph_entities.c b/src/serializers/decoders/prev/v12/decode_graph_entities.c index 4d8bd3136..3d1f2feb9 100644 --- a/src/serializers/decoders/prev/v12/decode_graph_entities.c +++ b/src/serializers/decoders/prev/v12/decode_graph_entities.c @@ -167,9 +167,8 @@ void RdbLoadEdges_v12 NodeID srcId = RedisModule_LoadUnsigned(rdb); NodeID destId = RedisModule_LoadUnsigned(rdb); uint64_t relation = RedisModule_LoadUnsigned(rdb); - Serializer_Graph_SetEdge(gc->g, - gc->decoding_context->multi_edge[relation], edgeId, srcId, - destId, relation, &e); + Serializer_Graph_SetEdge(gc->g, gc->decoding_context->multi_edge[relation], + edgeId, srcId, destId, relation, &e); _RdbLoadEntity(rdb, gc, (GraphEntity *)&e); // index edge diff --git a/src/serializers/decoders/prev/v13/decode_graph.c b/src/serializers/decoders/prev/v13/decode_graph.c index 9d60bbf29..97ee76a10 100644 --- a/src/serializers/decoders/prev/v13/decode_graph.c +++ b/src/serializers/decoders/prev/v13/decode_graph.c @@ -223,8 +223,8 @@ GraphContext *RdbLoadGraphContext_v13 // update the node statistics, enable node indices for(uint i = 0; i < label_count; i++) { GrB_Index nvals; - RG_Matrix L = Graph_GetLabelMatrix(g, i); - RG_Matrix_nvals(&nvals, L); + Delta_Matrix L = Graph_GetLabelMatrix(g, i); + Delta_Matrix_nvals(&nvals, L); GraphStatistics_IncNodeCount(&g->stats, i, nvals); Index idx; diff --git a/src/serializers/decoders/prev/v13/decode_graph_entities.c b/src/serializers/decoders/prev/v13/decode_graph_entities.c index d53c4a6c9..a1e23edd0 100644 --- a/src/serializers/decoders/prev/v13/decode_graph_entities.c +++ b/src/serializers/decoders/prev/v13/decode_graph_entities.c @@ -169,9 +169,8 @@ void RdbLoadEdges_v13 NodeID destId = RedisModule_LoadUnsigned(rdb); uint64_t relation = RedisModule_LoadUnsigned(rdb); - Serializer_Graph_SetEdge(gc->g, - gc->decoding_context->multi_edge[relation], edgeId, srcId, - destId, relation, &e); + Serializer_Graph_SetEdge(gc->g, gc->decoding_context->multi_edge[relation], + edgeId, srcId, destId, relation, &e); _RdbLoadEntity(rdb, gc, (GraphEntity *)&e); // index edge diff --git a/src/serializers/decoders/prev/v9/decode_graph.c b/src/serializers/decoders/prev/v9/decode_graph.c index 078d49627..05883758f 100644 --- a/src/serializers/decoders/prev/v9/decode_graph.c +++ b/src/serializers/decoders/prev/v9/decode_graph.c @@ -192,19 +192,19 @@ GraphContext *RdbLoadGraphContext_v9(RedisModuleIO *rdb) { // update the node statistics for(uint i = 0; i < node_schemas_count; i++) { GrB_Index nvals; - RG_Matrix L = g->labels[i]; - RG_Matrix_nvals(&nvals, L); + Delta_Matrix L = g->labels[i]; + Delta_Matrix_nvals(&nvals, L); GraphStatistics_IncNodeCount(&g->stats, i, nvals); } - + uint rel_count = Graph_RelationTypeCount(g); uint label_count = Graph_LabelTypeCount(g); // update the node statistics, enable node indices for(uint i = 0; i < label_count; i++) { GrB_Index nvals; - RG_Matrix L = Graph_GetLabelMatrix(g, i); - RG_Matrix_nvals(&nvals, L); + Delta_Matrix L = Graph_GetLabelMatrix(g, i); + Delta_Matrix_nvals(&nvals, L); GraphStatistics_IncNodeCount(&g->stats, i, nvals); Index idx; diff --git a/src/serializers/decoders/prev/v9/decode_graph_entities.c b/src/serializers/decoders/prev/v9/decode_graph_entities.c index 43f715c0b..90641c0a2 100644 --- a/src/serializers/decoders/prev/v9/decode_graph_entities.c +++ b/src/serializers/decoders/prev/v9/decode_graph_entities.c @@ -137,9 +137,8 @@ void RdbLoadEdges_v9(RedisModuleIO *rdb, GraphContext *gc, uint64_t edge_count) NodeID srcId = RedisModule_LoadUnsigned(rdb); NodeID destId = RedisModule_LoadUnsigned(rdb); uint64_t relation = RedisModule_LoadUnsigned(rdb); - Serializer_Graph_SetEdge(gc->g, - gc->decoding_context->multi_edge[relation], edgeId, srcId, - destId, relation, &e); + Serializer_Graph_SetEdge(gc->g, gc->decoding_context->multi_edge[relation], + edgeId, srcId, destId, relation, &e); _RdbLoadEntity(rdb, gc, (GraphEntity *)&e); } } diff --git a/src/serializers/encode_context.c b/src/serializers/encode_context.c index b1f38fb2d..9804ce7d4 100644 --- a/src/serializers/encode_context.c +++ b/src/serializers/encode_context.c @@ -43,11 +43,8 @@ void GraphEncodeContext_Reset(GraphEncodeContext *ctx) { ctx->offset = 0; ctx->keys_processed = 0; ctx->state = ENCODE_STATE_INIT; - ctx->multiple_edges_src_id = 0; - ctx->multiple_edges_dest_id = 0; - ctx->multiple_edges_array = NULL; + ctx->matrix_tuple_iterator = (MultiEdgeIterator){0}; ctx->current_relation_matrix_id = 0; - ctx->multiple_edges_current_index = 0; Config_Option_get(Config_VKEY_MAX_ENTITY_COUNT, &ctx->vkey_entity_count); @@ -58,7 +55,7 @@ void GraphEncodeContext_Reset(GraphEncodeContext *ctx) { } // Avoid leaks in case or reset during encodeing. - RG_MatrixTupleIter_detach(&ctx->matrix_tuple_iterator); + ctx->matrix_tuple_iterator = (MultiEdgeIterator){0}; } void GraphEncodeContext_InitHeader @@ -163,42 +160,12 @@ void GraphEncodeContext_SetCurrentRelationID(GraphEncodeContext *ctx, ctx->current_relation_matrix_id = current_relation_matrix_id; } -RG_MatrixTupleIter *GraphEncodeContext_GetMatrixTupleIterator( +MultiEdgeIterator *GraphEncodeContext_GetMatrixTupleIterator( GraphEncodeContext *ctx) { ASSERT(ctx); return &ctx->matrix_tuple_iterator; } -void GraphEncodeContext_SetMutipleEdgesArray(GraphEncodeContext *ctx, EdgeID *edges, - uint current_index, NodeID src, NodeID dest) { - ASSERT(ctx); - ctx->multiple_edges_array = edges; - ctx->multiple_edges_current_index = current_index; - ctx->multiple_edges_src_id = src; - ctx->multiple_edges_dest_id = dest; -} - -EdgeID *GraphEncodeContext_GetMultipleEdgesArray(const GraphEncodeContext *ctx) { - ASSERT(ctx); - return ctx->multiple_edges_array; -} - -uint GraphEncodeContext_GetMultipleEdgesCurrentIndex(const GraphEncodeContext *ctx) { - ASSERT(ctx); - return ctx->multiple_edges_current_index; -} - - -NodeID GraphEncodeContext_GetMultipleEdgesSourceNode(const GraphEncodeContext *ctx) { - ASSERT(ctx); - return ctx->multiple_edges_src_id; -} - -NodeID GraphEncodeContext_GetMultipleEdgesDestinationNode(const GraphEncodeContext *ctx) { - ASSERT(ctx); - return ctx->multiple_edges_dest_id; -} - bool GraphEncodeContext_Finished(const GraphEncodeContext *ctx) { ASSERT(ctx); return ctx->keys_processed == GraphEncodeContext_GetKeyCount(ctx); @@ -221,4 +188,3 @@ void GraphEncodeContext_Free(GraphEncodeContext *ctx) { rm_free(ctx); } } - diff --git a/src/serializers/encode_context.h b/src/serializers/encode_context.h index aa0a55b45..7e05c1785 100644 --- a/src/serializers/encode_context.h +++ b/src/serializers/encode_context.h @@ -11,7 +11,7 @@ #include "stdbool.h" #include "../graph/graph.h" #include "../util/datablock/datablock.h" -#include "../graph/rg_matrix/rg_matrix_iter.h" +#include "../graph/delta_matrix/delta_matrix_iter.h" #include "../graph/entities/graph_entity.h" #include "rax.h" @@ -41,19 +41,15 @@ typedef struct { // GraphEncodeContext maintains the state of a graph being encoded or decoded typedef struct { - rax *meta_keys; // The holds the names of meta keys representing the graph. - uint64_t offset; // Number of encoded entities in the current state. - EncodeState state; // Represents the current encoding state. - uint64_t keys_processed; // Count the number of procssed graph keys. - GraphEncodeHeader header; // Header replied for each vkey - uint64_t vkey_entity_count; // Number of entities in a single virtual key. - NodeID multiple_edges_src_id; // The current edges array sourc node id. - NodeID multiple_edges_dest_id; // The current edges array destination node id. - EdgeID *multiple_edges_array; // Multiple edges array, save in the context. - uint current_relation_matrix_id; // Current encoded relationship matrix. - uint multiple_edges_current_index; // The current index of the encoded edges array. - DataBlockIterator *datablock_iterator; // Datablock iterator to be saved in the context. - RG_MatrixTupleIter matrix_tuple_iterator; // Matrix tuple iterator to be saved in the context. + rax *meta_keys; // The holds the names of meta keys representing the graph. + uint64_t offset; // Number of encoded entities in the current state. + EncodeState state; // Represents the current encoding state. + uint64_t keys_processed; // Count the number of procssed graph keys. + GraphEncodeHeader header; // Header replied for each vkey + uint64_t vkey_entity_count; // Number of entities in a single virtual key. + uint current_relation_matrix_id; // Current encoded relationship matrix. + DataBlockIterator *datablock_iterator; // Datablock iterator to be saved in the context. + MultiEdgeIterator matrix_tuple_iterator; // Matrix tuple iterator to be saved in the context. } GraphEncodeContext; // Creates a new graph encoding context. @@ -106,23 +102,7 @@ void GraphEncodeContext_SetCurrentRelationID(GraphEncodeContext *ctx, uint current_relation_matrix_id); // Retrieve stored matrix tuple iterator. -RG_MatrixTupleIter *GraphEncodeContext_GetMatrixTupleIterator(GraphEncodeContext *ctx); - -// Sets a multiple edges array and the current index, for saving the state of multiple edges encoding. -void GraphEncodeContext_SetMutipleEdgesArray(GraphEncodeContext *ctx, EdgeID *edges, - uint current_index, NodeID src, NodeID dest); - -// Retrive the multiple edges array, to continue array of multiple edge encoding. -EdgeID *GraphEncodeContext_GetMultipleEdgesArray(const GraphEncodeContext *ctx); - -// Retrive the multiple edges array current index, to continue array of multiple edge encoding. -uint GraphEncodeContext_GetMultipleEdgesCurrentIndex(const GraphEncodeContext *ctx); - -// Retrive the multiple edges array source node. -NodeID GraphEncodeContext_GetMultipleEdgesSourceNode(const GraphEncodeContext *ctx); - -// Retrive the multiple edges array destination node. -NodeID GraphEncodeContext_GetMultipleEdgesDestinationNode(const GraphEncodeContext *ctx); +MultiEdgeIterator *GraphEncodeContext_GetMatrixTupleIterator(GraphEncodeContext *ctx); // Returns if the the number of processed keys is equal to the total number of graph keys. bool GraphEncodeContext_Finished(const GraphEncodeContext *ctx); @@ -132,4 +112,3 @@ void GraphEncodeContext_IncreaseProcessedKeyCount(GraphEncodeContext *ctx); // Free graph encoding context. void GraphEncodeContext_Free(GraphEncodeContext *ctx); - diff --git a/src/serializers/encoder/v14/encode_graph_entities.c b/src/serializers/encoder/v14/encode_graph_entities.c index 422fa00f3..39994cbf2 100644 --- a/src/serializers/encoder/v14/encode_graph_entities.c +++ b/src/serializers/encoder/v14/encode_graph_entities.c @@ -272,44 +272,6 @@ void RdbSaveNodes_v14 } } -// Auxilary function to encode a multiple edges array, -// while consdirating the allowed number of edges to encode -// returns true if the number of encoded edges has reached the capacity -static void _RdbSaveMultipleEdges -( - SerializerIO rdb, // RDB IO. - GraphContext *gc, // Graph context. - uint r, // Edges relation id. - EdgeID *multiple_edges_array, // Multiple edges array (passed by ref). - uint *multiple_edges_current_index, // Current index of the array to start encoding from (passed by ref). - uint64_t *encoded_edges, // Number of encoded edges in this phase (passed by ref). - uint64_t edges_to_encode, // Allowed capacity for encoding edges. - NodeID src, // Edges source node id. - NodeID dest // Edges destination node id. -) { - uint edgeCount = array_len(multiple_edges_array); - - // define function local variables from passed-by-reference parameters. - uint i = *multiple_edges_current_index; - uint encoded_edges_count = *encoded_edges; - - // add edges as long the number of encoded edges is in the allowed range - // and the array is not depleted - while(i < edgeCount && encoded_edges_count < edges_to_encode) { - Edge e; - EdgeID edgeID = multiple_edges_array[i++]; - e.src_id = src; - e.dest_id = dest; - Graph_GetEdge(gc->g, edgeID, &e); - _RdbSaveEdge(rdb, gc->g, &e, r); - encoded_edges_count++; - } - - // update passed-by-reference parameters - *encoded_edges = encoded_edges_count; - *multiple_edges_current_index = i; -} - void RdbSaveEdges_v14 ( SerializerIO rdb, @@ -324,8 +286,8 @@ void RdbSaveEdges_v14 // relation type // edge properties - GrB_Info info; - UNUSED(info); + bool depleted; + UNUSED(depleted); if(edges_to_encode == 0) return; @@ -341,50 +303,34 @@ void RdbSaveEdges_v14 // get current relation matrix uint r = GraphEncodeContext_GetCurrentRelationID(gc->encoding_context); - RG_Matrix M = Graph_GetRelationMatrix(gc->g, r, false); + NodeID src; + NodeID dest; // get matrix tuple iterator from context // already set to the next entry to fetch // for previous edge encide or create new one - RG_MatrixTupleIter *iter = GraphEncodeContext_GetMatrixTupleIterator(gc->encoding_context); - if(!RG_MatrixTupleIter_is_attached(iter, M)) { - info = RG_MatrixTupleIter_attach(iter, M); - ASSERT(info == GrB_SUCCESS); - } + uint relation_count = Graph_RelationTypeCount(gc->g); + MultiEdgeIterator *iter = GraphEncodeContext_GetMatrixTupleIterator(gc->encoding_context); + if(r < relation_count) { + Graph_GetRelationMatrix(gc->g, r, false); + Graph_GetMultiEdgeRelationMatrix(gc->g, r); - // first, see if the last edges encoding stopped at multiple edges array - EdgeID *multiple_edges_array = GraphEncodeContext_GetMultipleEdgesArray(gc->encoding_context); - NodeID src = GraphEncodeContext_GetMultipleEdgesSourceNode(gc->encoding_context); - NodeID dest = GraphEncodeContext_GetMultipleEdgesDestinationNode(gc->encoding_context); - uint multiple_edges_current_index = GraphEncodeContext_GetMultipleEdgesCurrentIndex( - gc->encoding_context); - if(multiple_edges_array) { - _RdbSaveMultipleEdges(rdb, gc, r, multiple_edges_array, - &multiple_edges_current_index, - &encoded_edges, edges_to_encode, src, dest); - // if the multiple edges array filled the capacity of entities allowed - // to be encoded, finish encoding - if(encoded_edges == edges_to_encode) { - goto finish; - } else { - // reset the multiple edges context for re-use - multiple_edges_array = NULL; - multiple_edges_current_index = 0; + if(!MultiEdgeIterator_is_attached(iter, gc->g->relations + r)) { + MultiEdgeIterator_AttachSourceRange(iter, gc->g->relations + r, 0, UINT64_MAX, false); } } - uint relation_count = Graph_RelationTypeCount(gc->g); // write the required number of edges while(encoded_edges < edges_to_encode) { Edge e; EdgeID edgeID; // try to get next tuple - info = RG_MatrixTupleIter_next_UINT64(iter, &src, &dest, &edgeID); + depleted = !MultiEdgeIterator_next(iter, &src, &dest, &edgeID); // if iterator is depleted // get new tuple from different matrix or finish encode - while(info == GxB_EXHAUSTED) { + while(depleted) { // proceed to next relation matrix r++; @@ -392,44 +338,27 @@ void RdbSaveEdges_v14 if(r == relation_count) goto finish; // get matrix and set iterator - M = Graph_GetRelationMatrix(gc->g, r, false); - info = RG_MatrixTupleIter_attach(iter, M); - ASSERT(info == GrB_SUCCESS); - info = RG_MatrixTupleIter_next_UINT64(iter, &src, &dest, &edgeID); + Graph_GetRelationMatrix(gc->g, r, false); + Graph_GetMultiEdgeRelationMatrix(gc->g, r); + MultiEdgeIterator_AttachSourceRange(iter, gc->g->relations + r, 0, UINT64_MAX, false); + depleted = !MultiEdgeIterator_next(iter, &src, &dest, &edgeID); } - ASSERT(info == GrB_SUCCESS); + ASSERT(!depleted); e.src_id = src; e.dest_id = dest; - if(SINGLE_EDGE(edgeID)) { - Graph_GetEdge(gc->g, edgeID, &e); - _RdbSaveEdge(rdb, gc->g, &e, r); - encoded_edges++; - } else { - multiple_edges_array = (EdgeID *)(CLEAR_MSB(edgeID)); - _RdbSaveMultipleEdges(rdb, gc, r, multiple_edges_array, - &multiple_edges_current_index, &encoded_edges, edges_to_encode, src, dest); - // if the multiple edges array filled the capacity of entities - // allowed to be encoded, finish encoding - if(encoded_edges == edges_to_encode) { - goto finish; - } else { - // reset the multiple edges context for re-use - multiple_edges_array = NULL; - multiple_edges_current_index = 0; - } - } + Graph_GetEdge(gc->g, edgeID, &e); + _RdbSaveEdge(rdb, gc->g, &e, r); + encoded_edges++; } finish: // check if done encoding edges if(offset + edges_to_encode == graph_edges) { - RG_MatrixTupleIter_detach(iter); + *iter = (MultiEdgeIterator){0}; } // update context GraphEncodeContext_SetCurrentRelationID(gc->encoding_context, r); - GraphEncodeContext_SetMutipleEdgesArray(gc->encoding_context, multiple_edges_array, - multiple_edges_current_index, src, dest); -} +} \ No newline at end of file diff --git a/src/serializers/graph_extensions.c b/src/serializers/graph_extensions.c index e5c3134d6..9f62fe43b 100644 --- a/src/serializers/graph_extensions.c +++ b/src/serializers/graph_extensions.c @@ -4,12 +4,13 @@ * the Server Side Public License v1 (SSPLv1). */ -#include "graph_extensions.h" #include "../RG.h" +#include "../util/arr.h" +#include "graph_extensions.h" #include "../util/datablock/oo_datablock.h" // functions declerations - implemented in graph.c -bool Graph_FormConnection(Graph *g, NodeID src, NodeID dest, EdgeID edge_id, int r); +void Graph_FormConnection(Graph *g, NodeID src, NodeID dest, EdgeID edge_id, int r); void Graph_EnsureNodeCap ( @@ -20,24 +21,24 @@ void Graph_EnsureNodeCap uint n; GrB_Index dim = Graph_RequiredMatrixDim(g); - RG_Matrix M = NULL; + Delta_Matrix M = NULL; M = Graph_GetAdjacencyMatrix(g, false); - RG_Matrix_resize(M, dim, dim); + Delta_Matrix_resize(M, dim, dim); M = Graph_GetNodeLabelMatrix(g); - RG_Matrix_resize(M, dim, dim); + Delta_Matrix_resize(M, dim, dim); n = array_len(g->labels); for(int i = 0; i < n; i ++) { M = Graph_GetLabelMatrix(g, i); - RG_Matrix_resize(M, dim, dim); + Delta_Matrix_resize(M, dim, dim); } n = array_len(g->relations); for(int i = 0; i < n; i ++) { M = Graph_GetRelationMatrix(g, i, false); - RG_Matrix_resize(M, dim, dim); + Delta_Matrix_resize(M, dim, dim); } } @@ -78,8 +79,8 @@ void Serializer_Graph_SetNode for(uint i = 0; i < label_count; i ++) { LabelID label = labels[i]; // set label matrix at position [id, id] - RG_Matrix M = Graph_GetLabelMatrix(g, label); - GrB_Matrix m = RG_MATRIX_M(M); + Delta_Matrix M = Graph_GetLabelMatrix(g, label); + GrB_Matrix m = Delta_Matrix_M(M); info = GrB_Matrix_setElement_BOOL(m, true, id, id); if(info == GrB_INVALID_INDEX) { RedisModule_Log(NULL, "notice", "RESIZE LABEL MATRIX"); @@ -102,20 +103,20 @@ void Serializer_Graph_SetNodeLabels GrB_Vector v; int node_count = Graph_RequiredMatrixDim(g); int label_count = Graph_LabelTypeCount(g); - RG_Matrix node_labels = Graph_GetNodeLabelMatrix(g); - GrB_Matrix node_labels_m = RG_MATRIX_M(node_labels); + Delta_Matrix node_labels = Graph_GetNodeLabelMatrix(g); + GrB_Matrix node_labels_m = Delta_Matrix_M(node_labels); #if RG_DEBUG GrB_Index nvals; - RG_Matrix_nvals(&nvals, node_labels); + Delta_Matrix_nvals(&nvals, node_labels); ASSERT(nvals == 0); #endif GrB_Vector_new(&v, GrB_BOOL, node_count); for(int i = 0; i < label_count; i++) { - RG_Matrix M = Graph_GetLabelMatrix(g, i); - GrB_Matrix m = RG_MATRIX_M(M); + Delta_Matrix M = Graph_GetLabelMatrix(g, i); + GrB_Matrix m = Delta_Matrix_M(M); GxB_Vector_diag(v, m, 0, NULL); @@ -128,7 +129,6 @@ void Serializer_Graph_SetNodeLabels } // optimized version of Graph_FormConnection -// used only when matrix doesn't contains multi edge values static void _OptimizedSingleEdgeFormConnection ( Graph *g, @@ -138,12 +138,12 @@ static void _OptimizedSingleEdgeFormConnection int r ) { GrB_Info info; - RG_Matrix M = Graph_GetRelationMatrix(g, r, false); - RG_Matrix adj = Graph_GetAdjacencyMatrix(g, false); - GrB_Matrix m = RG_MATRIX_M(M); - GrB_Matrix tm = RG_MATRIX_TM(M); - GrB_Matrix adj_m = RG_MATRIX_M(adj); - GrB_Matrix adj_tm = RG_MATRIX_TM(adj); + Delta_Matrix M = Graph_GetRelationMatrix(g, r, false); + Delta_Matrix adj = Graph_GetAdjacencyMatrix(g, false); + GrB_Matrix m = Delta_Matrix_M(M); + GrB_Matrix tm = Delta_Matrix_M(Delta_Matrix_getTranspose(M)); + GrB_Matrix adj_m = Delta_Matrix_M(adj); + GrB_Matrix adj_tm = Delta_Matrix_M(Delta_Matrix_getTranspose(adj)); UNUSED(info); @@ -175,8 +175,6 @@ static void _OptimizedSingleEdgeFormConnection info = GrB_Matrix_setElement_BOOL(tm, true, dest, src); ASSERT(info == GrB_SUCCESS); - // an edge of type r has just been created, update statistics - // TODO: stats->edge_count[relation_idx] += nvals; GraphStatistics_IncEdgeCount(&g->stats, r, 1); } @@ -203,15 +201,7 @@ void Serializer_Graph_SetEdge e->relationID = r; if(multi_edge) { - if(!Graph_FormConnection(g, src, dest, edge_id, r)) { - // resize matrices - RedisModule_Log(NULL, "notice", "RESIZE MATRIX MULTI EDGE"); - - uint64_t max_id = MAX(src, dest); - Graph_EnsureNodeCap(g, max_id); - bool res = Graph_FormConnection(g, src, dest, edge_id, r); - ASSERT(res == true); - } + Graph_FormConnection(g, src, dest, edge_id, r); } else { _OptimizedSingleEdgeFormConnection(g, src, dest, edge_id, r); } diff --git a/tests/flow/test_graph_deletion.py b/tests/flow/test_graph_deletion.py index 74986e07c..ae4b8e0ad 100644 --- a/tests/flow/test_graph_deletion.py +++ b/tests/flow/test_graph_deletion.py @@ -348,7 +348,7 @@ def test18_delete_self_edge(self): def test19_random_delete(self): # test random graph deletion added as a result of a crash found in Graph_GetNodeEdges - # when iterating RG_Matrix of type BOOL with RG_MatrixTupleIter_next_UINT64 + # when iterating Delta_Matrix of type BOOL with Delta_MatrixTupleIter_next_UINT64 for i in range(1, 10): self.graph.delete() diff --git a/tests/unit/test_algebraic_expression.c b/tests/unit/test_algebraic_expression.c index 2dbb9cbe2..a3167ad1e 100644 --- a/tests/unit/test_algebraic_expression.c +++ b/tests/unit/test_algebraic_expression.c @@ -36,16 +36,16 @@ extern AR_ExpNode **_BuildReturnExpressions(const cypher_astnode_t *ret_clause, QueryGraph *qg; // Matrices. -RG_Matrix mat_p; -RG_Matrix mat_ef; -RG_Matrix mat_tef; -RG_Matrix mat_f; -RG_Matrix mat_ev; -RG_Matrix mat_tev; -RG_Matrix mat_c; -RG_Matrix mat_ew; -RG_Matrix mat_tew; -RG_Matrix mat_e; +Delta_Matrix mat_p; +Delta_Matrix mat_ef; +Delta_Matrix mat_tef; +Delta_Matrix mat_f; +Delta_Matrix mat_ev; +Delta_Matrix mat_tev; +Delta_Matrix mat_c; +Delta_Matrix mat_ew; +Delta_Matrix mat_tew; +Delta_Matrix mat_e; rax *_matrices; const char *query_no_intermidate_return_nodes = @@ -220,10 +220,10 @@ void _print_matrix(GrB_Matrix mat) { } } -bool _compare_matrices(GrB_Matrix expected, RG_Matrix actual) { +bool _compare_matrices(GrB_Matrix expected, Delta_Matrix actual) { GrB_Matrix a = expected; GrB_Matrix b = NULL; - RG_Matrix_export(&b, actual); + Delta_Matrix_export(&b, actual); GrB_Index acols, arows, avals; GrB_Index bcols, brows, bvals; @@ -340,7 +340,7 @@ void tearDown() { } void test_algebraicExpression() { - RG_Matrix matrix = NULL; + Delta_Matrix matrix = NULL; bool diagonal = false; const char *src = "src"; const char *dest = "dest"; @@ -596,25 +596,25 @@ void test_algebraicExpression_Transpose() { void test_Exp_OP_ADD() { // Exp = A + B - RG_Matrix A; - RG_Matrix B; - RG_Matrix res; + Delta_Matrix A; + Delta_Matrix B; + Delta_Matrix res; GrB_Matrix expected; // A // 1 1 // 0 0 - RG_Matrix_new(&A, GrB_BOOL, 2, 2); - RG_Matrix_setElement_BOOL(A, 0, 0); - RG_Matrix_setElement_BOOL(A, 0, 1); + Delta_Matrix_new(&A, GrB_BOOL, 2, 2, false); + Delta_Matrix_setElement_BOOL(A, 0, 0); + Delta_Matrix_setElement_BOOL(A, 0, 1); // B // 0 1 // 1 1 - RG_Matrix_new(&B, GrB_BOOL, 2, 2); - RG_Matrix_setElement_BOOL(B, 0, 1); - RG_Matrix_setElement_BOOL(B, 1, 0); - RG_Matrix_setElement_BOOL(B, 1, 1); + Delta_Matrix_new(&B, GrB_BOOL, 2, 2, false); + Delta_Matrix_setElement_BOOL(B, 0, 1); + Delta_Matrix_setElement_BOOL(B, 1, 0); + Delta_Matrix_setElement_BOOL(B, 1, 1); // expected // 1 1 @@ -632,7 +632,7 @@ void test_Exp_OP_ADD() { // Matrix used for intermidate computations of AlgebraicExpression_Eval // but also contains the result of expression evaluation. - RG_Matrix_new(&res, GrB_BOOL, 2, 2); + Delta_Matrix_new(&res, GrB_BOOL, 2, 2, false); AlgebraicExpression_Eval(exp, res); // Using the A matrix described above, @@ -640,33 +640,33 @@ void test_Exp_OP_ADD() { TEST_ASSERT(_compare_matrices(expected, res)); raxFree(matrices); - RG_Matrix_free(&A); - RG_Matrix_free(&B); - RG_Matrix_free(&res); + Delta_Matrix_free(&A); + Delta_Matrix_free(&B); + Delta_Matrix_free(&res); GrB_Matrix_free(&expected); AlgebraicExpression_Free(exp); } void test_Exp_OP_MUL() { // Exp = A * I - RG_Matrix A; - RG_Matrix i; - RG_Matrix res; + Delta_Matrix A; + Delta_Matrix i; + Delta_Matrix res; // A // 1 1 // 0 0 - RG_Matrix_new(&A, GrB_BOOL, 2, 2); - RG_Matrix_setElement_BOOL(A, 0, 0); - RG_Matrix_setElement_BOOL(A, 0, 1); - RG_Matrix_wait(A, true); // force flush + Delta_Matrix_new(&A, GrB_BOOL, 2, 2, false); + Delta_Matrix_setElement_BOOL(A, 0, 0); + Delta_Matrix_setElement_BOOL(A, 0, 1); + Delta_Matrix_wait(A, true); // force flush // I // 1 0 // 0 1 - RG_Matrix_new(&i, GrB_BOOL, 2, 2); - RG_Matrix_setElement_BOOL(i, 0, 0); - RG_Matrix_setElement_BOOL(i, 1, 1); + Delta_Matrix_new(&i, GrB_BOOL, 2, 2, false); + Delta_Matrix_setElement_BOOL(i, 0, 0); + Delta_Matrix_setElement_BOOL(i, 1, 1); rax *matrices = raxNew(); raxInsert(matrices, (unsigned char *)"A", strlen("A"), A, NULL); @@ -675,26 +675,26 @@ void test_Exp_OP_MUL() { // Matrix used for intermidate computations of AlgebraicExpression_Eval // but also contains the result of expression evaluation. - RG_Matrix_new(&res, GrB_BOOL, 2, 2); + Delta_Matrix_new(&res, GrB_BOOL, 2, 2, false); AlgebraicExpression_Eval(exp, res); // Using the A matrix described above, // A * I = A. GrB_Matrix expected; - RG_Matrix_export(&expected, A); + Delta_Matrix_export(&expected, A); TEST_ASSERT(_compare_matrices(expected, res)); raxFree(matrices); - RG_Matrix_free(&A); - RG_Matrix_free(&i); - RG_Matrix_free(&res); + Delta_Matrix_free(&A); + Delta_Matrix_free(&i); + Delta_Matrix_free(&res); GrB_Matrix_free(&expected); AlgebraicExpression_Free(exp); } void test_Exp_OP_ADD_Transpose() { // Exp = A + Transpose(A) - RG_Matrix res; + Delta_Matrix res; GrB_Matrix expected; /* We must use matrices that we've added to the graph, or else * the transpose optimization will erroneously use the adjacency matrix @@ -732,7 +732,7 @@ void test_Exp_OP_ADD_Transpose() { GrB_Matrix_setElement_BOOL(expected, true, 3, 0); // Matrix used for intermidate computations of AlgebraicExpression_Eval // but also contains the result of expression evaluation. - RG_Matrix_new(&res, GrB_BOOL, n, n); + Delta_Matrix_new(&res, GrB_BOOL, n, n, false); AlgebraicExpression *exp = AlgebraicExpression_FromString("V+tV", _matrices); AlgebraicExpression_Eval(exp, res); @@ -740,7 +740,7 @@ void test_Exp_OP_ADD_Transpose() { // A + Transpose(A) = B. TEST_ASSERT(_compare_matrices(expected, res)); - RG_Matrix_free(&res); + Delta_Matrix_free(&res); GrB_Matrix_free(&expected); AlgebraicExpression_Free(exp); } @@ -748,7 +748,7 @@ void test_Exp_OP_ADD_Transpose() { void test_Exp_OP_MUL_Transpose() { // Exp = Transpose(A) * A GrB_Matrix B; - RG_Matrix res; + Delta_Matrix res; /* We must use matrices that we've added to the graph, or else * the transpose optimization will erroneously use the adjacency matrix @@ -784,7 +784,7 @@ void test_Exp_OP_MUL_Transpose() { // Matrix used for intermidate computations of AlgebraicExpression_Eval // but also contains the result of expression evaluation. - RG_Matrix_new(&res, GrB_BOOL, n, n); + Delta_Matrix_new(&res, GrB_BOOL, n, n, false); // Transpose(A) * A AlgebraicExpression *exp = AlgebraicExpression_FromString("V*tV", _matrices); @@ -795,42 +795,42 @@ void test_Exp_OP_MUL_Transpose() { TEST_ASSERT(_compare_matrices(B, res)); GrB_Matrix_free(&B); - RG_Matrix_free(&res); + Delta_Matrix_free(&res); AlgebraicExpression_Free(exp); } void test_Exp_OP_A_MUL_B_Plus_C() { // Exp = A*(B+C) = A*B + A*C - RG_Matrix A; - RG_Matrix B; - RG_Matrix C; - RG_Matrix res; + Delta_Matrix A; + Delta_Matrix B; + Delta_Matrix C; + Delta_Matrix res; GrB_Matrix expected; // A // 1 1 // 0 0 - RG_Matrix_new(&A, GrB_BOOL, 2, 2); - RG_Matrix_setElement_BOOL(A, 0, 0); - RG_Matrix_setElement_BOOL(A, 0, 1); - RG_Matrix_wait(A, true); // force flush + Delta_Matrix_new(&A, GrB_BOOL, 2, 2, false); + Delta_Matrix_setElement_BOOL(A, 0, 0); + Delta_Matrix_setElement_BOOL(A, 0, 1); + Delta_Matrix_wait(A, true); // force flush // B // 1 0 // 0 0 - RG_Matrix_new(&B, GrB_BOOL, 2, 2); - RG_Matrix_setElement_BOOL(B, 0, 0); + Delta_Matrix_new(&B, GrB_BOOL, 2, 2, false); + Delta_Matrix_setElement_BOOL(B, 0, 0); // C // 0 0 // 0 1 - RG_Matrix_new(&C, GrB_BOOL, 2, 2); - RG_Matrix_setElement_BOOL(C, 1, 1); + Delta_Matrix_new(&C, GrB_BOOL, 2, 2, false); + Delta_Matrix_setElement_BOOL(C, 1, 1); // Matrix used for intermidate computations of AlgebraicExpression_Eval // but also contains the result of expression evaluation. - RG_Matrix_new(&res, GrB_BOOL, 2, 2); + Delta_Matrix_new(&res, GrB_BOOL, 2, 2, false); // A * (B+C) = A.rax *matrices = raxNew(); rax *matrices = raxNew(); @@ -849,10 +849,10 @@ void test_Exp_OP_A_MUL_B_Plus_C() { TEST_ASSERT(_compare_matrices(expected, res)); raxFree(matrices); - RG_Matrix_free(&A); - RG_Matrix_free(&B); - RG_Matrix_free(&C); - RG_Matrix_free(&res); + Delta_Matrix_free(&A); + Delta_Matrix_free(&B); + Delta_Matrix_free(&C); + Delta_Matrix_free(&res); GrB_Matrix_free(&expected); AlgebraicExpression_Free(exp); } @@ -860,13 +860,13 @@ void test_Exp_OP_A_MUL_B_Plus_C() { void test_ExpTransform_A_Times_B_Plus_C() { // Test Mul / Add transformation: // A*(B+C) -> A*B + A*C - RG_Matrix A; - RG_Matrix B; - RG_Matrix C; + Delta_Matrix A; + Delta_Matrix B; + Delta_Matrix C; - RG_Matrix_new(&A, GrB_BOOL, 2, 2); - RG_Matrix_new(&B, GrB_BOOL, 2, 2); - RG_Matrix_new(&C, GrB_BOOL, 2, 2); + Delta_Matrix_new(&A, GrB_BOOL, 2, 2, false); + Delta_Matrix_new(&B, GrB_BOOL, 2, 2, false); + Delta_Matrix_new(&C, GrB_BOOL, 2, 2, false); rax *matrices = raxNew(); raxInsert(matrices, (unsigned char *)"A", strlen("A"), A, NULL); @@ -899,24 +899,24 @@ void test_ExpTransform_A_Times_B_Plus_C() { TEST_ASSERT(rightRight->type == AL_OPERAND && rightRight->operand.matrix == B); raxFree(matrices); - RG_Matrix_free(&A); - RG_Matrix_free(&B); - RG_Matrix_free(&C); + Delta_Matrix_free(&A); + Delta_Matrix_free(&B); + Delta_Matrix_free(&C); AlgebraicExpression_Free(exp); } void test_ExpTransform_AB_Times_C_Plus_D() { // Test Mul / Add transformation: // A*B*(C+D) -> A*B*C + A*B*D - RG_Matrix A; - RG_Matrix B; - RG_Matrix C; - RG_Matrix D; + Delta_Matrix A; + Delta_Matrix B; + Delta_Matrix C; + Delta_Matrix D; - RG_Matrix_new(&A, GrB_BOOL, 2, 2); - RG_Matrix_new(&B, GrB_BOOL, 2, 2); - RG_Matrix_new(&C, GrB_BOOL, 2, 2); - RG_Matrix_new(&D, GrB_BOOL, 2, 2); + Delta_Matrix_new(&A, GrB_BOOL, 2, 2, false); + Delta_Matrix_new(&B, GrB_BOOL, 2, 2, false); + Delta_Matrix_new(&C, GrB_BOOL, 2, 2, false); + Delta_Matrix_new(&D, GrB_BOOL, 2, 2, false); // A*B*(C+D) -> A*B*C + A*B*D AlgebraicExpression *exp = AlgebraicExpression_NewOperand(C, false, NULL, @@ -959,24 +959,24 @@ void test_ExpTransform_AB_Times_C_Plus_D() { TEST_ASSERT(rightchild_2->type == AL_OPERAND && rightchild_2->operand.matrix == D); - RG_Matrix_free(&A); - RG_Matrix_free(&B); - RG_Matrix_free(&C); - RG_Matrix_free(&D); + Delta_Matrix_free(&A); + Delta_Matrix_free(&B); + Delta_Matrix_free(&C); + Delta_Matrix_free(&D); AlgebraicExpression_Free(exp); } void test_ExpTransform_A_Plus_B_Times_C_Plus_D() { // Test Mul / Add transformation: // (A+B)*(C+D) -> A*C + A*D + B*C + B*D - RG_Matrix A; - RG_Matrix B; - RG_Matrix C; - RG_Matrix D; - RG_Matrix_new(&A, GrB_BOOL, 2, 2); - RG_Matrix_new(&B, GrB_BOOL, 2, 2); - RG_Matrix_new(&C, GrB_BOOL, 2, 2); - RG_Matrix_new(&D, GrB_BOOL, 2, 2); + Delta_Matrix A; + Delta_Matrix B; + Delta_Matrix C; + Delta_Matrix D; + Delta_Matrix_new(&A, GrB_BOOL, 2, 2, false); + Delta_Matrix_new(&B, GrB_BOOL, 2, 2, false); + Delta_Matrix_new(&C, GrB_BOOL, 2, 2, false); + Delta_Matrix_new(&D, GrB_BOOL, 2, 2, false); rax *matrices = raxNew(); raxInsert(matrices, (unsigned char *)"A", strlen("A"), A, NULL); @@ -1009,10 +1009,10 @@ void test_ExpTransform_A_Plus_B_Times_C_Plus_D() { TEST_ASSERT(strcmp("(((A * C + A * D) + B * C) + B * D)", exp_str) == 0); rm_free(exp_str); raxFree(matrices); - RG_Matrix_free(&A); - RG_Matrix_free(&B); - RG_Matrix_free(&C); - RG_Matrix_free(&D); + Delta_Matrix_free(&A); + Delta_Matrix_free(&B); + Delta_Matrix_free(&C); + Delta_Matrix_free(&D); AlgebraicExpression_Free(exp); } @@ -1514,15 +1514,15 @@ void test_ExpressionExecute() { TEST_ASSERT(strcmp(AlgebraicExpression_Src(exp), "p") == 0); TEST_ASSERT(strcmp(AlgebraicExpression_Dest(exp), "e") == 0); - RG_Matrix res; - RG_Matrix_new(&res, GrB_BOOL, Graph_RequiredMatrixDim(g), - Graph_RequiredMatrixDim(g)); + Delta_Matrix res; + Delta_Matrix_new(&res, GrB_BOOL, Graph_RequiredMatrixDim(g), + Graph_RequiredMatrixDim(g), false); AlgebraicExpression_Eval(exp, res); // Validate result matrix. GrB_Index ncols, nrows; - RG_Matrix_ncols(&ncols, res); - RG_Matrix_nrows(&nrows, res); + Delta_Matrix_ncols(&ncols, res); + Delta_Matrix_nrows(&nrows, res); assert(ncols == Graph_RequiredMatrixDim(g)); assert(nrows == Graph_RequiredMatrixDim(g)); @@ -1537,7 +1537,7 @@ void test_ExpressionExecute() { assert(_compare_matrices(expected, res)); // Clean up - RG_Matrix_free(&res); + Delta_Matrix_free(&res); GrB_Matrix_free(&expected); free_algebraic_expressions(ae, exp_count); array_free(ae); @@ -1754,7 +1754,7 @@ void test_RemoveOperand() { void test_LocateOperand() { // construct algebraic expression bool located = false; - RG_Matrix mat = NULL; + Delta_Matrix mat = NULL; AlgebraicExpression *A = NULL; AlgebraicExpression *B = NULL; AlgebraicExpression *r = NULL; diff --git a/tests/unit/test_all_paths.c b/tests/unit/test_all_paths.c index 200b8d207..782ef5c5d 100644 --- a/tests/unit/test_all_paths.c +++ b/tests/unit/test_all_paths.c @@ -20,7 +20,8 @@ static Graph *BuildGraph() { Edge e; Node n; size_t nodeCount = 4; - Graph *g = Graph_New(nodeCount, nodeCount); + size_t edgeCount = 7; + Graph *g = Graph_New(nodeCount, edgeCount); int relation = Graph_AddRelationType(g); for(int i = 0; i < 4; i++) { n = GE_NEW_NODE(); diff --git a/tests/unit/test_graph.c b/tests/unit/test_graph.c index e79c7d81f..b9e0c3896 100644 --- a/tests/unit/test_graph.c +++ b/tests/unit/test_graph.c @@ -45,10 +45,10 @@ void _test_node_creation(Graph *g, size_t node_count) { } // Validate nodes creation. - RG_Matrix adj = Graph_GetAdjacencyMatrix(g, false); - TEST_ASSERT(RG_Matrix_nrows(&nrows, adj) == GrB_SUCCESS); - TEST_ASSERT(RG_Matrix_ncols(&ncols, adj) == GrB_SUCCESS); - TEST_ASSERT(RG_Matrix_nvals(&nvals, adj) == GrB_SUCCESS); + Delta_Matrix adj = Graph_GetAdjacencyMatrix(g, false); + TEST_ASSERT(Delta_Matrix_nrows(&nrows, adj) == GrB_SUCCESS); + TEST_ASSERT(Delta_Matrix_ncols(&ncols, adj) == GrB_SUCCESS); + TEST_ASSERT(Delta_Matrix_nvals(&nvals, adj) == GrB_SUCCESS); TEST_ASSERT(nvals == 0); // No connection were formed. TEST_ASSERT(ncols >= Graph_NodeCount(g)); // Graph's adjacency matrix dimensions. @@ -226,10 +226,10 @@ void test_newGraph() { GrB_Index ncols, nrows, nvals; Graph *g = Graph_New(GRAPH_DEFAULT_NODE_CAP, GRAPH_DEFAULT_EDGE_CAP); Graph_AcquireWriteLock(g); - RG_Matrix adj_matrix = g->adjacency_matrix; - TEST_ASSERT(RG_Matrix_ncols(&ncols, adj_matrix) == GrB_SUCCESS); - TEST_ASSERT(RG_Matrix_nrows(&nrows, adj_matrix) == GrB_SUCCESS); - TEST_ASSERT(RG_Matrix_nvals(&nvals, adj_matrix) == GrB_SUCCESS); + Delta_Matrix adj_matrix = g->adjacency_matrix; + TEST_ASSERT(Delta_Matrix_ncols(&ncols, adj_matrix) == GrB_SUCCESS); + TEST_ASSERT(Delta_Matrix_nrows(&nrows, adj_matrix) == GrB_SUCCESS); + TEST_ASSERT(Delta_Matrix_nvals(&nvals, adj_matrix) == GrB_SUCCESS); TEST_ASSERT(g->nodes != NULL); TEST_ASSERT(g->relations != NULL); @@ -258,7 +258,7 @@ void test_graphConstruction() { void test_removeNodes() { // Construct graph. - RG_Matrix M; + Delta_Matrix M; GrB_Index nnz; Graph *g = Graph_New(32, 32); Graph_AcquireWriteLock(g); @@ -290,11 +290,11 @@ void test_removeNodes() { // Validate graph creation. TEST_ASSERT(Graph_NodeCount(g) == 3); M = Graph_GetRelationMatrix(g, r, false); - RG_Matrix_nvals(&nnz, M); + Delta_Matrix_nvals(&nnz, M); TEST_ASSERT(nnz == 3); M = Graph_GetAdjacencyMatrix(g, false); - RG_Matrix_nvals(&nnz, M); + Delta_Matrix_nvals(&nnz, M); TEST_ASSERT(nnz == 3); Edge *edges = (Edge *)array_new(Edge, 3); diff --git a/tests/unit/test_rg_matrix.c b/tests/unit/test_rg_matrix.c deleted file mode 100644 index 7be4f0d2d..000000000 --- a/tests/unit/test_rg_matrix.c +++ /dev/null @@ -1,1632 +0,0 @@ -/* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ - -#include "src/util/rmalloc.h" -#include "src/configuration/config.h" -#include "src/graph/rg_matrix/rg_matrix.h" - -#include - -void setup(); -void tearDown(); - -#define TEST_INIT setup(); -#define TEST_FINI tearDown(); -#include "acutest.h" - -#define MATRIX_EMPTY(M) \ - ({ \ - GrB_Matrix_nvals(&nvals, M); \ - TEST_ASSERT(nvals == 0); \ - }) - -#define MATRIX_NOT_EMPTY(M) \ - ({ \ - GrB_Matrix_nvals(&nvals, M); \ - TEST_ASSERT(nvals != 0); \ - }) - -#define M_EMPTY() MATRIX_EMPTY(M) -#define DP_EMPTY() MATRIX_EMPTY(DP) -#define DM_EMPTY() MATRIX_EMPTY(DM) - -#define M_NOT_EMPTY() MATRIX_NOT_EMPTY(M) -#define DP_NOT_EMPTY() MATRIX_NOT_EMPTY(DP) -#define DM_NOT_EMPTY() MATRIX_NOT_EMPTY(DM) - -void setup() { - // use the malloc family for allocations - Alloc_Reset(); - - // initialize GraphBLAS - GrB_init(GrB_NONBLOCKING); - - // all matrices in CSR format - GxB_Global_Option_set(GxB_FORMAT, GxB_BY_ROW); - - // set delta matrix flush threshold - Config_Option_set(Config_DELTA_MAX_PENDING_CHANGES, "10000", NULL); -} - -void tearDown() { - GrB_finalize(); -} - -// nvals(A + B) == nvals(A) == nvals(B) -void ASSERT_GrB_Matrices_EQ(const GrB_Matrix A, const GrB_Matrix B) -{ - GrB_Type t_A = NULL; - GrB_Type t_B = NULL; - GrB_Matrix C = NULL; - GrB_Info info = GrB_SUCCESS; - GrB_Index nvals_A = 0; - GrB_Index nvals_B = 0; - GrB_Index nvals_C = 0; - GrB_Index nrows_A = 0; - GrB_Index ncols_A = 0; - GrB_Index nrows_B = 0; - GrB_Index ncols_B = 0; - - //-------------------------------------------------------------------------- - // type(A) == type(B) - //-------------------------------------------------------------------------- - - info = GxB_Matrix_type(&t_A, A); - TEST_ASSERT(info == GrB_SUCCESS); - - info = GxB_Matrix_type(&t_B, B); - TEST_ASSERT(info == GrB_SUCCESS); - - TEST_ASSERT(t_A == t_B); - - //-------------------------------------------------------------------------- - // dim(A) == dim(B) - //-------------------------------------------------------------------------- - - info = GrB_Matrix_nrows(&nrows_A, A); - TEST_ASSERT(info == GrB_SUCCESS); - - info = GrB_Matrix_ncols(&ncols_A, A); - TEST_ASSERT(info == GrB_SUCCESS); - - info = GrB_Matrix_nrows(&nrows_B, B); - TEST_ASSERT(info == GrB_SUCCESS); - - info = GrB_Matrix_ncols(&ncols_B, B); - TEST_ASSERT(info == GrB_SUCCESS); - - TEST_ASSERT(nrows_A == nrows_B); - TEST_ASSERT(ncols_A == ncols_B); - - //-------------------------------------------------------------------------- - // NNZ(A) == NNZ(B) - //-------------------------------------------------------------------------- - - GrB_Matrix_nvals(&nvals_A, A); - TEST_ASSERT(info == GrB_SUCCESS); - - GrB_Matrix_nvals(&nvals_B, B); - TEST_ASSERT(info == GrB_SUCCESS); - - //-------------------------------------------------------------------------- - // structure(A) == structure(B) - //-------------------------------------------------------------------------- - - info = GrB_Matrix_new(&C, t_A, nrows_A, ncols_A); - TEST_ASSERT(info == GrB_SUCCESS); - - info = GrB_Matrix_eWiseMult_BinaryOp(C, NULL, NULL, GrB_LAND, A, B, NULL); - TEST_ASSERT(info == GrB_SUCCESS); - - GrB_Matrix_nvals(&nvals_C, C); - TEST_ASSERT(info == GrB_SUCCESS); - - TEST_ASSERT(nvals_C == nvals_A); - - // clean up - info = GrB_Matrix_free(&C); - TEST_ASSERT(info == GrB_SUCCESS); -} - -// test RGMatrix initialization -void test_RGMatrix_new() { - RG_Matrix A = NULL; - GrB_Matrix M = NULL; - GrB_Matrix DP = NULL; - GrB_Matrix DM = NULL; - GrB_Type t = GrB_UINT64; - GrB_Info info = GrB_SUCCESS; - GrB_Index nvals = 0; - GrB_Index nrows = 100; - GrB_Index ncols = 100; - - info = RG_Matrix_new(&A, t, nrows, ncols); - TEST_ASSERT(info == GrB_SUCCESS); - - // get internal matrices - M = RG_MATRIX_M(A); - DP = RG_MATRIX_DELTA_PLUS(A); - DM = RG_MATRIX_DELTA_MINUS(A); - - // uint64 matrix always maintain transpose - TEST_ASSERT(RG_MATRIX_MAINTAIN_TRANSPOSE(A)); - - // uint64 matrix always multi edge - TEST_ASSERT(RG_MATRIX_MULTI_EDGE(A)); - - // a new empty matrix should be synced - // no data in either DP or DM - TEST_ASSERT(RG_Matrix_Synced(A)); - - // test M, DP and DM hyper switch - int format; - double hyper_switch; - - // M should be either hyper-sparse or sparse - GxB_Matrix_Option_get(M, GxB_SPARSITY_CONTROL, &format); - TEST_ASSERT(format == (GxB_SPARSE | GxB_HYPERSPARSE)); - - // DP should always be hyper - GxB_Matrix_Option_get(DP, GxB_HYPER_SWITCH, &hyper_switch); - TEST_ASSERT(hyper_switch == GxB_ALWAYS_HYPER); - GxB_Matrix_Option_get(DP, GxB_SPARSITY_CONTROL, &format); - TEST_ASSERT(format == GxB_HYPERSPARSE); - - // DM should always be hyper - GxB_Matrix_Option_get(DM, GxB_HYPER_SWITCH, &hyper_switch); - TEST_ASSERT(hyper_switch == GxB_ALWAYS_HYPER); - GxB_Matrix_Option_get(DM, GxB_SPARSITY_CONTROL, &format); - TEST_ASSERT(format == GxB_HYPERSPARSE); - - // matrix should be empty - M_EMPTY(); - DP_EMPTY(); - DM_EMPTY(); - RG_Matrix_nvals(&nvals, A); - TEST_ASSERT(nvals == 0); - - RG_Matrix_free(&A); - TEST_ASSERT(A == NULL); - - t = GrB_BOOL; - - info = RG_Matrix_new(&A, t, nrows, ncols); - TEST_ASSERT(info == GrB_SUCCESS); - - // get internal matrices - M = RG_MATRIX_M(A); - DP = RG_MATRIX_DELTA_PLUS(A); - DM = RG_MATRIX_DELTA_MINUS(A); - - // bool matrix do not maintain transpose - TEST_ASSERT(!(RG_MATRIX_MAINTAIN_TRANSPOSE(A))); - - // bool matrix always not multi edge - TEST_ASSERT(!RG_MATRIX_MULTI_EDGE(A)); - - // a new empty matrix should be synced - // no data in either DP or DM - TEST_ASSERT(RG_Matrix_Synced(A)); - - // matrix should be empty - M_EMPTY(); - DP_EMPTY(); - DM_EMPTY(); - RG_Matrix_nvals(&nvals, A); - TEST_ASSERT(nvals == 0); - - RG_Matrix_free(&A); - TEST_ASSERT(A == NULL); -} - -// setting an empty entry -// M[i,j] = 1 -void test_RGMatrix_simple_set() { - GrB_Type t = GrB_UINT64; - RG_Matrix A = NULL; - GrB_Matrix M = NULL; - GrB_Matrix DP = NULL; - GrB_Matrix DM = NULL; - GrB_Info info = GrB_SUCCESS; - GrB_Index nvals = 0; - GrB_Index nrows = 100; - GrB_Index ncols = 100; - GrB_Index i = 0; - GrB_Index j = 1; - uint64_t x = 1; - - info = RG_Matrix_new(&A, t, nrows, ncols); - TEST_ASSERT(info == GrB_SUCCESS); - - //-------------------------------------------------------------------------- - // set element at position i,j - //-------------------------------------------------------------------------- - - info = RG_Matrix_setElement_UINT64(A, x, i, j); - TEST_ASSERT(info == GrB_SUCCESS); - - // make sure element at position i,j exists - info = RG_Matrix_extractElement_UINT64(&x, A, i, j); - TEST_ASSERT(info == GrB_SUCCESS); - TEST_ASSERT(x == 1); - - // matrix should contain a single element - RG_Matrix_nvals(&nvals, A); - TEST_ASSERT(nvals == 1); - - // matrix should be mark as dirty - TEST_ASSERT(RG_Matrix_isDirty(A)); - - // get internal matrices - M = RG_MATRIX_M(A); - DP = RG_MATRIX_DELTA_PLUS(A); - DM = RG_MATRIX_DELTA_MINUS(A); - - //-------------------------------------------------------------------------- - // validations - //-------------------------------------------------------------------------- - - // M should be empty - M_EMPTY(); - - // DM should be empty - DM_EMPTY(); - - // DP should contain a single element - DP_NOT_EMPTY(); - - //-------------------------------------------------------------------------- - // set already existing entry - //-------------------------------------------------------------------------- - - // flush matrix - RG_Matrix_wait(A, false); - - // introduce existing entry - info = RG_Matrix_setElement_UINT64(A, x, i, j); - TEST_ASSERT(info == GrB_SUCCESS); - - //-------------------------------------------------------------------------- - // validations - //-------------------------------------------------------------------------- - - // M should be empty - M_EMPTY(); - - // DM should be empty - DM_EMPTY(); - - // DP should contain a multi-value entry - DP_NOT_EMPTY(); - - // clean up - RG_Matrix_free(&A); - TEST_ASSERT(A == NULL); -} - -// multiple delete scenarios -void test_RGMatrix_del() { - GrB_Type t = GrB_UINT64; - RG_Matrix A = NULL; - GrB_Matrix M = NULL; - GrB_Matrix DP = NULL; - GrB_Matrix DM = NULL; - GrB_Info info = GrB_SUCCESS; - GrB_Index nvals = 0; - GrB_Index nrows = 100; - GrB_Index ncols = 100; - GrB_Index i = 0; - GrB_Index j = 1; - uint64_t x = 1; - - info = RG_Matrix_new(&A, t, nrows, ncols); - TEST_ASSERT(info == GrB_SUCCESS); - - // get internal matrices - M = RG_MATRIX_M(A); - DP = RG_MATRIX_DELTA_PLUS(A); - DM = RG_MATRIX_DELTA_MINUS(A); - - //-------------------------------------------------------------------------- - // remove none existing entry - //-------------------------------------------------------------------------- - - info = RG_Matrix_removeElement_UINT64(A, i, j); - TEST_ASSERT(info == GrB_NO_VALUE); - - // matrix should not contain any entries in either DP or DM - TEST_ASSERT(RG_Matrix_Synced(A)); - - //-------------------------------------------------------------------------- - // remove none flushed addition - //-------------------------------------------------------------------------- - - // set element at position i,j - info = RG_Matrix_setElement_UINT64(A, x, i, j); - TEST_ASSERT(info == GrB_SUCCESS); - - // remove element at position i,j - info = RG_Matrix_removeElement_UINT64(A, i, j); - TEST_ASSERT(info == GrB_SUCCESS); - - // matrix should be mark as dirty - TEST_ASSERT(RG_Matrix_isDirty(A)); - - //-------------------------------------------------------------------------- - // validations - //-------------------------------------------------------------------------- - - // A should be empty - RG_Matrix_nvals(&nvals, A); - TEST_ASSERT(nvals == 0); - - // M should be empty - M_EMPTY(); - - // DM should be empty - DM_EMPTY(); - - // DP should be empty - DP_EMPTY(); - - //-------------------------------------------------------------------------- - // remove flushed addition - //-------------------------------------------------------------------------- - - // set element at position i,j - info = RG_Matrix_setElement_UINT64(A, x, i, j); - TEST_ASSERT(info == GrB_SUCCESS); - - // force sync - // entry should migrated from 'delta-plus' to 'M' - info = RG_Matrix_wait(A, true); - - // remove element at position i,j - info = RG_Matrix_removeElement_UINT64(A, i, j); - TEST_ASSERT(info == GrB_SUCCESS); - - //-------------------------------------------------------------------------- - // validations - //-------------------------------------------------------------------------- - - // A should be empty - RG_Matrix_nvals(&nvals, A); - TEST_ASSERT(nvals == 0); - - // M should contain a single element - M_NOT_EMPTY(); - - // DM should contain a single element - DM_NOT_EMPTY(); - - // DP should be empty - DP_EMPTY(); - - //-------------------------------------------------------------------------- - // flush - //-------------------------------------------------------------------------- - - info = RG_Matrix_wait(A, true); - TEST_ASSERT(info == GrB_SUCCESS); - - //-------------------------------------------------------------------------- - // validations - //-------------------------------------------------------------------------- - - // entry should be removed from both 'delta-minus' and 'M' - // A should be empty - RG_Matrix_nvals(&nvals, A); - TEST_ASSERT(nvals == 0); - - // M should be empty - M_EMPTY(); - - // DM should be empty - DM_EMPTY(); - - // DP should be empty - DP_EMPTY(); - - //-------------------------------------------------------------------------- - - // commit an entry M[i,j] = 1 - // delete entry del DM[i,j] = true - // re-introduce entry DM[i,j] = 0, M[i,j] = 2 - // delete entry DM[i,j] = true - // commit - // M[i,j] = 0, DP[i,j] = 0, DM[i,j] = 0 - - //-------------------------------------------------------------------------- - // commit an entry M[i,j] = 1 - //-------------------------------------------------------------------------- - - // set element at position i,j - info = RG_Matrix_setElement_UINT64(A, 1, i, j); - TEST_ASSERT(info == GrB_SUCCESS); - - // force sync - info = RG_Matrix_wait(A, true); - - // M should contain a single element - M_NOT_EMPTY(); - DP_EMPTY(); - DM_EMPTY(); - - //-------------------------------------------------------------------------- - // delete entry del DM[i,j] = true - //-------------------------------------------------------------------------- - - // remove element at position i,j - info = RG_Matrix_removeElement_UINT64(A, i, j); - TEST_ASSERT(info == GrB_SUCCESS); - - M_NOT_EMPTY(); - DP_EMPTY(); - DM_NOT_EMPTY(); - - //-------------------------------------------------------------------------- - // introduce an entry DP[i,j] = 2 - //-------------------------------------------------------------------------- - - // set element at position i,j - info = RG_Matrix_setElement_UINT64(A, 2, i, j); - TEST_ASSERT(info == GrB_SUCCESS); - - // M should contain a single element - M_NOT_EMPTY(); - DP_EMPTY(); - DM_EMPTY(); - - //-------------------------------------------------------------------------- - // commit - //-------------------------------------------------------------------------- - - // force sync - info = RG_Matrix_wait(A, true); - - //-------------------------------------------------------------------------- - // M[i,j] = 2, DP[i,j] = 0, DM[i,j] = 0 - //-------------------------------------------------------------------------- - - info = RG_Matrix_extractElement_UINT64(&x, A, i, j); - TEST_ASSERT(info == GrB_SUCCESS); - TEST_ASSERT(2 == x); - - M_NOT_EMPTY(); - DP_EMPTY(); - DM_EMPTY(); - - //-------------------------------------------------------------------------- - // clean up - //-------------------------------------------------------------------------- - - RG_Matrix_free(&A); - TEST_ASSERT(A == NULL); -} - -// multiple delete entry scenarios -void test_RGMatrix_del_entry() { - GrB_Type t = GrB_UINT64; - RG_Matrix A = NULL; - GrB_Matrix M = NULL; - GrB_Matrix DP = NULL; - GrB_Matrix DM = NULL; - GrB_Info info = GrB_SUCCESS; - GrB_Index nvals = 0; - GrB_Index nrows = 100; - GrB_Index ncols = 100; - GrB_Index i = 0; - GrB_Index j = 1; - uint64_t x = 1; - bool entry_deleted = false; - - info = RG_Matrix_new(&A, t, nrows, ncols); - TEST_ASSERT(info == GrB_SUCCESS); - - // get internal matrices - M = RG_MATRIX_M(A); - DP = RG_MATRIX_DELTA_PLUS(A); - DM = RG_MATRIX_DELTA_MINUS(A); - - //-------------------------------------------------------------------------- - // remove none existing entry - //-------------------------------------------------------------------------- - - info = RG_Matrix_removeEntry_UINT64(A, i, j, x, &entry_deleted); - TEST_ASSERT(info == GrB_NO_VALUE); - - // matrix should not contain any entries in either DP or DM - TEST_ASSERT(RG_Matrix_Synced(A)); - - //-------------------------------------------------------------------------- - // remove none flushed addition - //-------------------------------------------------------------------------- - - // set element at position i,j - info = RG_Matrix_setElement_UINT64(A, x, i, j); - TEST_ASSERT(info == GrB_SUCCESS); - - // remove element at position i,j - info = RG_Matrix_removeEntry_UINT64(A, i, j, x, &entry_deleted); - TEST_ASSERT(info == GrB_SUCCESS); - - // matrix should be mark as dirty - TEST_ASSERT(RG_Matrix_isDirty(A)); - - //-------------------------------------------------------------------------- - // validations - //-------------------------------------------------------------------------- - - // A should be empty - RG_Matrix_nvals(&nvals, A); - TEST_ASSERT(nvals == 0); - - // M should be empty - M_EMPTY(); - - // DM should be empty - DM_EMPTY(); - - // DP should be empty - DP_EMPTY(); - - //-------------------------------------------------------------------------- - // remove flushed addition - //-------------------------------------------------------------------------- - - // set element at position i,j - info = RG_Matrix_setElement_UINT64(A, x, i, j); - TEST_ASSERT(info == GrB_SUCCESS); - - // force sync - // entry should migrated from 'delta-plus' to 'M' - info = RG_Matrix_wait(A, true); - - // remove element at position i,j - info = RG_Matrix_removeEntry_UINT64(A, i, j, x, &entry_deleted); - TEST_ASSERT(info == GrB_SUCCESS); - - //-------------------------------------------------------------------------- - // validations - //-------------------------------------------------------------------------- - - // A should be empty - RG_Matrix_nvals(&nvals, A); - TEST_ASSERT(nvals == 0); - - // M should contain a single element - M_NOT_EMPTY(); - - // DM should contain a single element - DM_NOT_EMPTY(); - - // DP should be empty - DP_EMPTY(); - - //-------------------------------------------------------------------------- - // flush - //-------------------------------------------------------------------------- - - info = RG_Matrix_wait(A, true); - TEST_ASSERT(info == GrB_SUCCESS); - - //-------------------------------------------------------------------------- - // validations - //-------------------------------------------------------------------------- - - // entry should be removed from both 'delta-minus' and 'M' - // A should be empty - RG_Matrix_nvals(&nvals, A); - TEST_ASSERT(nvals == 0); - - // M should be empty - M_EMPTY(); - - // DM should be empty - DM_EMPTY(); - - // DP should be empty - DP_EMPTY(); - - //-------------------------------------------------------------------------- - - // commit an entry M[i,j] = 1 - // delete entry del DM[i,j] = true - // re-introduce entry DM[i,j] = 0, M[i,j] = 2 - // delete entry DM[i,j] = true - // commit - // M[i,j] = 0, DP[i,j] = 0, DM[i,j] = 0 - - //-------------------------------------------------------------------------- - // commit an entry M[i,j] = 1 - //-------------------------------------------------------------------------- - - // set element at position i,j - info = RG_Matrix_setElement_UINT64(A, 1, i, j); - TEST_ASSERT(info == GrB_SUCCESS); - - // force sync - info = RG_Matrix_wait(A, true); - - // M should contain a single element - M_NOT_EMPTY(); - DP_EMPTY(); - DM_EMPTY(); - - //-------------------------------------------------------------------------- - // delete entry del DM[i,j] = true - //-------------------------------------------------------------------------- - - // remove element at position i,j - info = RG_Matrix_removeEntry_UINT64(A, i, j, x, &entry_deleted); - TEST_ASSERT(info == GrB_SUCCESS); - - M_NOT_EMPTY(); - DP_EMPTY(); - DM_NOT_EMPTY(); - - //-------------------------------------------------------------------------- - // introduce an entry DP[i,j] = 2 - //-------------------------------------------------------------------------- - - // set element at position i,j - info = RG_Matrix_setElement_UINT64(A, 2, i, j); - TEST_ASSERT(info == GrB_SUCCESS); - - // M should contain a single element - M_NOT_EMPTY(); - DP_EMPTY(); - DM_EMPTY(); - - //-------------------------------------------------------------------------- - // commit - //-------------------------------------------------------------------------- - - // force sync - info = RG_Matrix_wait(A, true); - - //-------------------------------------------------------------------------- - // M[i,j] = 2, DP[i,j] = 0, DM[i,j] = 0 - //-------------------------------------------------------------------------- - - M_NOT_EMPTY(); - DP_EMPTY(); - DM_EMPTY(); - - //-------------------------------------------------------------------------- - // clean up - //-------------------------------------------------------------------------- - - RG_Matrix_free(&A); - TEST_ASSERT(A == NULL); -} - -void test_RGMatrix_set() { - GrB_Type t = GrB_BOOL; - RG_Matrix A = NULL; - GrB_Matrix M = NULL; - GrB_Matrix DP = NULL; - GrB_Matrix DM = NULL; - GrB_Info info = GrB_SUCCESS; - GrB_Index nvals = 0; - GrB_Index nrows = 100; - GrB_Index ncols = 100; - GrB_Index i = 0; - GrB_Index j = 1; - - info = RG_Matrix_new(&A, t, nrows, ncols); - TEST_ASSERT(info == GrB_SUCCESS); - - // get internal matrices - M = RG_MATRIX_M(A); - DP = RG_MATRIX_DELTA_PLUS(A); - DM = RG_MATRIX_DELTA_MINUS(A); - - //-------------------------------------------------------------------------- - // Set element that marked for deletion - //-------------------------------------------------------------------------- - - // set element at position i,j - info = RG_Matrix_setElement_BOOL(A, i, j); - TEST_ASSERT(info == GrB_SUCCESS); - - // force sync - // entry should migrated from 'delta-plus' to 'M' - RG_Matrix_wait(A, true); - - // set element at position i,j - info = RG_Matrix_removeElement_BOOL(A, i, j); - TEST_ASSERT(info == GrB_SUCCESS); - - // set element at position i,j - info = RG_Matrix_setElement_BOOL(A, i, j); - TEST_ASSERT(info == GrB_SUCCESS); - - //-------------------------------------------------------------------------- - // validations - //-------------------------------------------------------------------------- - - // A should be empty - RG_Matrix_nvals(&nvals, A); - TEST_ASSERT(nvals == 1); - - // M should contain a single element - M_NOT_EMPTY(); - - // DM should contain a single element - DM_EMPTY(); - - // DP should be empty - DP_EMPTY(); - - - //-------------------------------------------------------------------------- - // clean up - //-------------------------------------------------------------------------- - - RG_Matrix_free(&A); - TEST_ASSERT(A == NULL); -} - -// flush simple addition -void test_RGMatrix_flus() { - GrB_Type t = GrB_BOOL; - RG_Matrix A = NULL; - GrB_Matrix M = NULL; - GrB_Matrix DP = NULL; - GrB_Matrix DM = NULL; - GrB_Info info = GrB_SUCCESS; - GrB_Index nvals = 0; - GrB_Index nrows = 100; - GrB_Index ncols = 100; - GrB_Index i = 0; - GrB_Index j = 1; - bool sync = false; - - info = RG_Matrix_new(&A, t, nrows, ncols); - TEST_ASSERT(info == GrB_SUCCESS); - - // set element at position i,j - info = RG_Matrix_setElement_BOOL(A, i, j); - TEST_ASSERT(info == GrB_SUCCESS); - - // get internal matrices - M = RG_MATRIX_M(A); - DP = RG_MATRIX_DELTA_PLUS(A); - DM = RG_MATRIX_DELTA_MINUS(A); - - //-------------------------------------------------------------------------- - // flush matrix, no sync - //-------------------------------------------------------------------------- - - // wait, don't force sync - sync = false; - RG_Matrix_wait(A, sync); - - // M should be empty - M_EMPTY(); - - // DM should be empty - DM_EMPTY(); - - // DP should contain a single element - DP_NOT_EMPTY(); - - //-------------------------------------------------------------------------- - // flush matrix, sync - //-------------------------------------------------------------------------- - - // wait, force sync - sync = true; - RG_Matrix_wait(A, sync); - - RG_Matrix_nvals(&nvals, A); - TEST_ASSERT(nvals == 1); - - // M should be empty - M_NOT_EMPTY(); - - // DM should be empty - DM_EMPTY(); - - // DP should contain a single element - DP_EMPTY(); - - // clean up - RG_Matrix_free(&A); - TEST_ASSERT(A == NULL); -} - -//------------------------------------------------------------------------------ -// transpose test -//------------------------------------------------------------------------------ - -// M[i,j] = x, M[i,j] = y -void test_GRMatrix_managed_transposed() { - GrB_Type t = GrB_UINT64; - RG_Matrix A = NULL; - RG_Matrix T = NULL; // A transposed - GrB_Matrix M = NULL; // primary internal matrix - GrB_Matrix DP = NULL; // delta plus - GrB_Matrix DM = NULL; // delta minus - GrB_Info info = GrB_SUCCESS; - GrB_Index nvals = 0; - GrB_Index nrows = 100; - GrB_Index ncols = 100; - GrB_Index i = 0; - GrB_Index j = 1; - uint64_t x = 0; // M[i,j] = x - bool b = false; - bool entry_deleted = false; - - //-------------------------------------------------------------------------- - // create RGMatrix - //-------------------------------------------------------------------------- - - info = RG_Matrix_new(&A, t, nrows, ncols); - TEST_ASSERT(info == GrB_SUCCESS); - - // make sure transposed was created - T = RG_Matrix_getTranspose(A); - TEST_ASSERT(T != A); - TEST_ASSERT(T != NULL); - - // get internal matrices - M = RG_MATRIX_M(T); - DP = RG_MATRIX_DELTA_PLUS(T); - DM = RG_MATRIX_DELTA_MINUS(T); - - //-------------------------------------------------------------------------- - // set element at position i,j - //-------------------------------------------------------------------------- - - info = RG_Matrix_setElement_UINT64(A, x, i, j); - TEST_ASSERT(info == GrB_SUCCESS); - - // make sure element at position j,i exists - info = RG_Matrix_extractElement_BOOL(&b, T, j, i); - TEST_ASSERT(info == GrB_SUCCESS); - TEST_ASSERT(true == b); - - // matrix should contain a single element - RG_Matrix_nvals(&nvals, T); - TEST_ASSERT(nvals == 1); - - // matrix should be mark as dirty - TEST_ASSERT(RG_Matrix_isDirty(T)); - - //-------------------------------------------------------------------------- - // validations - //-------------------------------------------------------------------------- - - // TM should be empty - M_EMPTY(); - - // TDM should be empty - DM_EMPTY(); - - // TDP should contain a single element - DP_NOT_EMPTY(); - - //-------------------------------------------------------------------------- - // flush matrix - //-------------------------------------------------------------------------- - - RG_Matrix_wait(A, true); - - // flushing 'A' should flush 'T' aswell - - // TM should contain a single element - M_NOT_EMPTY(); - - // TDM should be empty - DM_EMPTY(); - - // TDP should be empty - DP_EMPTY(); - - //-------------------------------------------------------------------------- - // delete element at position i,j - //-------------------------------------------------------------------------- - - info = RG_Matrix_removeElement_UINT64(A, i, j); - TEST_ASSERT(info == GrB_SUCCESS); - - // matrix should be mark as dirty - TEST_ASSERT(RG_Matrix_isDirty(T)); - - //-------------------------------------------------------------------------- - // validations - //-------------------------------------------------------------------------- - - // TM should contain a single element - M_NOT_EMPTY(); - - // TDM should contain a single element - DM_NOT_EMPTY(); - - // TDP should be empty - DP_EMPTY(); - - //-------------------------------------------------------------------------- - // flush matrix - //-------------------------------------------------------------------------- - - // flushing 'A' should flush 'T' aswell - - RG_Matrix_wait(A, true); - - // TM should be empty - M_EMPTY(); - - // TDM should be empty - DM_EMPTY(); - - // TDP should be empty - DP_EMPTY(); - - //-------------------------------------------------------------------------- - // delete entry at position i,j - //-------------------------------------------------------------------------- - - info = RG_Matrix_setElement_UINT64(A, x, i, j); - TEST_ASSERT(info == GrB_SUCCESS); - info = RG_Matrix_setElement_UINT64(A, x + 1, i, j); - TEST_ASSERT(info == GrB_SUCCESS); - - info = RG_Matrix_removeEntry_UINT64(A, i, j, x, &entry_deleted); - - // make sure element at position j,i exists - info = RG_Matrix_extractElement_BOOL(&b, T, j, i); - TEST_ASSERT(info == GrB_SUCCESS); - TEST_ASSERT(true == b); - - info = RG_Matrix_removeEntry_UINT64(A, i, j, x + 1, &entry_deleted); - info = RG_Matrix_extractElement_BOOL(&b, T, j, i); - TEST_ASSERT(info == GrB_NO_VALUE); - - //-------------------------------------------------------------------------- - // delete flushed entry at position i,j - //-------------------------------------------------------------------------- - - info = RG_Matrix_setElement_UINT64(A, x, i, j); - TEST_ASSERT(info == GrB_SUCCESS); - info = RG_Matrix_setElement_UINT64(A, x + 1, i, j); - TEST_ASSERT(info == GrB_SUCCESS); - - RG_Matrix_wait(A, true); - - info = RG_Matrix_removeEntry_UINT64(A, i, j, x, &entry_deleted); - - // make sure element at position j,i exists - info = RG_Matrix_extractElement_BOOL(&b, T, j, i); - TEST_ASSERT(info == GrB_SUCCESS); - TEST_ASSERT(true == b); - - info = RG_Matrix_removeEntry_UINT64(A, i, j, x + 1, &entry_deleted); - info = RG_Matrix_extractElement_BOOL(&b, T, j, i); - TEST_ASSERT(info == GrB_NO_VALUE); - - //-------------------------------------------------------------------------- - // revive deleted entry at position i,j - //-------------------------------------------------------------------------- - - info = RG_Matrix_setElement_UINT64(A, x, i, j); - TEST_ASSERT(info == GrB_SUCCESS); - - RG_Matrix_wait(A, true); - - info = RG_Matrix_removeElement_UINT64(A, i, j); - - info = RG_Matrix_setElement_UINT64(A, x, i, j); - TEST_ASSERT(info == GrB_SUCCESS); - - // make sure element at position j,i exists - info = RG_Matrix_extractElement_BOOL(&b, T, j, i); - TEST_ASSERT(info == GrB_SUCCESS); - TEST_ASSERT(true == b); - - // clean up - RG_Matrix_free(&A); - TEST_ASSERT(A == NULL); -} - -//------------------------------------------------------------------------------ -// fuzzy test compare RG_Matrix to GrB_Matrix -//------------------------------------------------------------------------------ - -void test_RGMatrix_fuzzy() { - GrB_Type t = GrB_BOOL; - RG_Matrix A = NULL; - RG_Matrix T = NULL; // A transposed - GrB_Matrix M = NULL; // primary internal matrix - GrB_Matrix MT = NULL; - GrB_Matrix N = NULL; - GrB_Matrix NT = NULL; - GrB_Info info = GrB_SUCCESS; - GrB_Index nrows = 100; - GrB_Index ncols = 100; - GrB_Index i = 0; - GrB_Index j = 1; - GrB_Index* II = NULL; - GrB_Index* J = NULL; - uint32_t operations = 10000; - - //-------------------------------------------------------------------------- - // create RGMatrix - //-------------------------------------------------------------------------- - - srand(time(0)); - - II = (GrB_Index*) malloc(sizeof(GrB_Index) * operations); - J = (GrB_Index*) malloc(sizeof(GrB_Index) * operations); - - info = RG_Matrix_new(&A, t, nrows, ncols); - info = RG_Matrix_new(&A->transposed, t, ncols, nrows); - TEST_ASSERT(info == GrB_SUCCESS); - - // make sure transposed was created - T = RG_Matrix_getTranspose(A); - TEST_ASSERT(T != A); - TEST_ASSERT(T != NULL); - - // get internal matrices - M = RG_MATRIX_M(A); - MT = RG_MATRIX_M(T); - - info = GrB_Matrix_new(&N, t, nrows, ncols); - TEST_ASSERT(info == GrB_SUCCESS); - - info = GrB_Matrix_new(&NT, t, ncols, nrows); - TEST_ASSERT(info == GrB_SUCCESS); - - uint additions = 0; - for (size_t index = 0; index < operations; index++) - { - if (index < 10 || rand() % 100 > 20) - { - i = rand() % nrows; - j = rand() % ncols; - - //------------------------------------------------------------------ - // set element at position i,j - //------------------------------------------------------------------ - - info = RG_Matrix_setElement_BOOL(A, i, j); - TEST_ASSERT(info == GrB_SUCCESS); - - info = GrB_Matrix_setElement_BOOL(N, true, i, j); - TEST_ASSERT(info == GrB_SUCCESS); - - II[additions] = i; - J[additions] = j; - additions++; - } - else - { - uint32_t delete_pos = rand() % additions; - i = II[delete_pos]; - j = J[delete_pos]; - - //------------------------------------------------------------------ - // delete element at position i,j - //------------------------------------------------------------------ - - RG_Matrix_removeElement_BOOL(A, i, j); - - GrB_Matrix_removeElement(N, i, j); - } - } - - //-------------------------------------------------------------------------- - // flush matrix - //-------------------------------------------------------------------------- - - RG_Matrix_wait(A, true); - - //-------------------------------------------------------------------------- - // validation - //-------------------------------------------------------------------------- - - info = GrB_transpose(NT, NULL, NULL, N, NULL); - TEST_ASSERT(info == GrB_SUCCESS); - - ASSERT_GrB_Matrices_EQ(M, N); - ASSERT_GrB_Matrices_EQ(MT, NT); - - //-------------------------------------------------------------------------- - // clean up - //-------------------------------------------------------------------------- - - RG_Matrix_free(&A); - TEST_ASSERT(A == NULL); - - info = GrB_Matrix_free(&N); - TEST_ASSERT(info == GrB_SUCCESS); - - info = GrB_Matrix_free(&NT); - TEST_ASSERT(info == GrB_SUCCESS); - - free(II); - free(J); -} - -// test exporting RG_Matrix to GrB_Matrix when there are no pending changes -// by exporting the matrix after flushing -void test_RGMatrix_export_no_changes() { - GrB_Type t = GrB_BOOL; - RG_Matrix A = NULL; - GrB_Matrix M = NULL; - GrB_Matrix N = NULL; // exported matrix - GrB_Info info = GrB_SUCCESS; - GrB_Index i = 0; - GrB_Index j = 1; - GrB_Index nrows = 100; - GrB_Index ncols = 100; - bool sync = false; - - info = RG_Matrix_new(&A, t, nrows, ncols); - TEST_ASSERT(info == GrB_SUCCESS); - - // get internal matrices - M = RG_MATRIX_M(A); - - //-------------------------------------------------------------------------- - // export empty matrix - //-------------------------------------------------------------------------- - - info = RG_Matrix_export(&N, A); - TEST_ASSERT(info == GrB_SUCCESS); - - //-------------------------------------------------------------------------- - // validation - //-------------------------------------------------------------------------- - - ASSERT_GrB_Matrices_EQ(M, N); - GrB_Matrix_free(&N); - - //-------------------------------------------------------------------------- - // export none empty matrix - //-------------------------------------------------------------------------- - - // set element at position i,j - info = RG_Matrix_setElement_BOOL(A, i, j); - TEST_ASSERT(info == GrB_SUCCESS); - - //-------------------------------------------------------------------------- - // flush matrix, sync - //-------------------------------------------------------------------------- - - // wait, force sync - sync = true; - RG_Matrix_wait(A, sync); - - //-------------------------------------------------------------------------- - // validation - //-------------------------------------------------------------------------- - - info = RG_Matrix_export(&N, A); - TEST_ASSERT(info == GrB_SUCCESS); - - ASSERT_GrB_Matrices_EQ(M, N); - - //-------------------------------------------------------------------------- - // clean up - //-------------------------------------------------------------------------- - - RG_Matrix_free(&A); - GrB_Matrix_free(&N); -} - -// test exporting RG_Matrix to GrB_Matrix when there are pending changes -// by exporting the matrix after making changes -// then flush the matrix and compare the internal matrix to the exported matrix -void test_RGMatrix_export_pending_changes() { - GrB_Type t = GrB_BOOL; - RG_Matrix A = NULL; - GrB_Matrix M = NULL; - GrB_Matrix N = NULL; // exported matrix - GrB_Info info = GrB_SUCCESS; - GrB_Index nrows = 100; - GrB_Index ncols = 100; - bool sync = false; - - info = RG_Matrix_new(&A, t, nrows, ncols); - TEST_ASSERT(info == GrB_SUCCESS); - - // get internal matrices - M = RG_MATRIX_M(A); - - // set elements - info = RG_Matrix_setElement_BOOL(A, 0, 0); - TEST_ASSERT(info == GrB_SUCCESS); - info = RG_Matrix_setElement_BOOL(A, 1, 1); - TEST_ASSERT(info == GrB_SUCCESS); - - //-------------------------------------------------------------------------- - // flush matrix, sync - //-------------------------------------------------------------------------- - - // wait, force sync - sync = true; - RG_Matrix_wait(A, sync); - - //-------------------------------------------------------------------------- - // set pending changes - //-------------------------------------------------------------------------- - - // remove element at position 0,0 - info = RG_Matrix_removeElement_BOOL(A, 0, 0); - TEST_ASSERT(info == GrB_SUCCESS); - - // set element at position 2,2 - info = RG_Matrix_setElement_BOOL(A, 2, 2); - TEST_ASSERT(info == GrB_SUCCESS); - - //-------------------------------------------------------------------------- - // export matrix - //-------------------------------------------------------------------------- - - info = RG_Matrix_export(&N, A); - TEST_ASSERT(info == GrB_SUCCESS); - - //-------------------------------------------------------------------------- - // flush matrix, sync - //-------------------------------------------------------------------------- - - // wait, force sync - sync = true; - RG_Matrix_wait(A, sync); - - //-------------------------------------------------------------------------- - // validation - //-------------------------------------------------------------------------- - - ASSERT_GrB_Matrices_EQ(M, N); - - // clean up - GrB_Matrix_free(&N); - RG_Matrix_free(&A); - TEST_ASSERT(A == NULL); -} - -void test_RGMatrix_copy() { - GrB_Type t = GrB_BOOL; - RG_Matrix A = NULL; - RG_Matrix B = NULL; - GrB_Matrix A_M = NULL; - GrB_Matrix B_M = NULL; - GrB_Matrix A_DP = NULL; - GrB_Matrix B_DP = NULL; - GrB_Matrix A_DM = NULL; - GrB_Matrix B_DM = NULL; - GrB_Info info = GrB_SUCCESS; - GrB_Index nrows = 100; - GrB_Index ncols = 100; - bool sync = false; - - info = RG_Matrix_new(&A, t, nrows, ncols); - TEST_ASSERT(info == GrB_SUCCESS); - - info = RG_Matrix_new(&B, t, nrows, ncols); - TEST_ASSERT(info == GrB_SUCCESS); - - // set elements - info = RG_Matrix_setElement_BOOL(A, 0, 0); - TEST_ASSERT(info == GrB_SUCCESS); - info = RG_Matrix_setElement_BOOL(A, 1, 1); - TEST_ASSERT(info == GrB_SUCCESS); - - //-------------------------------------------------------------------------- - // flush matrix, sync - //-------------------------------------------------------------------------- - - // wait, force sync - sync = true; - RG_Matrix_wait(A, sync); - - //-------------------------------------------------------------------------- - // set pending changes - //-------------------------------------------------------------------------- - - // remove element at position 0,0 - info = RG_Matrix_removeElement_BOOL(A, 0, 0); - TEST_ASSERT(info == GrB_SUCCESS); - - // set element at position 2,2 - info = RG_Matrix_setElement_BOOL(A, 2, 2); - TEST_ASSERT(info == GrB_SUCCESS); - - //-------------------------------------------------------------------------- - // copy matrix - //-------------------------------------------------------------------------- - - info = RG_Matrix_copy(B, A); - TEST_ASSERT(info == GrB_SUCCESS); - - //-------------------------------------------------------------------------- - // validation - //-------------------------------------------------------------------------- - - A_M = RG_MATRIX_M(A); - B_M = RG_MATRIX_M(B); - A_DP = RG_MATRIX_DELTA_PLUS(A); - B_DP = RG_MATRIX_DELTA_PLUS(B); - A_DM = RG_MATRIX_DELTA_MINUS(A); - B_DM = RG_MATRIX_DELTA_MINUS(B); - - ASSERT_GrB_Matrices_EQ(A_M, B_M); - ASSERT_GrB_Matrices_EQ(A_DP, B_DP); - ASSERT_GrB_Matrices_EQ(A_DM, B_DM); - - // clean up - RG_Matrix_free(&A); - TEST_ASSERT(A == NULL); - RG_Matrix_free(&B); - TEST_ASSERT(B == NULL); -} - -void test_RGMatrix_mxm() { - GrB_Type t = GrB_BOOL; - RG_Matrix A = NULL; - RG_Matrix B = NULL; - RG_Matrix C = NULL; - RG_Matrix D = NULL; - GrB_Matrix C_M = NULL; - GrB_Matrix D_M = NULL; - GrB_Info info = GrB_SUCCESS; - GrB_Index nrows = 100; - GrB_Index ncols = 100; - bool sync = false; - - info = RG_Matrix_new(&A, t, nrows, ncols); - TEST_ASSERT(info == GrB_SUCCESS); - - info = RG_Matrix_new(&B, t, nrows, ncols); - TEST_ASSERT(info == GrB_SUCCESS); - - info = RG_Matrix_new(&C, t, nrows, ncols); - TEST_ASSERT(info == GrB_SUCCESS); - - info = RG_Matrix_new(&D, t, nrows, ncols); - TEST_ASSERT(info == GrB_SUCCESS); - - // set elements - info = RG_Matrix_setElement_BOOL(A, 0, 1); - TEST_ASSERT(info == GrB_SUCCESS); - info = RG_Matrix_setElement_BOOL(A, 2, 3); - TEST_ASSERT(info == GrB_SUCCESS); - info = RG_Matrix_setElement_BOOL(B, 1, 2); - TEST_ASSERT(info == GrB_SUCCESS); - info = RG_Matrix_setElement_BOOL(B, 3, 4); - TEST_ASSERT(info == GrB_SUCCESS); - - //-------------------------------------------------------------------------- - // flush matrix, sync - //-------------------------------------------------------------------------- - - // wait, force sync - sync = true; - RG_Matrix_wait(A, sync); - RG_Matrix_wait(B, sync); - - //-------------------------------------------------------------------------- - // set pending changes - //-------------------------------------------------------------------------- - - // remove element at position 0,0 - info = RG_Matrix_removeElement_BOOL(B, 1, 2); - TEST_ASSERT(info == GrB_SUCCESS); - - // set element at position 2,2 - info = RG_Matrix_setElement_BOOL(B, 1, 3); - TEST_ASSERT(info == GrB_SUCCESS); - - //-------------------------------------------------------------------------- - // mxm matrix - //-------------------------------------------------------------------------- - - info = RG_mxm(C, GxB_ANY_PAIR_BOOL, A, B); - TEST_ASSERT(info == GrB_SUCCESS); - - RG_Matrix_wait(B, sync); - - info = RG_mxm(D, GxB_ANY_PAIR_BOOL, A, B); - //-------------------------------------------------------------------------- - // validation - //-------------------------------------------------------------------------- - - C_M = RG_MATRIX_M(C); - D_M = RG_MATRIX_M(D); - - ASSERT_GrB_Matrices_EQ(C_M, D_M); - - // clean up - RG_Matrix_free(&A); - TEST_ASSERT(A == NULL); - RG_Matrix_free(&B); - TEST_ASSERT(B == NULL); - RG_Matrix_free(&C); - TEST_ASSERT(C == NULL); - RG_Matrix_free(&D); - TEST_ASSERT(C == NULL); -} - -void test_RGMatrix_resize() { - RG_Matrix A = NULL; - RG_Matrix T = NULL; - GrB_Info info = GrB_SUCCESS; - GrB_Type t = GrB_UINT64; - GrB_Index nrows = 10; - GrB_Index ncols = 20; - - info = RG_Matrix_new(&A, t, nrows, ncols); - T = RG_Matrix_getTranspose(A); - - GrB_Index A_nrows; - GrB_Index A_ncols; - GrB_Index T_nrows; - GrB_Index T_ncols; - - // verify A and T dimensions - RG_Matrix_nrows(&A_nrows, A); - TEST_ASSERT(info == GrB_SUCCESS); - RG_Matrix_ncols(&A_ncols, A); - TEST_ASSERT(info == GrB_SUCCESS); - - TEST_ASSERT(A_nrows == nrows); - TEST_ASSERT(A_ncols == ncols); - - RG_Matrix_nrows(&T_nrows, T); - TEST_ASSERT(info == GrB_SUCCESS); - RG_Matrix_ncols(&T_ncols, T); - TEST_ASSERT(info == GrB_SUCCESS); - - TEST_ASSERT(T_nrows == ncols); - TEST_ASSERT(T_ncols == nrows); - - // resize matrix, increase size by 2 - nrows *= 2; - ncols *= 2; - - info = RG_Matrix_resize(A, nrows, ncols); - TEST_ASSERT(info == GrB_SUCCESS); - - // verify A and T dimensions - RG_Matrix_nrows(&A_nrows, A); - TEST_ASSERT(info == GrB_SUCCESS); - RG_Matrix_ncols(&A_ncols, A); - TEST_ASSERT(info == GrB_SUCCESS); - - TEST_ASSERT(A_nrows == nrows); - TEST_ASSERT(A_ncols == ncols); - - RG_Matrix_nrows(&T_nrows, T); - TEST_ASSERT(info == GrB_SUCCESS); - RG_Matrix_ncols(&T_ncols, T); - TEST_ASSERT(info == GrB_SUCCESS); - - TEST_ASSERT(T_nrows == ncols); - TEST_ASSERT(T_ncols == nrows); - - // resize matrix decrease size by 2 - nrows /= 2; - ncols /= 2; - - info = RG_Matrix_resize(A, nrows, ncols); - TEST_ASSERT(info == GrB_SUCCESS); - - // verify A and T dimensions - RG_Matrix_nrows(&A_nrows, A); - TEST_ASSERT(info == GrB_SUCCESS); - RG_Matrix_ncols(&A_ncols, A); - TEST_ASSERT(info == GrB_SUCCESS); - - TEST_ASSERT(A_nrows == nrows); - TEST_ASSERT(A_ncols == ncols); - - RG_Matrix_nrows(&T_nrows, T); - TEST_ASSERT(info == GrB_SUCCESS); - RG_Matrix_ncols(&T_ncols, T); - TEST_ASSERT(info == GrB_SUCCESS); - - TEST_ASSERT(T_nrows == ncols); - TEST_ASSERT(T_ncols == nrows); - - RG_Matrix_free(&A); -} - -TEST_LIST = { - {"RGMatrix_new", test_RGMatrix_new}, - {"RGMatrix_simple_set", test_RGMatrix_simple_set}, - {"RGMatrix_del", test_RGMatrix_del}, - {"RGMatrix_del_entry", test_RGMatrix_del_entry}, - {"RGMatrix_set", test_RGMatrix_set}, - {"RGMatrix_flus", test_RGMatrix_flus}, - {"GRMatrix_managed_transposed", test_GRMatrix_managed_transposed}, - {"RGMatrix_fuzzy", test_RGMatrix_fuzzy}, - {"RGMatrix_export_no_changes", test_RGMatrix_export_no_changes}, - {"RGMatrix_export_pending_changes", test_RGMatrix_export_pending_changes}, - {"RGMatrix_copy", test_RGMatrix_copy}, - {"RGMatrix_mxm", test_RGMatrix_mxm}, - {"RGMatrix_resize", test_RGMatrix_resize}, - {NULL, NULL} -}; - -//#ifndef RG_DEBUG -//// test RGMatrix_pending -//// if RG_DEBUG is defined, each call to setElement will flush all 3 matrices -//// causing this test to fail -//TEST_F(RGMatrixTest, RGMatrix_pending) { -// RG_Matrix A = NULL; -// GrB_Info info = GrB_SUCCESS; -// GrB_Type t = GrB_UINT64; -// GrB_Index nrows = 100; -// GrB_Index ncols = 100; -// bool pending = false; -// -// info = RG_Matrix_new(&A, t, nrows, ncols); -// ASSERT_EQ(info, GrB_SUCCESS); -// -// // new RG_Matrix shouldn't have any pending operations -// info = RG_Matrix_pending(A, &pending); -// ASSERT_EQ(info, GrB_SUCCESS); -// ASSERT_FALSE(pending); -// -// // set element, modifies delta-plus -// info = RG_Matrix_setElement_UINT64(A, 2, 2, 2); -// ASSERT_EQ(info, GrB_SUCCESS); -// -// // expecting pending changes -// info = RG_Matrix_pending(A, &pending); -// ASSERT_EQ(info, GrB_SUCCESS); -// ASSERT_TRUE(pending); -// -// // flush pending changes on both DP and DM -// info = RG_Matrix_wait(A, false); -// ASSERT_EQ(info, GrB_SUCCESS); -// -// // expecting no pending changes -// info = RG_Matrix_pending(A, &pending); -// ASSERT_EQ(info, GrB_SUCCESS); -// ASSERT_FALSE(pending); -// -// // remove entry, DP entry is now a zombie -// info = RG_Matrix_removeElement_UINT64(A, 2, 2); -// ASSERT_EQ(info, GrB_SUCCESS); -// -// // expecting pending changes -// info = RG_Matrix_pending(A, &pending); -// ASSERT_EQ(info, GrB_SUCCESS); -// ASSERT_TRUE(pending); -// -// // flush pending changes on both DP and DM -// info = RG_Matrix_wait(A, false); -// ASSERT_EQ(info, GrB_SUCCESS); -// -// // expecting no pending changes -// info = RG_Matrix_pending(A, &pending); -// ASSERT_EQ(info, GrB_SUCCESS); -// ASSERT_FALSE(pending); -// -// // set element, modifies delta-plus -// info = RG_Matrix_setElement_UINT64(A, 2, 2, 2); -// ASSERT_EQ(info, GrB_SUCCESS); -// -// // flush pending changes on M, DM and DP -// info = RG_Matrix_wait(A, true); -// ASSERT_EQ(info, GrB_SUCCESS); -// -// // expecting no pending changes -// info = RG_Matrix_pending(A, &pending); -// ASSERT_EQ(info, GrB_SUCCESS); -// ASSERT_FALSE(pending); -// -// // clean up -// RG_Matrix_free(&A); -// ASSERT_TRUE(A == NULL); -//} -//#endif diff --git a/tests/unit/test_rg_matrix_iter.c b/tests/unit/test_rg_matrix_iter.c deleted file mode 100644 index d7af07bad..000000000 --- a/tests/unit/test_rg_matrix_iter.c +++ /dev/null @@ -1,393 +0,0 @@ -/* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ - -#include "src/util/rmalloc.h" -#include "src/configuration/config.h" -#include "src/graph/rg_matrix/rg_matrix.h" -#include "src/graph/rg_matrix/rg_matrix_iter.h" - -void setup() { - Alloc_Reset(); - - // initialize GraphBLAS - GrB_init(GrB_NONBLOCKING); - - // all matrices in CSR format - GxB_Global_Option_set(GxB_FORMAT, GxB_BY_ROW); - - // set delta matrix flush threshold - Config_Option_set(Config_DELTA_MAX_PENDING_CHANGES, "10000", NULL); -} - -void tearDown() { - GrB_finalize(); -} - -#define TEST_INIT setup(); -#define TEST_FINI tearDown(); -#include "acutest.h" - -// test RGMatrixTupleIter initialization -void test_RGMatrixTupleIter_attach() { - RG_Matrix A = NULL; - GrB_Type t = GrB_UINT64; - GrB_Info info = GrB_SUCCESS; - GrB_Index nrows = 100; - GrB_Index ncols = 100; - RG_MatrixTupleIter iter; - memset(&iter, 0, sizeof(RG_MatrixTupleIter)); - - info = RG_Matrix_new(&A, t, nrows, ncols); - TEST_ASSERT(info == GrB_SUCCESS); - - info = RG_MatrixTupleIter_attach(&iter, A); - TEST_ASSERT(RG_MatrixTupleIter_is_attached(&iter, A)); - - RG_MatrixTupleIter_detach(&iter); - TEST_ASSERT(iter.A == NULL); - - RG_Matrix_free(&A); - TEST_ASSERT(A == NULL); -} - -// test RGMatrixTupleIter iteration -void test_RGMatrixTupleIter_next() { - RG_Matrix A = NULL; - GrB_Type t = GrB_UINT64; - GrB_Info info = GrB_SUCCESS; - GrB_Index i = 1; - GrB_Index j = 2; - GrB_Index row = 0; - GrB_Index col = 0; - GrB_Index nrows = 100; - GrB_Index ncols = 100; - uint64_t val = 0; - bool sync = false; - RG_MatrixTupleIter iter; - memset(&iter, 0, sizeof(RG_MatrixTupleIter)); - - info = RG_Matrix_new(&A, t, nrows, ncols); - TEST_ASSERT(info == GrB_SUCCESS); - - // set element at position i,j - info = RG_Matrix_setElement_UINT64(A, 0, i, j); - TEST_ASSERT(info == GrB_SUCCESS); - - //-------------------------------------------------------------------------- - // flush matrix, sync - //-------------------------------------------------------------------------- - - // wait, force sync - sync = true; - RG_Matrix_wait(A, sync); - - //-------------------------------------------------------------------------- - // set pending changes - //-------------------------------------------------------------------------- - - // remove element at position i,j - info = RG_Matrix_removeElement_UINT64(A, i, j); - TEST_ASSERT(info == GrB_SUCCESS); - - // set element at position i+1,j+1 - info = RG_Matrix_setElement_UINT64(A, 1, i+1, j+1); - TEST_ASSERT(info == GrB_SUCCESS); - - info = RG_MatrixTupleIter_attach(&iter, A); - TEST_ASSERT(RG_MatrixTupleIter_is_attached(&iter, A)); - - info = RG_MatrixTupleIter_next_UINT64(&iter, &row, &col, &val); - TEST_ASSERT(info == GrB_SUCCESS); - - TEST_ASSERT(row == i+1); - TEST_ASSERT(col == j+1); - TEST_ASSERT(val == 1); - - info = RG_MatrixTupleIter_next_UINT64(&iter, &row, &col, &val); - - TEST_ASSERT(info == GxB_EXHAUSTED); - - RG_Matrix_free(&A); - TEST_ASSERT(A == NULL); - RG_MatrixTupleIter_detach(&iter); - TEST_ASSERT(iter.A == NULL); -} - -// test RGMatrixTupleIter iteration for sparse matrix -void test_RGMatrixTupleIter_next_sparse() { - RG_Matrix A = NULL; - GrB_Type t = GrB_UINT64; - GrB_Info info = GrB_SUCCESS; - GrB_Index row = 0; - GrB_Index col = 0; - GrB_Index nrows = 100; - GrB_Index ncols = 100; - uint64_t val = 0; - bool sync = false; - RG_MatrixTupleIter iter; - memset(&iter, 0, sizeof(RG_MatrixTupleIter)); - - info = RG_Matrix_new(&A, t, nrows, ncols); - TEST_ASSERT(info == GrB_SUCCESS); - - for (GrB_Index i = 25; i < 100; i++) { - for (GrB_Index j = 25; j < 100; j++) { - // set element at position i,j - info = RG_Matrix_setElement_UINT64(A, 0, i, j); - TEST_ASSERT(info == GrB_SUCCESS); - } - } - - //-------------------------------------------------------------------------- - // flush matrix, sync - //-------------------------------------------------------------------------- - - // wait, force sync - sync = true; - RG_Matrix_wait(A, sync); - - //-------------------------------------------------------------------------- - // check M is sparse - //-------------------------------------------------------------------------- - - GrB_Matrix M = RG_MATRIX_M(A); - - int sparsity; - GxB_Matrix_Option_get(M, GxB_SPARSITY_STATUS, &sparsity); - TEST_ASSERT(sparsity == GxB_SPARSE); - - //-------------------------------------------------------------------------- - // check iter start from correct row - //-------------------------------------------------------------------------- - - info = RG_MatrixTupleIter_attach(&iter, A); - TEST_ASSERT(RG_MatrixTupleIter_is_attached(&iter, A)); - - info = RG_MatrixTupleIter_next_UINT64(&iter, &row, &col, &val); - TEST_ASSERT(info == GrB_SUCCESS); - - TEST_ASSERT(row == 25); - TEST_ASSERT(col == 25); - TEST_ASSERT(val == 0); - - RG_Matrix_free(&A); - TEST_ASSERT(A == NULL); - RG_MatrixTupleIter_detach(&iter); - TEST_ASSERT(iter.A == NULL); -} - -// test RGMatrixTupleIter iteration -void test_RGMatrixTupleIter_reuse() { - RG_Matrix A = NULL; - RG_Matrix B = NULL; - GrB_Type t = GrB_UINT64; - GrB_Info info = GrB_SUCCESS; - GrB_Index i = 1; - GrB_Index j = 2; - GrB_Index row = 0; - GrB_Index col = 0; - GrB_Index nrows = 100; - GrB_Index ncols = 100; - uint64_t val = 0; - bool sync = false; - RG_MatrixTupleIter iter; - memset(&iter, 0, sizeof(RG_MatrixTupleIter)); - - info = RG_Matrix_new(&A, t, nrows, ncols); - TEST_ASSERT(info == GrB_SUCCESS); - - info = RG_Matrix_new(&B, t, nrows, ncols); - TEST_ASSERT(info == GrB_SUCCESS); - - // set element at position i,j - info = RG_Matrix_setElement_UINT64(A, 0, i, j); - TEST_ASSERT(info == GrB_SUCCESS); - - //-------------------------------------------------------------------------- - // flush matrix, sync - //-------------------------------------------------------------------------- - - // wait, force sync - sync = true; - RG_Matrix_wait(A, sync); - - info = RG_MatrixTupleIter_attach(&iter, B); - TEST_ASSERT(RG_MatrixTupleIter_is_attached(&iter, B)); - - info = RG_MatrixTupleIter_attach(&iter, A); - TEST_ASSERT(RG_MatrixTupleIter_is_attached(&iter, A)); - - info = RG_MatrixTupleIter_next_UINT64(&iter, &row, &col, &val); - - TEST_ASSERT(info == GrB_SUCCESS); - TEST_ASSERT(row == i); - TEST_ASSERT(col == j); - TEST_ASSERT(val == 0); - - info = RG_MatrixTupleIter_next_UINT64(&iter, &row, &col, &val); - - TEST_ASSERT(info == GxB_EXHAUSTED); - - RG_Matrix_free(&A); - TEST_ASSERT(A == NULL); - RG_Matrix_free(&B); - TEST_ASSERT(A == NULL); - RG_MatrixTupleIter_detach(&iter); - TEST_ASSERT(iter.A == NULL); -} - -// test RGMatrixTupleIter_iterate_row -void test_RGMatrixTupleIter_iterate_row() { - RG_Matrix A = NULL; - GrB_Type t = GrB_UINT64; - GrB_Info info = GrB_SUCCESS; - GrB_Index i = 1; - GrB_Index j = 2; - GrB_Index row = 0; - GrB_Index col = 0; - GrB_Index nrows = 100; - GrB_Index ncols = 100; - uint64_t val = 0; - bool sync = false; - RG_MatrixTupleIter iter; - memset(&iter, 0, sizeof(RG_MatrixTupleIter)); - - info = RG_Matrix_new(&A, t, nrows, ncols); - TEST_ASSERT(info == GrB_SUCCESS); - - // set element at position i,j - info = RG_Matrix_setElement_UINT64(A, 1, i, j); - TEST_ASSERT(info == GrB_SUCCESS); - - //-------------------------------------------------------------------------- - // flush matrix, sync - //-------------------------------------------------------------------------- - - // wait, force sync - sync = true; - RG_Matrix_wait(A, sync); - - //-------------------------------------------------------------------------- - // set pending changes - //-------------------------------------------------------------------------- - - // remove element at position i,j - info = RG_Matrix_removeElement_UINT64(A, i, j); - TEST_ASSERT(info == GrB_SUCCESS); - - // wait, DM can't have pendding changes - sync = false; - RG_Matrix_wait(A, sync); - - // set element at position i+1,j+1 - info = RG_Matrix_setElement_UINT64(A, 2, i+1, j+1); - TEST_ASSERT(info == GrB_SUCCESS); - - info = RG_MatrixTupleIter_attach(&iter, A); - TEST_ASSERT(iter.A == A); - - info = RG_MatrixTupleIter_iterate_row(&iter, i); - TEST_ASSERT(info == GrB_SUCCESS); - - info = RG_MatrixTupleIter_next_UINT64(&iter, &row, &col, &val); - TEST_ASSERT(info == GxB_EXHAUSTED); - - info = RG_MatrixTupleIter_reset(&iter); - TEST_ASSERT(info == GrB_SUCCESS); - - info = RG_MatrixTupleIter_iterate_row(&iter, i+1); - TEST_ASSERT(info == GrB_SUCCESS); - - info = RG_MatrixTupleIter_next_UINT64(&iter, &row, &col, &val); - - TEST_ASSERT(info == GrB_SUCCESS); - TEST_ASSERT(row == i+1); - TEST_ASSERT(col == j+1); - TEST_ASSERT(val == 2); - - info = RG_MatrixTupleIter_next_UINT64(&iter, &row, &col, &val); - TEST_ASSERT(info == GxB_EXHAUSTED); - - RG_Matrix_free(&A); - TEST_ASSERT(A == NULL); - RG_MatrixTupleIter_detach(&iter); - TEST_ASSERT(iter.A == NULL); -} - -// test RGMatrixTupleiIter_iterate_range -void test_RGMatrixTupleIter_iterate_range() { - RG_Matrix A = NULL; - GrB_Type t = GrB_UINT64; - GrB_Info info = GrB_SUCCESS; - GrB_Index i = 1; - GrB_Index j = 2; - GrB_Index row = 0; - GrB_Index col = 0; - GrB_Index nrows = 100; - GrB_Index ncols = 100; - uint64_t val = 0; - bool sync = false; - RG_MatrixTupleIter iter; - memset(&iter, 0, sizeof(RG_MatrixTupleIter)); - - info = RG_Matrix_new(&A, t, nrows, ncols); - TEST_ASSERT(info == GrB_SUCCESS); - - // set element at position i,j - info = RG_Matrix_setElement_UINT64(A, 0, i, j); - TEST_ASSERT(info == GrB_SUCCESS); - - //-------------------------------------------------------------------------- - // flush matrix, sync - //-------------------------------------------------------------------------- - - // wait, force sync - sync = true; - RG_Matrix_wait(A, sync); - - //-------------------------------------------------------------------------- - // set pending changes - //-------------------------------------------------------------------------- - - // remove element at position i,j - info = RG_Matrix_removeElement_UINT64(A, i, j); - TEST_ASSERT(info == GrB_SUCCESS); - - // set element at position i+1,j+1 - info = RG_Matrix_setElement_UINT64(A, 1, i+1, j+1); - TEST_ASSERT(info == GrB_SUCCESS); - - info = RG_MatrixTupleIter_attach(&iter, A); - TEST_ASSERT(RG_MatrixTupleIter_is_attached(&iter, A)); - - info = RG_MatrixTupleIter_iterate_range(&iter, i+1, i+1); - TEST_ASSERT(info == GrB_SUCCESS); - - info = RG_MatrixTupleIter_next_UINT64(&iter, &row, &col, &val); - - TEST_ASSERT(info == GrB_SUCCESS); - TEST_ASSERT(row == i+1); - TEST_ASSERT(col == j+1); - TEST_ASSERT(val == 1); - - info = RG_MatrixTupleIter_next_UINT64(&iter, &row, &col, &val); - TEST_ASSERT(info == GxB_EXHAUSTED); - - RG_Matrix_free(&A); - TEST_ASSERT(A == NULL); - RG_MatrixTupleIter_detach(&iter); - TEST_ASSERT(iter.A == NULL); -} - -TEST_LIST = { - {"RGMatrixTupleIter_attach", test_RGMatrixTupleIter_attach}, - {"RGMatrixTupleIter_next", test_RGMatrixTupleIter_next}, - {"RGMatrixTupleIter_next_sparse", test_RGMatrixTupleIter_next_sparse}, - {"RGMatrixTupleIter_reuse", test_RGMatrixTupleIter_reuse}, - {"RGMatrixTupleIter_iterate_row", test_RGMatrixTupleIter_iterate_row}, - {"RGMatrixTupleIter_iterate_range", test_RGMatrixTupleIter_iterate_range}, - {NULL, NULL} -};