From ade1e9936435c562407d0403190ed25658a65dbc Mon Sep 17 00:00:00 2001 From: Homka122 Date: Mon, 5 May 2025 23:08:04 +0300 Subject: [PATCH 001/122] Feat: intial commit with draft version of CFL algorithm with optimization --- .../LAGraph_CFL_reachability_advanced.c | 495 ++++++++++++++++++ 1 file changed, 495 insertions(+) create mode 100644 experimental/algorithm/LAGraph_CFL_reachability_advanced.c diff --git a/experimental/algorithm/LAGraph_CFL_reachability_advanced.c b/experimental/algorithm/LAGraph_CFL_reachability_advanced.c new file mode 100644 index 0000000000..8a6bb612bb --- /dev/null +++ b/experimental/algorithm/LAGraph_CFL_reachability_advanced.c @@ -0,0 +1,495 @@ +//------------------------------------------------------------------------------ +// LAGraph_CFL_reachability.c: Context-Free Language Reachability Matrix-Based +// Algorithm +// ------------------------------------------------------------------------------ +// +// LAGraph, (c) 2019-2024 by The LAGraph Contributors, All Rights Reserved. +// SPDX-License-Identifier: BSD-2-Clause + +// Contributed by Ilhom Kombaev, Semyon Grigoriev, St. Petersburg State University. + +//------------------------------------------------------------------------------ + +// Code is based on the "A matrix-based CFPQ algorithm" described in the +// following paper: * Rustam Azimov, Semyon Grigorev, "Context-Free Path +// Querying Using Linear Algebra", URL: +// https://disser.spbu.ru/files/2022/disser_azimov.pdf + +#define LG_FREE_WORK \ + { \ + LAGraph_Free((void **)&nnzs, msg); \ + GrB_free(&true_scalar); \ + GrB_free(&identity_matrix); \ + LAGraph_Free((void **)&T, msg); \ + LAGraph_Free((void **)&indexes, msg); \ + } + +#define LG_FREE_ALL \ + { \ + for (size_t i = 0; i < nonterms_count; i++) { \ + GrB_free(&T[i]); \ + } \ + \ + LG_FREE_WORK; \ + } + +#include "LG_internal.h" +#include + +#define ERROR_RULE(msg) \ + { \ + LG_ASSERT_MSGF(false, GrB_INVALID_VALUE, "Rule with index %ld is invalid. " msg, \ + i); \ + } + +#define ADD_TO_MSG(...) \ + { \ + if (msg_len == 0) { \ + msg_len += \ + snprintf(msg, LAGRAPH_MSG_LEN, \ + "LAGraph failure (file %s, line %d): ", __FILE__, __LINE__); \ + } \ + if (msg_len < LAGRAPH_MSG_LEN) { \ + msg_len += snprintf(msg + msg_len, LAGRAPH_MSG_LEN - msg_len, __VA_ARGS__); \ + } \ + } + +#define ADD_INDEX_TO_ERROR_RULE(rule, i) \ + { \ + rule.len_indexes_str += snprintf(rule.indexes_str + rule.len_indexes_str, \ + LAGRAPH_MSG_LEN - rule.len_indexes_str, \ + rule.count == 0 ? "%ld" : ", %ld", i); \ + rule.count++; \ + } + +#define IS_ISO(matrix, msg) \ + { \ + GxB_Matrix_iso(&iso_flag, matrix); \ + GRB_TRY(GrB_Matrix_nvals(&new_nnz, matrix)); \ + if (!iso_flag && new_nnz) { \ + GxB_print(matrix, 1); \ + printf(msg); \ + } \ + } + +#define SKIP_IF_NULL(matrix) \ + GrB_Matrix_nvals(&new_nnz, matrix); \ + if (new_nnz == 0) { \ + continue; \ + } + +// LAGraph_CFL_reachability: Context-Free Language Reachability Matrix-Based Algorithm +// +// This function determines the set of vertex pairs (u, v) in a graph (represented by +// adjacency matrices) such that there is a path from u to v, where the edge labels form a +// word from the language generated by the context-free grammar (represented by `rules`). +// +// Terminals and non-terminals are enumerated by integers starting from zero. +// The start non-terminal is the non-terminal with index 0. +// +// Example: +// +// Graph: +// ┌───┐ ┌───┐ ┌───┐ ┌───┐ ┌───┐ +// │ 0 ├───► 1 ├───► 2 ├───► 3 ├───► 4 │ +// └───┘ a └─┬─┘ a └─▲─┘ b └───┘ b └───┘ +// │ │ +// │ ┌───┐ │ +// a└─► 5 ├─┘b +// └───┘ +// +// Grammar: S -> aSb | ab +// +// There are paths from node [1] to node [3] and from node [1] to node [2] that form the +// word "ab" ([1]-a->[2]-b->[3] and [1]-a->[5]-b->[2]). The word "ab" is in the language +// generated by our context-free grammar, so the pairs (1, 3) and (1, 2) will be included +// in the result. +// +// Note: It doesn't matter how many paths exist from node [A] to node [B] that form a word +// in the language. If at least one path exists, the pair ([A], [B]) will be included in +// the result. +// +// In contrast, the path from node [1] to node [4] forms the word "abb" +// ([1]-a->[2]-b->[3]-b->[4]) and the word "abbb" ([1]-a->[5]-b->[2]-b->[3]-b->[4]). +// The words "aab" and "abbb" are not in the language, so the pair (1, 4) will not be +// included in the result. +// +// With this graph and grammar, we obtain the following results: +// (0, 4) - because there exists a path (0-1-2-3-4) that forms the word "aabb" +// (1, 3) - because there exists a path (1-2-3) that forms "ab" +// (1, 2) - because there exists a path (1-5-2) that forms the word "ab" +// (0, 3) - because there exists a path (0-1-5-2-3) that forms the word "aabb" +GrB_Info LAGraph_CFL_reachability_adv( + // Output + GrB_Matrix *outputs, // Array of matrices containing results. + // The size of the array must be equal to nonterms_count. + // + // outputs[k]: (i, j) = true if and only if there is a path + // from node i to node j whose edge labels form a word + // derivable from the non-terminal 'k' of the specified CFG. + // Input + const GrB_Matrix *adj_matrices, // Array of adjacency matrices representing the graph. + // The length of this array is equal to the count of + // terminals (terms_count). + // + // adj_matrices[t]: (i, j) == 1 if and only if there + // is an edge between nodes i and j with the label of + // the terminal corresponding to index 't' (where t is + // in the range [0, terms_count - 1]). + int32_t terms_count, // The total number of terminal symbols in the CFG. + int32_t nonterms_count, // The total number of non-terminal symbols in the CFG. + const LAGraph_rule_WCNF *rules, // The rules of the CFG. + size_t rules_count, // The total number of rules in the CFG. + char *msg // Message string for error reporting. +) { + // Declare workspace and clear the msg string, if not NULL + GrB_Matrix *T; + GrB_Matrix *delta_matrices; + GrB_Matrix *matrices; + GrB_Matrix *temp_matrices; + bool t_empty_flags[nonterms_count]; // t_empty_flags[i] == true <=> T[i] is empty + GrB_Matrix identity_matrix = NULL; + uint64_t *nnzs = NULL; + LG_CLEAR_MSG; + size_t msg_len = 0; // For error formatting + bool iso_flag = false; + GrB_Index *indexes = NULL; + + GrB_Scalar true_scalar; + GrB_Scalar_new(&true_scalar, GrB_BOOL); + GrB_Scalar_setElement_BOOL(true_scalar, true); + + LG_TRY(LAGraph_Calloc((void **)&T, nonterms_count, sizeof(GrB_Matrix), msg)); + LG_TRY(LAGraph_Calloc((void **)&delta_matrices, nonterms_count, sizeof(GrB_Matrix), + msg)); + LG_TRY(LAGraph_Calloc((void **)&matrices, nonterms_count, sizeof(GrB_Matrix), msg)); + LG_TRY( + LAGraph_Calloc((void **)&temp_matrices, nonterms_count, sizeof(GrB_Matrix), msg)); + + LG_ASSERT_MSG(terms_count > 0, GrB_INVALID_VALUE, + "The number of terminals must be greater than zero."); + LG_ASSERT_MSG(nonterms_count > 0, GrB_INVALID_VALUE, + "The number of non-terminals must be greater than zero."); + LG_ASSERT_MSG(rules_count > 0, GrB_INVALID_VALUE, + "The number of rules must be greater than zero."); + LG_ASSERT_MSG(outputs != NULL, GrB_NULL_POINTER, "The outputs array cannot be null."); + LG_ASSERT_MSG(rules != NULL, GrB_NULL_POINTER, "The rules array cannot be null."); + LG_ASSERT_MSG(adj_matrices != NULL, GrB_NULL_POINTER, + "The adjacency matrices array cannot be null."); + + // Find null adjacency matrices + bool found_null = false; + for (int32_t i = 0; i < terms_count; i++) { + if (adj_matrices[i] != NULL) + continue; + + if (!found_null) { + ADD_TO_MSG("Adjacency matrices with these indexes are null: "); + ADD_TO_MSG("%d", i); + } else { + ADD_TO_MSG(", %d", i); + } + + found_null = true; + } + + if (found_null) { + LG_FREE_ALL; + return GrB_NULL_POINTER; + } + + GrB_Index n; + GRB_TRY(GrB_Matrix_ncols(&n, adj_matrices[0])); + + // Create nonterms matrices + for (int32_t i = 0; i < nonterms_count; i++) { + GRB_TRY(GrB_Matrix_new(&T[i], GrB_BOOL, n, n)); + GRB_TRY(GrB_Matrix_new(&delta_matrices[i], GrB_BOOL, n, n)); + GRB_TRY(GrB_Matrix_new(&matrices[i], GrB_BOOL, n, n)); + GRB_TRY(GrB_Matrix_new(&temp_matrices[i], GrB_BOOL, n, n)); + t_empty_flags[i] = true; + } + + // Arrays for processing rules + size_t eps_rules[rules_count], eps_rules_count = 0; // [Variable -> eps] + size_t term_rules[rules_count], term_rules_count = 0; // [Variable -> term] + size_t bin_rules[rules_count], bin_rules_count = 0; // [Variable -> AB] + + // Process rules + typedef struct { + size_t count; + size_t len_indexes_str; + char indexes_str[LAGRAPH_MSG_LEN]; + } rule_error_s; + rule_error_s term_err = {0}; + rule_error_s nonterm_err = {0}; + rule_error_s invalid_err = {0}; + for (size_t i = 0; i < rules_count; i++) { + LAGraph_rule_WCNF rule = rules[i]; + + bool is_rule_eps = rule.prod_A == -1 && rule.prod_B == -1; + bool is_rule_term = rule.prod_A != -1 && rule.prod_B == -1; + bool is_rule_bin = rule.prod_A != -1 && rule.prod_B != -1; + + // Check that all rules are well-formed + if (rule.nonterm < 0 || rule.nonterm >= nonterms_count) { + ADD_INDEX_TO_ERROR_RULE(nonterm_err, i); + } + + // [Variable -> eps] + if (is_rule_eps) { + eps_rules[eps_rules_count++] = i; + + continue; + } + + // [Variable -> term] + if (is_rule_term) { + term_rules[term_rules_count++] = i; + + if (rule.prod_A < -1 || rule.prod_A >= terms_count) { + ADD_INDEX_TO_ERROR_RULE(term_err, i); + } + + continue; + } + + // [Variable -> A B] + if (is_rule_bin) { + bin_rules[bin_rules_count++] = i; + + if (rule.prod_A < -1 || rule.prod_A >= nonterms_count || rule.prod_B < -1 || + rule.prod_B >= nonterms_count) { + ADD_INDEX_TO_ERROR_RULE(nonterm_err, i); + } + + continue; + } + + // [Variable -> _ B] + ADD_INDEX_TO_ERROR_RULE(invalid_err, i); + } + + if (term_err.count + nonterm_err.count + invalid_err.count > 0) { + ADD_TO_MSG("Count of invalid rules: %ld.\n", + term_err.count + nonterm_err.count + invalid_err.count); + + if (nonterm_err.count > 0) { + ADD_TO_MSG("Non-terminals must be in range [0, nonterms_count). "); + ADD_TO_MSG("Indexes of invalid rules: %s\n", nonterm_err.indexes_str) + } + if (term_err.count > 0) { + ADD_TO_MSG("Terminals must be in range [-1, nonterms_count). "); + ADD_TO_MSG("Indexes of invalid rules: %s\n", term_err.indexes_str) + } + if (invalid_err.count > 0) { + ADD_TO_MSG("[Variable -> _ B] type of rule is not acceptable. "); + ADD_TO_MSG("Indexes of invalid rules: %.120s\n", invalid_err.indexes_str) + } + + LG_FREE_ALL; + return GrB_INVALID_VALUE; + } + + // Rule [Variable -> term] + for (size_t i = 0; i < term_rules_count; i++) { + LAGraph_rule_WCNF term_rule = rules[term_rules[i]]; + GrB_Index adj_matrix_nnz = 0; + GRB_TRY(GrB_Matrix_nvals(&adj_matrix_nnz, adj_matrices[term_rule.prod_A])); + + if (adj_matrix_nnz == 0) { + continue; + } + + GxB_eWiseUnion(delta_matrices[term_rule.nonterm], GrB_NULL, GrB_NULL, + GxB_PAIR_BOOL, delta_matrices[term_rule.nonterm], true_scalar, + adj_matrices[term_rule.prod_A], true_scalar, GrB_NULL); + + t_empty_flags[term_rule.nonterm] = false; + +#ifdef DEBUG_CFL_REACHBILITY + GxB_Matrix_iso(&iso_flag, T[term_rule.nonterm]); + printf("[TERM] eWiseUnion: NONTERM: %d (ISO: %d)\n", term_rule.nonterm, iso_flag); +#endif + } + + GrB_Vector v_diag; + GRB_TRY(GrB_Vector_new(&v_diag, GrB_BOOL, n)); + GRB_TRY(GrB_Vector_assign_BOOL(v_diag, GrB_NULL, GrB_NULL, true, GrB_ALL, n, NULL)); + GRB_TRY(GrB_Matrix_diag(&identity_matrix, v_diag, 0)); + GRB_TRY(GrB_free(&v_diag)); + + // Rule [Variable -> eps] + for (size_t i = 0; i < eps_rules_count; i++) { + LAGraph_rule_WCNF eps_rule = rules[eps_rules[i]]; + + GxB_eWiseUnion(delta_matrices[eps_rule.nonterm], GrB_NULL, GxB_PAIR_BOOL, + GxB_PAIR_BOOL, delta_matrices[eps_rule.nonterm], true_scalar, + identity_matrix, true_scalar, GrB_NULL); + + t_empty_flags[eps_rule.nonterm] = false; + +#ifdef DEBUG_CFL_REACHBILITY + GxB_Matrix_iso(&iso_flag, T[eps_rule.nonterm]); + printf("[EPS] eWiseUnion: NONTERM: %d (ISO: %d)\n", eps_rule.nonterm, iso_flag); +#endif + } + + // Rule [Variable -> Variable1 Variable2] + LG_TRY(LAGraph_Calloc((void **)&nnzs, nonterms_count, sizeof(uint64_t), msg)); + + double start, end; + bool changed = true; + size_t iteration = 0; + double mxm1 = 0.0; + double wise1 = 0.0; + double mxm2 = 0.0; + double wise2 = 0.0; + double rsub = 0.0; + GrB_Index new_nnz; + while (changed) { + iteration++; + changed = false; + + printf("\n--- ITERATARION %d ---\n", iteration); + + for (size_t i = 0; i < nonterms_count; i++) { + GRB_TRY(GrB_Matrix_new(&temp_matrices[i], GrB_BOOL, n, n)); + } + + start = LAGraph_WallClockTime(); + for (size_t i = 0; i < bin_rules_count; i++) { + LAGraph_rule_WCNF bin_rule = rules[bin_rules[i]]; + + SKIP_IF_NULL(matrices[bin_rule.prod_A]); + SKIP_IF_NULL(delta_matrices[bin_rule.prod_B]); + + GRB_TRY(GrB_mxm(temp_matrices[bin_rule.nonterm], GrB_NULL, GrB_LOR, + GrB_LOR_LAND_SEMIRING_BOOL, matrices[bin_rule.prod_A], + delta_matrices[bin_rule.prod_B], GrB_NULL)); + GxB_Matrix_iso(&iso_flag, temp_matrices[bin_rule.nonterm]); + GRB_TRY(GrB_Matrix_nvals(&new_nnz, temp_matrices[bin_rule.nonterm])); + if (!iso_flag && new_nnz) { + GxB_print(temp_matrices[bin_rule.nonterm], 1); + printf("ALERT"); + } + GxB_Matrix_iso(&iso_flag, matrices[bin_rule.prod_A]); + GRB_TRY(GrB_Matrix_nvals(&new_nnz, matrices[bin_rule.prod_A])); + if (!iso_flag && new_nnz) { + GxB_print(matrices[bin_rule.prod_A], 1); + printf("ALERT"); + } + GxB_Matrix_iso(&iso_flag, delta_matrices[bin_rule.prod_B]); + GRB_TRY(GrB_Matrix_nvals(&new_nnz, delta_matrices[bin_rule.prod_B])); + if (!iso_flag && new_nnz) { + GxB_print(delta_matrices[bin_rule.prod_B], 1); + printf("ALERT"); + } + } + end = LAGraph_WallClockTime(); + printf("MXM 1 %.3fs\n", end - start); + mxm1 += end - start; + + start = LAGraph_WallClockTime(); + for (size_t i = 0; i < nonterms_count; i++) { + SKIP_IF_NULL(delta_matrices[i]); + GrB_Matrix_nvals(&new_nnz, matrices[i]); + if (new_nnz == 0) { + GrB_Matrix_apply(matrices[i], GrB_NULL, GrB_NULL, GrB_IDENTITY_BOOL, + delta_matrices[i], GrB_NULL); + IS_ISO(matrices[i], "ALERT WISE 1"); + continue; + } + GrB_eWiseAdd(matrices[i], GrB_NULL, GrB_NULL, GxB_ANY_BOOL, matrices[i], + delta_matrices[i], GrB_NULL); + IS_ISO(matrices[i], "ALERT WISE 1"); + } + end = LAGraph_WallClockTime(); + printf("WISE 1 %.3f\n", end - start); + wise1 += end - start; + + start = LAGraph_WallClockTime(); + for (size_t i = 0; i < bin_rules_count; i++) { + LAGraph_rule_WCNF bin_rule = rules[bin_rules[i]]; + + SKIP_IF_NULL(delta_matrices[bin_rule.prod_A]); + SKIP_IF_NULL(matrices[bin_rule.prod_B]); + + GRB_TRY(GrB_mxm(temp_matrices[bin_rule.nonterm], GrB_NULL, GxB_ANY_BOOL, + GxB_ANY_PAIR_BOOL, delta_matrices[bin_rule.prod_A], + matrices[bin_rule.prod_B], GrB_NULL)) + } + end = LAGraph_WallClockTime(); + printf("MXM 2 %.3f\n", end - start); + mxm2 += end - start; + + start = LAGraph_WallClockTime(); + + for (size_t i = 0; i < nonterms_count; i++) { + // GrB_eWiseAdd(delta_matrices[i], GrB_NULL, GrB_NULL, GxB_ANY_BOOL, + // temp_matrices[i], temp_matrices[i], GrB_DESC_R); + GrB_Matrix_new(&delta_matrices[i], GrB_BOOL, n, n); + GrB_Matrix_apply(delta_matrices[i], GrB_NULL, GrB_NULL, GrB_IDENTITY_BOOL, + temp_matrices[i], GrB_NULL); + // GxB_eWiseUnion ( + // delta_matrices[i],GrB_NULL,GrB_NULL,GxB_ANY_BOOL, + // temp_matrices[i],true_scalar,temp_matrices[i],true_scalar,GrB_DESC_R + // ); + // GrB_Matrix_dup(&delta_matrices[i], temp_matrices[i]); + } + end = LAGraph_WallClockTime(); + printf("WISE 2 (COPY) %.3f\n", end - start); + wise2 += end - start; + + start = LAGraph_WallClockTime(); + for (size_t i = 0; i < nonterms_count; i++) { + SKIP_IF_NULL(delta_matrices[i]); + GrB_Matrix_apply(delta_matrices[i], matrices[i], GrB_NULL, GrB_IDENTITY_BOOL, + delta_matrices[i], GrB_DESC_C); + + // GrB_eWiseAdd(matrices[i], GrB_NULL, GrB_NULL, GrB_MINUS_BOOL, matrices[i], + // delta_matrices[i], GrB_NULL); + // GxB_eWiseUnion ( + // delta_matrices[i],matrices[i],GrB_NULL,GxB_ANY_BOOL, + // delta_matrices[i],true_scalar,delta_matrices[i],true_scalar,GrB_DESC_C + // ); + } + end = LAGraph_WallClockTime(); + printf("WISE 3 (MASK) %.3f\n", end - start); + rsub += end - start; + + for (size_t i = 0; i < nonterms_count; i++) { + GrB_Index new_nnz; + GRB_TRY(GrB_Matrix_nvals(&new_nnz, matrices[i])); + if (new_nnz != 0) + t_empty_flags[i] = false; + + changed = changed || (nnzs[i] != new_nnz); + nnzs[i] = new_nnz; + } + +#ifdef DEBUG_CFL_REACHBILITY + GxB_Matrix_iso(&iso_flag, T[bin_rule.nonterm]); + printf("[TERM1 TERM2] MULTIPLY, S: %d, A: %d, B: %d, " + "I: %ld (ISO: %d)\n", + bin_rule.nonterm, bin_rule.prod_A, bin_rule.prod_B, i, iso_flag); +#endif + } + + printf("MXM1: %.3f, wise1: %.3f, MXM2: %.3f, wise2: %.3f, rsub: %.3f", mxm1, wise1, + mxm2, wise2, rsub); + +#ifdef DEBUG_CFL_REACHBILITY + for (int32_t i = 0; i < nonterms_count; i++) { + printf("MATRIX WITH INDEX %d:\n", i); + GxB_print(T[i], GxB_SUMMARY); + } +#endif + + for (int32_t i = 0; i < nonterms_count; i++) { + outputs[i] = matrices[i]; + } + + LG_FREE_WORK; + return GrB_SUCCESS; +} From 8b16e59d9799b94f9b92528af8e14d195d32b43a Mon Sep 17 00:00:00 2001 From: Homka122 Date: Mon, 5 May 2025 23:28:03 +0300 Subject: [PATCH 002/122] Feat: add algorithm with optimization to header --- include/LAGraphX.h | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/include/LAGraphX.h b/include/LAGraphX.h index 3355addb2e..aaecb137c1 100644 --- a/include/LAGraphX.h +++ b/include/LAGraphX.h @@ -1096,6 +1096,33 @@ GrB_Info LAGraph_CFL_reachability char *msg // Message string for error reporting. ) ; +GrB_Info LAGraph_CFL_reachability_adv +( + // Output + GrB_Matrix *outputs, // Array of matrices containing results. + // The size of the array must be equal to nonterms_count. + // + // outputs[k]: (i, j) = true if and only if there is a path + // from node i to node j whose edge labels form a word + // derivable from the non-terminal 'k' of the specified CFG. + + // Input + const GrB_Matrix *adj_matrices, // Array of adjacency matrices representing the graph. + // The length of this array is equal to the count of + // terminals (terms_count). + // + // adj_matrices[t]: (i, j) == 1 if and only if there + // is an edge between nodes i and j with the label of + // the terminal corresponding to index 't' (where t is + // in the range [0, terms_count - 1]). + + int32_t terms_count, // The total number of terminal symbols in the CFG. + int32_t nonterms_count, // The total number of non-terminal symbols in the CFG. + const LAGraph_rule_WCNF *rules, // The rules of the CFG. + size_t rules_count, // The total number of rules in the CFG. + char *msg // Message string for error reporting. +); + //------------------------------------------------------------------------------ // a simple example of an algorithm //------------------------------------------------------------------------------ From 2cdcee78a6531df653c96bc42090cbd9110df21f Mon Sep 17 00:00:00 2001 From: Homka122 Date: Mon, 5 May 2025 23:58:14 +0300 Subject: [PATCH 003/122] Feat: add measure time macro --- .../LAGraph_CFL_reachability_advanced.c | 95 ++++++++----------- 1 file changed, 41 insertions(+), 54 deletions(-) diff --git a/experimental/algorithm/LAGraph_CFL_reachability_advanced.c b/experimental/algorithm/LAGraph_CFL_reachability_advanced.c index 8a6bb612bb..6e82ad1c43 100644 --- a/experimental/algorithm/LAGraph_CFL_reachability_advanced.c +++ b/experimental/algorithm/LAGraph_CFL_reachability_advanced.c @@ -78,6 +78,20 @@ continue; \ } +#define TIMER_START() \ + { \ + start_time = LAGraph_WallClockTime(); \ + } + +#define TIMER_STOP(label, accumulator) \ + { \ + end_time = LAGraph_WallClockTime(); \ + printf("%s %.3fs\n", label, end_time - start_time); \ + if (accumulator != NULL) { \ + *(accumulator) += (end_time - start_time); \ + } \ + } + // LAGraph_CFL_reachability: Context-Free Language Reachability Matrix-Based Algorithm // // This function determines the set of vertex pairs (u, v) in a graph (represented by @@ -338,7 +352,7 @@ GrB_Info LAGraph_CFL_reachability_adv( // Rule [Variable -> Variable1 Variable2] LG_TRY(LAGraph_Calloc((void **)&nnzs, nonterms_count, sizeof(uint64_t), msg)); - double start, end; + double start_time, end_time; bool changed = true; size_t iteration = 0; double mxm1 = 0.0; @@ -357,42 +371,30 @@ GrB_Info LAGraph_CFL_reachability_adv( GRB_TRY(GrB_Matrix_new(&temp_matrices[i], GrB_BOOL, n, n)); } - start = LAGraph_WallClockTime(); + TIMER_START(); for (size_t i = 0; i < bin_rules_count; i++) { LAGraph_rule_WCNF bin_rule = rules[bin_rules[i]]; SKIP_IF_NULL(matrices[bin_rule.prod_A]); SKIP_IF_NULL(delta_matrices[bin_rule.prod_B]); + GrB_Index left_nnz; + GrB_Index right_nnz; + GRB_TRY(GrB_mxm(temp_matrices[bin_rule.nonterm], GrB_NULL, GrB_LOR, GrB_LOR_LAND_SEMIRING_BOOL, matrices[bin_rule.prod_A], delta_matrices[bin_rule.prod_B], GrB_NULL)); - GxB_Matrix_iso(&iso_flag, temp_matrices[bin_rule.nonterm]); - GRB_TRY(GrB_Matrix_nvals(&new_nnz, temp_matrices[bin_rule.nonterm])); - if (!iso_flag && new_nnz) { - GxB_print(temp_matrices[bin_rule.nonterm], 1); - printf("ALERT"); - } - GxB_Matrix_iso(&iso_flag, matrices[bin_rule.prod_A]); - GRB_TRY(GrB_Matrix_nvals(&new_nnz, matrices[bin_rule.prod_A])); - if (!iso_flag && new_nnz) { - GxB_print(matrices[bin_rule.prod_A], 1); - printf("ALERT"); - } - GxB_Matrix_iso(&iso_flag, delta_matrices[bin_rule.prod_B]); - GRB_TRY(GrB_Matrix_nvals(&new_nnz, delta_matrices[bin_rule.prod_B])); - if (!iso_flag && new_nnz) { - GxB_print(delta_matrices[bin_rule.prod_B], 1); - printf("ALERT"); - } + + IS_ISO(temp_matrices[bin_rule.nonterm], "ALERT"); + IS_ISO(matrices[bin_rule.prod_A], "ALERT"); + IS_ISO(delta_matrices[bin_rule.prod_B], "ALERT"); } - end = LAGraph_WallClockTime(); - printf("MXM 1 %.3fs\n", end - start); - mxm1 += end - start; + TIMER_STOP("MXM 1", &mxm1); - start = LAGraph_WallClockTime(); + TIMER_START() for (size_t i = 0; i < nonterms_count; i++) { SKIP_IF_NULL(delta_matrices[i]); + GrB_Matrix_nvals(&new_nnz, matrices[i]); if (new_nnz == 0) { GrB_Matrix_apply(matrices[i], GrB_NULL, GrB_NULL, GrB_IDENTITY_BOOL, @@ -400,15 +402,15 @@ GrB_Info LAGraph_CFL_reachability_adv( IS_ISO(matrices[i], "ALERT WISE 1"); continue; } + GrB_eWiseAdd(matrices[i], GrB_NULL, GrB_NULL, GxB_ANY_BOOL, matrices[i], delta_matrices[i], GrB_NULL); + IS_ISO(matrices[i], "ALERT WISE 1"); } - end = LAGraph_WallClockTime(); - printf("WISE 1 %.3f\n", end - start); - wise1 += end - start; + TIMER_STOP("WISE 1", &wise1); - start = LAGraph_WallClockTime(); + TIMER_START() for (size_t i = 0; i < bin_rules_count; i++) { LAGraph_rule_WCNF bin_rule = rules[bin_rules[i]]; @@ -419,44 +421,29 @@ GrB_Info LAGraph_CFL_reachability_adv( GxB_ANY_PAIR_BOOL, delta_matrices[bin_rule.prod_A], matrices[bin_rule.prod_B], GrB_NULL)) } - end = LAGraph_WallClockTime(); - printf("MXM 2 %.3f\n", end - start); - mxm2 += end - start; - - start = LAGraph_WallClockTime(); + TIMER_STOP("MXM 2", &mxm2); + TIMER_START(); for (size_t i = 0; i < nonterms_count; i++) { - // GrB_eWiseAdd(delta_matrices[i], GrB_NULL, GrB_NULL, GxB_ANY_BOOL, - // temp_matrices[i], temp_matrices[i], GrB_DESC_R); GrB_Matrix_new(&delta_matrices[i], GrB_BOOL, n, n); + SKIP_IF_NULL(temp_matrices[i]); + GrB_Matrix_apply(delta_matrices[i], GrB_NULL, GrB_NULL, GrB_IDENTITY_BOOL, temp_matrices[i], GrB_NULL); - // GxB_eWiseUnion ( - // delta_matrices[i],GrB_NULL,GrB_NULL,GxB_ANY_BOOL, - // temp_matrices[i],true_scalar,temp_matrices[i],true_scalar,GrB_DESC_R - // ); - // GrB_Matrix_dup(&delta_matrices[i], temp_matrices[i]); + + IS_ISO(delta_matrices[i], "WISE 2"); } - end = LAGraph_WallClockTime(); - printf("WISE 2 (COPY) %.3f\n", end - start); - wise2 += end - start; + TIMER_STOP("WISE 2 (copy)", &wise2); - start = LAGraph_WallClockTime(); + TIMER_START(); for (size_t i = 0; i < nonterms_count; i++) { SKIP_IF_NULL(delta_matrices[i]); + GrB_Matrix_apply(delta_matrices[i], matrices[i], GrB_NULL, GrB_IDENTITY_BOOL, delta_matrices[i], GrB_DESC_C); - - // GrB_eWiseAdd(matrices[i], GrB_NULL, GrB_NULL, GrB_MINUS_BOOL, matrices[i], - // delta_matrices[i], GrB_NULL); - // GxB_eWiseUnion ( - // delta_matrices[i],matrices[i],GrB_NULL,GxB_ANY_BOOL, - // delta_matrices[i],true_scalar,delta_matrices[i],true_scalar,GrB_DESC_C - // ); + IS_ISO(delta_matrices[i], "WISE 3"); } - end = LAGraph_WallClockTime(); - printf("WISE 3 (MASK) %.3f\n", end - start); - rsub += end - start; + TIMER_STOP("WISE 3 (MASK)", &rsub); for (size_t i = 0; i < nonterms_count; i++) { GrB_Index new_nnz; From 9548c1e7d5e3ad12467e3edc5e7a02451ad7d749 Mon Sep 17 00:00:00 2001 From: Homka122 Date: Sat, 10 May 2025 15:30:40 +0300 Subject: [PATCH 004/122] Feat: add null check to mxm --- .../LAGraph_CFL_reachability_advanced.c | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/experimental/algorithm/LAGraph_CFL_reachability_advanced.c b/experimental/algorithm/LAGraph_CFL_reachability_advanced.c index 6e82ad1c43..a1cd941f6d 100644 --- a/experimental/algorithm/LAGraph_CFL_reachability_advanced.c +++ b/experimental/algorithm/LAGraph_CFL_reachability_advanced.c @@ -381,9 +381,15 @@ GrB_Info LAGraph_CFL_reachability_adv( GrB_Index left_nnz; GrB_Index right_nnz; - GRB_TRY(GrB_mxm(temp_matrices[bin_rule.nonterm], GrB_NULL, GrB_LOR, - GrB_LOR_LAND_SEMIRING_BOOL, matrices[bin_rule.prod_A], - delta_matrices[bin_rule.prod_B], GrB_NULL)); + GrB_Matrix res; + GrB_Matrix_new(&res, GrB_BOOL, n, n); + + GRB_TRY(GrB_mxm(res, GrB_NULL, GrB_NULL, GxB_ANY_PAIR_BOOL, + matrices[bin_rule.prod_A], delta_matrices[bin_rule.prod_B], + GrB_NULL)); + SKIP_IF_NULL(res); + GrB_eWiseAdd(temp_matrices[bin_rule.nonterm], GrB_NULL, GrB_NULL, + GxB_ANY_BOOL, temp_matrices[bin_rule.nonterm], res, GrB_NULL); IS_ISO(temp_matrices[bin_rule.nonterm], "ALERT"); IS_ISO(matrices[bin_rule.prod_A], "ALERT"); @@ -438,6 +444,10 @@ GrB_Info LAGraph_CFL_reachability_adv( TIMER_START(); for (size_t i = 0; i < nonterms_count; i++) { SKIP_IF_NULL(delta_matrices[i]); + SKIP_IF_NULL(matrices[i]); + + GrB_Matrix zero; + GrB_Matrix_new(&zero, GrB_NULL, n, n); GrB_Matrix_apply(delta_matrices[i], matrices[i], GrB_NULL, GrB_IDENTITY_BOOL, delta_matrices[i], GrB_DESC_C); From 4660261090342170772a9a3c9462d671fa4d9e43 Mon Sep 17 00:00:00 2001 From: Homka122 Date: Sat, 10 May 2025 15:31:00 +0300 Subject: [PATCH 005/122] Refactor: replace apply to ewiseAdd --- experimental/algorithm/LAGraph_CFL_reachability_advanced.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/experimental/algorithm/LAGraph_CFL_reachability_advanced.c b/experimental/algorithm/LAGraph_CFL_reachability_advanced.c index a1cd941f6d..f194877f67 100644 --- a/experimental/algorithm/LAGraph_CFL_reachability_advanced.c +++ b/experimental/algorithm/LAGraph_CFL_reachability_advanced.c @@ -449,8 +449,9 @@ GrB_Info LAGraph_CFL_reachability_adv( GrB_Matrix zero; GrB_Matrix_new(&zero, GrB_NULL, n, n); - GrB_Matrix_apply(delta_matrices[i], matrices[i], GrB_NULL, GrB_IDENTITY_BOOL, - delta_matrices[i], GrB_DESC_C); + GrB_eWiseAdd(delta_matrices[i], matrices[i], GrB_NULL, GxB_ANY_BOOL, zero, + delta_matrices[i], GrB_DESC_C); + IS_ISO(delta_matrices[i], "WISE 3"); } TIMER_STOP("WISE 3 (MASK)", &rsub); From 6bd45f2c25929382987011da154fb7b37537c71d Mon Sep 17 00:00:00 2001 From: Homka122 Date: Sat, 10 May 2025 15:31:22 +0300 Subject: [PATCH 006/122] Feat: replace apply to dup method --- experimental/algorithm/LAGraph_CFL_reachability_advanced.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/experimental/algorithm/LAGraph_CFL_reachability_advanced.c b/experimental/algorithm/LAGraph_CFL_reachability_advanced.c index f194877f67..df02248f47 100644 --- a/experimental/algorithm/LAGraph_CFL_reachability_advanced.c +++ b/experimental/algorithm/LAGraph_CFL_reachability_advanced.c @@ -403,8 +403,7 @@ GrB_Info LAGraph_CFL_reachability_adv( GrB_Matrix_nvals(&new_nnz, matrices[i]); if (new_nnz == 0) { - GrB_Matrix_apply(matrices[i], GrB_NULL, GrB_NULL, GrB_IDENTITY_BOOL, - delta_matrices[i], GrB_NULL); + GrB_Matrix_dup(&matrices[i], delta_matrices[i]); IS_ISO(matrices[i], "ALERT WISE 1"); continue; } From 76bc80a88a5053930fe5dc2bc20a3c3ceea47ec8 Mon Sep 17 00:00:00 2001 From: Homka122 Date: Sun, 11 May 2025 18:51:34 +0300 Subject: [PATCH 007/122] Fix: type in printf while iteration --- experimental/algorithm/LAGraph_CFL_reachability_advanced.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/experimental/algorithm/LAGraph_CFL_reachability_advanced.c b/experimental/algorithm/LAGraph_CFL_reachability_advanced.c index df02248f47..9eb20a8ea7 100644 --- a/experimental/algorithm/LAGraph_CFL_reachability_advanced.c +++ b/experimental/algorithm/LAGraph_CFL_reachability_advanced.c @@ -365,7 +365,7 @@ GrB_Info LAGraph_CFL_reachability_adv( iteration++; changed = false; - printf("\n--- ITERATARION %d ---\n", iteration); + printf("\n--- ITERATARION %ld ---\n", iteration); for (size_t i = 0; i < nonterms_count; i++) { GRB_TRY(GrB_Matrix_new(&temp_matrices[i], GrB_BOOL, n, n)); From 4115a05ba2fc3a259160bc625c83d7bfe0902484 Mon Sep 17 00:00:00 2001 From: Homka122 Date: Sun, 11 May 2025 18:52:13 +0300 Subject: [PATCH 008/122] Refactor: apply mask now seperate function --- .../LAGraph_CFL_reachability_advanced.c | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/experimental/algorithm/LAGraph_CFL_reachability_advanced.c b/experimental/algorithm/LAGraph_CFL_reachability_advanced.c index 9eb20a8ea7..ca8d2d74a0 100644 --- a/experimental/algorithm/LAGraph_CFL_reachability_advanced.c +++ b/experimental/algorithm/LAGraph_CFL_reachability_advanced.c @@ -92,6 +92,18 @@ } \ } +#define TRY(GrB_method) \ + { \ + GrB_Info LG_GrB_Info = GrB_method; \ + if (LG_GrB_Info < GrB_SUCCESS) { \ + return LG_GrB_Info; \ + } \ + } + +GrB_Info matrix_apply_mask_i(GrB_Matrix matrix, GrB_Matrix mask, GrB_Index size) { + TRY(GrB_Matrix_apply(matrix, mask, GrB_NULL, GrB_IDENTITY_BOOL, matrix, GrB_DESC_SC)); +} + // LAGraph_CFL_reachability: Context-Free Language Reachability Matrix-Based Algorithm // // This function determines the set of vertex pairs (u, v) in a graph (represented by @@ -445,11 +457,7 @@ GrB_Info LAGraph_CFL_reachability_adv( SKIP_IF_NULL(delta_matrices[i]); SKIP_IF_NULL(matrices[i]); - GrB_Matrix zero; - GrB_Matrix_new(&zero, GrB_NULL, n, n); - - GrB_eWiseAdd(delta_matrices[i], matrices[i], GrB_NULL, GxB_ANY_BOOL, zero, - delta_matrices[i], GrB_DESC_C); + GRB_TRY(matrix_apply_mask_i(delta_matrices[i], matrices[i], n)); IS_ISO(delta_matrices[i], "WISE 3"); } From 838ad5bad96c580177b38f95b636300e3b61e139 Mon Sep 17 00:00:00 2001 From: Homka122 Date: Mon, 12 May 2025 07:37:33 +0300 Subject: [PATCH 009/122] Refactor: now bench information output only with flag --- .../LAGraph_CFL_reachability_advanced.c | 35 ++++++++++++------- 1 file changed, 23 insertions(+), 12 deletions(-) diff --git a/experimental/algorithm/LAGraph_CFL_reachability_advanced.c b/experimental/algorithm/LAGraph_CFL_reachability_advanced.c index ca8d2d74a0..5515c04cf1 100644 --- a/experimental/algorithm/LAGraph_CFL_reachability_advanced.c +++ b/experimental/algorithm/LAGraph_CFL_reachability_advanced.c @@ -62,28 +62,27 @@ rule.count++; \ } -#define IS_ISO(matrix, msg) \ +// clang-format off +#if BENCH_CFL_REACHBILITY + #define IS_ISO(matrix, str) \ { \ + bool iso_flag; \ + GrB_Index nnz; \ GxB_Matrix_iso(&iso_flag, matrix); \ - GRB_TRY(GrB_Matrix_nvals(&new_nnz, matrix)); \ - if (!iso_flag && new_nnz) { \ + GrB_Matrix_nvals(&nnz, matrix); \ + if (!iso_flag && nnz) { \ + printf("-----ISO ALERT----- (%s)\n", str); \ GxB_print(matrix, 1); \ - printf(msg); \ + printf("-------------------\n"); \ } \ } -#define SKIP_IF_NULL(matrix) \ - GrB_Matrix_nvals(&new_nnz, matrix); \ - if (new_nnz == 0) { \ - continue; \ - } - -#define TIMER_START() \ + #define TIMER_START() \ { \ start_time = LAGraph_WallClockTime(); \ } -#define TIMER_STOP(label, accumulator) \ + #define TIMER_STOP(label, accumulator) \ { \ end_time = LAGraph_WallClockTime(); \ printf("%s %.3fs\n", label, end_time - start_time); \ @@ -91,6 +90,18 @@ *(accumulator) += (end_time - start_time); \ } \ } +#else + #define IS_ISO(matrix, str) + #define TIMER_START() + #define TIMER_STOP(label, accumulator) +#endif +// clang-format on + +#define SKIP_IF_NULL(matrix) \ + GrB_Matrix_nvals(&new_nnz, matrix); \ + if (new_nnz == 0) { \ + continue; \ + } #define TRY(GrB_method) \ { \ From 7d113ddb3b991540fe171f7bad68ab6a320a9397 Mon Sep 17 00:00:00 2001 From: Homka122 Date: Mon, 12 May 2025 07:38:02 +0300 Subject: [PATCH 010/122] Feat: add ISO check to rsub --- experimental/algorithm/LAGraph_CFL_reachability_advanced.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/experimental/algorithm/LAGraph_CFL_reachability_advanced.c b/experimental/algorithm/LAGraph_CFL_reachability_advanced.c index 5515c04cf1..0eaafcabfd 100644 --- a/experimental/algorithm/LAGraph_CFL_reachability_advanced.c +++ b/experimental/algorithm/LAGraph_CFL_reachability_advanced.c @@ -112,7 +112,8 @@ } GrB_Info matrix_apply_mask_i(GrB_Matrix matrix, GrB_Matrix mask, GrB_Index size) { - TRY(GrB_Matrix_apply(matrix, mask, GrB_NULL, GrB_IDENTITY_BOOL, matrix, GrB_DESC_SC)); + GrB_eWiseAdd(matrix, mask, GrB_NULL, GxB_ANY_BOOL, matrix, matrix, GrB_DESC_RSC); + IS_ISO(matrix, "RSUB RESULT"); } // LAGraph_CFL_reachability: Context-Free Language Reachability Matrix-Based Algorithm From 0433361083d53fe6c7f0d30b49dd13062289e845 Mon Sep 17 00:00:00 2001 From: Homka122 Date: Mon, 12 May 2025 07:38:58 +0300 Subject: [PATCH 011/122] Refactor: iteration info now print if flag set --- experimental/algorithm/LAGraph_CFL_reachability_advanced.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/experimental/algorithm/LAGraph_CFL_reachability_advanced.c b/experimental/algorithm/LAGraph_CFL_reachability_advanced.c index 0eaafcabfd..8b9cbcc476 100644 --- a/experimental/algorithm/LAGraph_CFL_reachability_advanced.c +++ b/experimental/algorithm/LAGraph_CFL_reachability_advanced.c @@ -389,7 +389,9 @@ GrB_Info LAGraph_CFL_reachability_adv( iteration++; changed = false; +#if BENCH_CFL_REACHBILITY printf("\n--- ITERATARION %ld ---\n", iteration); +#endif for (size_t i = 0; i < nonterms_count; i++) { GRB_TRY(GrB_Matrix_new(&temp_matrices[i], GrB_BOOL, n, n)); @@ -493,8 +495,10 @@ GrB_Info LAGraph_CFL_reachability_adv( #endif } +#if BENCH_CFL_REACHBILITY printf("MXM1: %.3f, wise1: %.3f, MXM2: %.3f, wise2: %.3f, rsub: %.3f", mxm1, wise1, mxm2, wise2, rsub); +#endif #ifdef DEBUG_CFL_REACHBILITY for (int32_t i = 0; i < nonterms_count; i++) { From 155e60981a49c94ce18013a12dfbaffab0ee78aa Mon Sep 17 00:00:00 2001 From: Homka122 Date: Mon, 12 May 2025 07:40:50 +0300 Subject: [PATCH 012/122] Feat: add null check in first mxm --- .../algorithm/LAGraph_CFL_reachability_advanced.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/experimental/algorithm/LAGraph_CFL_reachability_advanced.c b/experimental/algorithm/LAGraph_CFL_reachability_advanced.c index 8b9cbcc476..e6267c49f4 100644 --- a/experimental/algorithm/LAGraph_CFL_reachability_advanced.c +++ b/experimental/algorithm/LAGraph_CFL_reachability_advanced.c @@ -414,8 +414,17 @@ GrB_Info LAGraph_CFL_reachability_adv( matrices[bin_rule.prod_A], delta_matrices[bin_rule.prod_B], GrB_NULL)); SKIP_IF_NULL(res); - GrB_eWiseAdd(temp_matrices[bin_rule.nonterm], GrB_NULL, GrB_NULL, - GxB_ANY_BOOL, temp_matrices[bin_rule.nonterm], res, GrB_NULL); + IS_ISO(res, "MXM RES"); + + GrB_Index nnz; + GrB_Matrix_nvals(&nnz, temp_matrices[bin_rule.nonterm]); + if (nnz == 0) { + GrB_Matrix_dup(&temp_matrices[bin_rule.nonterm], res); + } else { + GrB_eWiseAdd(temp_matrices[bin_rule.nonterm], GrB_NULL, GrB_NULL, + GxB_ANY_BOOL, temp_matrices[bin_rule.nonterm], res, + GrB_NULL); + } IS_ISO(temp_matrices[bin_rule.nonterm], "ALERT"); IS_ISO(matrices[bin_rule.prod_A], "ALERT"); From 8dc7d1d8587195a11e744443674337a5494de604 Mon Sep 17 00:00:00 2001 From: Homka122 Date: Mon, 12 May 2025 12:18:24 +0300 Subject: [PATCH 013/122] Feat: now empty optimization is seperate --- .../LAGraph_CFL_reachability_advanced.c | 353 +++++++++++++----- 1 file changed, 263 insertions(+), 90 deletions(-) diff --git a/experimental/algorithm/LAGraph_CFL_reachability_advanced.c b/experimental/algorithm/LAGraph_CFL_reachability_advanced.c index e6267c49f4..e4c8f03ca5 100644 --- a/experimental/algorithm/LAGraph_CFL_reachability_advanced.c +++ b/experimental/algorithm/LAGraph_CFL_reachability_advanced.c @@ -90,10 +90,34 @@ *(accumulator) += (end_time - start_time); \ } \ } + + #define IS_ROW(matrix, str) \ + { \ + int32_t orientation; \ + GrB_get(matrix, &orientation, GrB_STORAGE_ORIENTATION_HINT); \ + if (orientation != GrB_ROWMAJOR) { \ + printf("-----NOT A ROW----- (%s)\n", str); \ + GxB_print(matrix, 1); \ + printf("-------------------\n"); \ + } \ + } + + #define IS_COL(matrix, str) \ + { \ + int32_t orientation; \ + GrB_get(matrix, &orientation, GrB_STORAGE_ORIENTATION_HINT); \ + if (orientation != GrB_COLMAJOR) { \ + printf("-----NOT A COL----- (%s)\n", str); \ + GxB_print(matrix, 1); \ + printf("-------------------\n"); \ + } \ + } #else #define IS_ISO(matrix, str) #define TIMER_START() #define TIMER_STOP(label, accumulator) + #define IS_ROW(matrix, str) + #define IS_COL(matrix, str) #endif // clang-format on @@ -103,6 +127,9 @@ continue; \ } +#define TO_COL(matrix) GrB_set(matrix, GrB_COLMAJOR, GrB_STORAGE_ORIENTATION_HINT) +#define TO_ROW(matrix) GrB_set(matrix, GrB_ROWMAJOR, GrB_STORAGE_ORIENTATION_HINT) + #define TRY(GrB_method) \ { \ GrB_Info LG_GrB_Info = GrB_method; \ @@ -111,16 +138,200 @@ } \ } -GrB_Info matrix_apply_mask_i(GrB_Matrix matrix, GrB_Matrix mask, GrB_Index size) { - GrB_eWiseAdd(matrix, mask, GrB_NULL, GxB_ANY_BOOL, matrix, matrix, GrB_DESC_RSC); - IS_ISO(matrix, "RSUB RESULT"); +typedef struct { + GrB_Matrix base; + GrB_Matrix base_col; + GrB_Index nvals; + GrB_Index size; + int32_t format; +} Matrix; + +void matrix_update(Matrix *matrix) { + GrB_Matrix_nvals(&matrix->nvals, matrix->base); + GrB_Matrix_nrows(&matrix->size, matrix->base); + GrB_get(matrix->base, &matrix->format, GrB_STORAGE_ORIENTATION_HINT); +} + +Matrix matrix_from_base(GrB_Matrix matrix) { + Matrix result; + result.base = matrix; + result.base_col = NULL; + result.nvals = 0; + result.size = 0; + result.format = GrB_ROWMAJOR; + matrix_update(&result); + return result; +} + +// void matrix_to_row(Matrix matrix) { +// if (matrix.base == NULL) { +// matrix.base = matrix.base_col; +// matrix.base_col = NULL; +// matrix.format = GrB_ROWMAJOR; +// TO_ROW(matrix.base); +// } +// } + +// void matrix_to_col(Matrix matrix) { +// if (matrix.base_col == NULL) { +// matrix.base_col = matrix.base; +// matrix.base = NULL; +// matrix.format = GrB_COLMAJOR; +// TO_COL(matrix.base_col); +// } +// } + +// void matrix_to_col_both(Matrix matrix) { +// if (matrix.base_col == NULL) { +// GrB_Matrix new_matrix; +// GrB_Matrix_new(&new_matrix, GrB_BOOL, matrix.size, matrix.size); +// TO_COL(new_matrix); +// matrix.base_col = new_matrix; +// matrix.format = GrB_BOTH; +// } +// } + +// GrB_Info matrix_apply_mask_i(GrB_Matrix matrix, GrB_Matrix mask, GrB_Index size) { +// GrB_eWiseAdd(matrix, mask, GrB_NULL, GxB_ANY_BOOL, matrix, matrix, GrB_DESC_RSC); +// IS_ISO(matrix, "RSUB RESULT"); +// } + +GrB_Info matrix_dup(Matrix output, Matrix input) { + // if (output.format == GrB_ROWMAJOR || output.format == GrB_BOTH) { + // matrix_to_row(input); + // GrB_Matrix_dup(&output.base, input.base); + // } + + // if (output.format == GrB_COLMAJOR || output.format == GrB_BOTH) { + // matrix_to_col(input); + // GrB_Matrix_dup(&output.base_col, input.base_col); + // } + + GrB_Matrix_assign(output.base, GrB_NULL, GrB_NULL, input.base, GrB_ALL, input.size, + GrB_ALL, input.size, GrB_NULL); + + // GrB_Matrix_dup(&output->base, input.base); +} + +GrB_Info matrix_mxm(Matrix output, Matrix first, Matrix second, bool accum) { + GrB_mxm(output.base, GrB_NULL, accum ? GxB_ANY_BOOL : NULL, GxB_ANY_PAIR_BOOL, + first.base, second.base, GrB_NULL); + IS_ISO(output.base, "MXM output"); +} + +// GrB_Info matrix_mxm_format(Matrix output, Matrix first, Matrix second, bool accum) { +// int32_t desired_orientation = +// first.nvals > second.nvals ? GrB_COLMAJOR : GrB_ROWMAJOR; + +// if (first.format == desired_orientation || first.format == GrB_BOTH) { +// GrB_set(second.base, desired_orientation, GrB_STORAGE_ORIENTATION_HINT); +// GrB_set(output.base, desired_orientation, GrB_STORAGE_ORIENTATION_HINT); +// return matrix_mxm(output, first, second, accum); +// } + +// if (first.nvals > second.nvals / 3.0) { +// matrix_to_col_both(first); +// matrix_to_row(second); +// matrix_to_row(output); +// return matrix_mxm(output, first, second, accum); +// } + +// return matrix_mxm(output, first, second, accum); +// } + +GrB_Info matrix_mxm_empty(Matrix output, Matrix first, Matrix second, bool accum) { + if (first.nvals == 0 || second.nvals == 0) + return GrB_SUCCESS; + + matrix_mxm(output, first, second, accum); +} + +GrB_Info matrix_wise(Matrix output, Matrix first, Matrix second, bool accum) { + GrB_BinaryOp accum_op = accum ? GxB_ANY_BOOL : GrB_NULL; + + return GrB_eWiseAdd(output.base, GrB_NULL, accum_op, GxB_ANY_BOOL, first.base, + second.base, GrB_NULL); +} + +GrB_Info matrix_wise_empty(Matrix output, Matrix first, Matrix second, bool accum) { + GrB_BinaryOp accum_op = accum ? GxB_ANY_BOOL : GrB_NULL; + + if (first.nvals == 0 && second.nvals == 0) { + if (accum) { + return GrB_SUCCESS; + } + + return GrB_Matrix_clear(output.base); + } + + if (first.nvals == 0) { + if (accum) { + return matrix_wise(output, output, second, false); + } + + return matrix_dup(output, second); + } + + if (second.nvals == 0) { + if (accum) { + return matrix_wise(output, output, first, false); + } + + return matrix_dup(output, first); + } + + return matrix_wise(output, first, second, accum); } +// GrB_Info matrix_wise_format(Matrix output, Matrix first, Matrix second, bool accum) { +// GrB_BinaryOp accum_op = accum ? GxB_ANY_BOOL : GrB_NULL; + +// if (first.format == GrB_ROWMAJOR || first.format == GrB_BOTH) { +// matrix_to_row(second); +// matrix_to_row(output); +// GrB_eWiseAdd(output.base, GrB_NULL, accum_op, GxB_ANY_BOOL, first.base, +// second.base, GrB_NULL); +// } + +// if (first.format == GrB_COLMAJOR || first.format == GrB_BOTH) { +// matrix_to_col(second); +// matrix_to_col(output); +// GrB_eWiseAdd(output.base_col, GrB_NULL, accum_op, GxB_ANY_BOOL, first.base_col, +// second.base_col, GrB_NULL); +// } + +// return GrB_SUCCESS; +// } + +GrB_Info matrix_rsub(Matrix output, Matrix mask) { + GrB_eWiseAdd(output.base, mask.base, GrB_NULL, GxB_ANY_BOOL, output.base, output.base, + GrB_DESC_RSC); +} + +GrB_Info matrix_rsub_empty(Matrix output, Matrix mask) { + if (mask.nvals == 0 || output.nvals == 0) { + return GrB_SUCCESS; + } + + return matrix_rsub(output, mask); +} + +// GrB_Info matrix_wise(Matrix output, Matrix first, Matrix second, bool accum) { +// GrB_eWiseAdd(output.base, GrB_NULL, GrB_NULL, GxB_ANY_BOOL, matrices[i].base, +// delta_matrices[i].base, GrB_NULL); +// } + +// GrB_Info matrix_mxm_format(GrB_Matrix output, GrB_Matrix first, GrB_Matrix second) +// { + +// } + // LAGraph_CFL_reachability: Context-Free Language Reachability Matrix-Based Algorithm // // This function determines the set of vertex pairs (u, v) in a graph (represented by -// adjacency matrices) such that there is a path from u to v, where the edge labels form a -// word from the language generated by the context-free grammar (represented by `rules`). +// adjacency matrices) such that there is a path from u to v, where the edge labels +// form a word from the language generated by the context-free grammar (represented by +// `rules`). // // Terminals and non-terminals are enumerated by integers starting from zero. // The start non-terminal is the non-terminal with index 0. @@ -138,14 +349,14 @@ GrB_Info matrix_apply_mask_i(GrB_Matrix matrix, GrB_Matrix mask, GrB_Index size) // // Grammar: S -> aSb | ab // -// There are paths from node [1] to node [3] and from node [1] to node [2] that form the -// word "ab" ([1]-a->[2]-b->[3] and [1]-a->[5]-b->[2]). The word "ab" is in the language -// generated by our context-free grammar, so the pairs (1, 3) and (1, 2) will be included -// in the result. +// There are paths from node [1] to node [3] and from node [1] to node [2] that form +// the word "ab" ([1]-a->[2]-b->[3] and [1]-a->[5]-b->[2]). The word "ab" is in the +// language generated by our context-free grammar, so the pairs (1, 3) and (1, 2) will +// be included in the result. // -// Note: It doesn't matter how many paths exist from node [A] to node [B] that form a word -// in the language. If at least one path exists, the pair ([A], [B]) will be included in -// the result. +// Note: It doesn't matter how many paths exist from node [A] to node [B] that form a +// word in the language. If at least one path exists, the pair ([A], [B]) will be +// included in the result. // // In contrast, the path from node [1] to node [4] forms the word "abb" // ([1]-a->[2]-b->[3]-b->[4]) and the word "abbb" ([1]-a->[5]-b->[2]-b->[3]-b->[4]). @@ -182,9 +393,9 @@ GrB_Info LAGraph_CFL_reachability_adv( ) { // Declare workspace and clear the msg string, if not NULL GrB_Matrix *T; - GrB_Matrix *delta_matrices; - GrB_Matrix *matrices; - GrB_Matrix *temp_matrices; + Matrix *delta_matrices; + Matrix *matrices; + Matrix *temp_matrices; bool t_empty_flags[nonterms_count]; // t_empty_flags[i] == true <=> T[i] is empty GrB_Matrix identity_matrix = NULL; uint64_t *nnzs = NULL; @@ -198,11 +409,9 @@ GrB_Info LAGraph_CFL_reachability_adv( GrB_Scalar_setElement_BOOL(true_scalar, true); LG_TRY(LAGraph_Calloc((void **)&T, nonterms_count, sizeof(GrB_Matrix), msg)); - LG_TRY(LAGraph_Calloc((void **)&delta_matrices, nonterms_count, sizeof(GrB_Matrix), - msg)); - LG_TRY(LAGraph_Calloc((void **)&matrices, nonterms_count, sizeof(GrB_Matrix), msg)); - LG_TRY( - LAGraph_Calloc((void **)&temp_matrices, nonterms_count, sizeof(GrB_Matrix), msg)); + LG_TRY(LAGraph_Calloc((void **)&delta_matrices, nonterms_count, sizeof(Matrix), msg)); + LG_TRY(LAGraph_Calloc((void **)&matrices, nonterms_count, sizeof(Matrix), msg)); + LG_TRY(LAGraph_Calloc((void **)&temp_matrices, nonterms_count, sizeof(Matrix), msg)); LG_ASSERT_MSG(terms_count > 0, GrB_INVALID_VALUE, "The number of terminals must be greater than zero."); @@ -241,10 +450,19 @@ GrB_Info LAGraph_CFL_reachability_adv( // Create nonterms matrices for (int32_t i = 0; i < nonterms_count; i++) { + GrB_Matrix matrix; + GRB_TRY(GrB_Matrix_new(&T[i], GrB_BOOL, n, n)); - GRB_TRY(GrB_Matrix_new(&delta_matrices[i], GrB_BOOL, n, n)); - GRB_TRY(GrB_Matrix_new(&matrices[i], GrB_BOOL, n, n)); - GRB_TRY(GrB_Matrix_new(&temp_matrices[i], GrB_BOOL, n, n)); + + GRB_TRY(GrB_Matrix_new(&matrix, GrB_BOOL, n, n)); + delta_matrices[i] = matrix_from_base(matrix); + + GRB_TRY(GrB_Matrix_new(&matrix, GrB_BOOL, n, n)); + matrices[i] = matrix_from_base(matrix); + + GRB_TRY(GrB_Matrix_new(&matrix, GrB_BOOL, n, n)); + temp_matrices[i] = matrix_from_base(matrix); + t_empty_flags[i] = true; } @@ -339,9 +557,10 @@ GrB_Info LAGraph_CFL_reachability_adv( continue; } - GxB_eWiseUnion(delta_matrices[term_rule.nonterm], GrB_NULL, GrB_NULL, - GxB_PAIR_BOOL, delta_matrices[term_rule.nonterm], true_scalar, + GxB_eWiseUnion(delta_matrices[term_rule.nonterm].base, GrB_NULL, GrB_NULL, + GxB_PAIR_BOOL, delta_matrices[term_rule.nonterm].base, true_scalar, adj_matrices[term_rule.prod_A], true_scalar, GrB_NULL); + matrix_update(&delta_matrices[term_rule.nonterm]); t_empty_flags[term_rule.nonterm] = false; @@ -361,9 +580,10 @@ GrB_Info LAGraph_CFL_reachability_adv( for (size_t i = 0; i < eps_rules_count; i++) { LAGraph_rule_WCNF eps_rule = rules[eps_rules[i]]; - GxB_eWiseUnion(delta_matrices[eps_rule.nonterm], GrB_NULL, GxB_PAIR_BOOL, - GxB_PAIR_BOOL, delta_matrices[eps_rule.nonterm], true_scalar, + GxB_eWiseUnion(delta_matrices[eps_rule.nonterm].base, GrB_NULL, GxB_PAIR_BOOL, + GxB_PAIR_BOOL, delta_matrices[eps_rule.nonterm].base, true_scalar, identity_matrix, true_scalar, GrB_NULL); + matrix_update(&delta_matrices[eps_rule.nonterm]); t_empty_flags[eps_rule.nonterm] = false; @@ -394,59 +614,24 @@ GrB_Info LAGraph_CFL_reachability_adv( #endif for (size_t i = 0; i < nonterms_count; i++) { - GRB_TRY(GrB_Matrix_new(&temp_matrices[i], GrB_BOOL, n, n)); + GRB_TRY(GrB_Matrix_clear(temp_matrices[i].base)); + matrix_update(&temp_matrices[i]); } TIMER_START(); for (size_t i = 0; i < bin_rules_count; i++) { LAGraph_rule_WCNF bin_rule = rules[bin_rules[i]]; - SKIP_IF_NULL(matrices[bin_rule.prod_A]); - SKIP_IF_NULL(delta_matrices[bin_rule.prod_B]); - - GrB_Index left_nnz; - GrB_Index right_nnz; - - GrB_Matrix res; - GrB_Matrix_new(&res, GrB_BOOL, n, n); - - GRB_TRY(GrB_mxm(res, GrB_NULL, GrB_NULL, GxB_ANY_PAIR_BOOL, - matrices[bin_rule.prod_A], delta_matrices[bin_rule.prod_B], - GrB_NULL)); - SKIP_IF_NULL(res); - IS_ISO(res, "MXM RES"); - - GrB_Index nnz; - GrB_Matrix_nvals(&nnz, temp_matrices[bin_rule.nonterm]); - if (nnz == 0) { - GrB_Matrix_dup(&temp_matrices[bin_rule.nonterm], res); - } else { - GrB_eWiseAdd(temp_matrices[bin_rule.nonterm], GrB_NULL, GrB_NULL, - GxB_ANY_BOOL, temp_matrices[bin_rule.nonterm], res, - GrB_NULL); - } - - IS_ISO(temp_matrices[bin_rule.nonterm], "ALERT"); - IS_ISO(matrices[bin_rule.prod_A], "ALERT"); - IS_ISO(delta_matrices[bin_rule.prod_B], "ALERT"); + matrix_mxm_empty(temp_matrices[bin_rule.nonterm], matrices[bin_rule.prod_A], + delta_matrices[bin_rule.prod_B], false); + matrix_update(&temp_matrices[bin_rule.nonterm]); } TIMER_STOP("MXM 1", &mxm1); TIMER_START() for (size_t i = 0; i < nonterms_count; i++) { - SKIP_IF_NULL(delta_matrices[i]); - - GrB_Matrix_nvals(&new_nnz, matrices[i]); - if (new_nnz == 0) { - GrB_Matrix_dup(&matrices[i], delta_matrices[i]); - IS_ISO(matrices[i], "ALERT WISE 1"); - continue; - } - - GrB_eWiseAdd(matrices[i], GrB_NULL, GrB_NULL, GxB_ANY_BOOL, matrices[i], - delta_matrices[i], GrB_NULL); - - IS_ISO(matrices[i], "ALERT WISE 1"); + matrix_wise_empty(matrices[i], matrices[i], delta_matrices[i], false); + matrix_update(&matrices[i]); } TIMER_STOP("WISE 1", &wise1); @@ -454,41 +639,29 @@ GrB_Info LAGraph_CFL_reachability_adv( for (size_t i = 0; i < bin_rules_count; i++) { LAGraph_rule_WCNF bin_rule = rules[bin_rules[i]]; - SKIP_IF_NULL(delta_matrices[bin_rule.prod_A]); - SKIP_IF_NULL(matrices[bin_rule.prod_B]); - - GRB_TRY(GrB_mxm(temp_matrices[bin_rule.nonterm], GrB_NULL, GxB_ANY_BOOL, - GxB_ANY_PAIR_BOOL, delta_matrices[bin_rule.prod_A], - matrices[bin_rule.prod_B], GrB_NULL)) + matrix_mxm_empty(temp_matrices[bin_rule.nonterm], + delta_matrices[bin_rule.prod_A], matrices[bin_rule.prod_B], + true); + matrix_update(&temp_matrices[bin_rule.nonterm]); } TIMER_STOP("MXM 2", &mxm2); TIMER_START(); for (size_t i = 0; i < nonterms_count; i++) { - GrB_Matrix_new(&delta_matrices[i], GrB_BOOL, n, n); - SKIP_IF_NULL(temp_matrices[i]); - - GrB_Matrix_apply(delta_matrices[i], GrB_NULL, GrB_NULL, GrB_IDENTITY_BOOL, - temp_matrices[i], GrB_NULL); - - IS_ISO(delta_matrices[i], "WISE 2"); + matrix_dup(delta_matrices[i], temp_matrices[i]); } TIMER_STOP("WISE 2 (copy)", &wise2); TIMER_START(); for (size_t i = 0; i < nonterms_count; i++) { - SKIP_IF_NULL(delta_matrices[i]); - SKIP_IF_NULL(matrices[i]); - - GRB_TRY(matrix_apply_mask_i(delta_matrices[i], matrices[i], n)); - - IS_ISO(delta_matrices[i], "WISE 3"); + matrix_rsub_empty(delta_matrices[i], matrices[i]); + matrix_update(&delta_matrices[i]); } TIMER_STOP("WISE 3 (MASK)", &rsub); for (size_t i = 0; i < nonterms_count; i++) { GrB_Index new_nnz; - GRB_TRY(GrB_Matrix_nvals(&new_nnz, matrices[i])); + GRB_TRY(GrB_Matrix_nvals(&new_nnz, matrices[i].base)); if (new_nnz != 0) t_empty_flags[i] = false; @@ -517,7 +690,7 @@ GrB_Info LAGraph_CFL_reachability_adv( #endif for (int32_t i = 0; i < nonterms_count; i++) { - outputs[i] = matrices[i]; + outputs[i] = matrices[i].base; } LG_FREE_WORK; From 08ab76c9cb939dd6098fc6fa4311407f65bc4ec6 Mon Sep 17 00:00:00 2001 From: Homka122 Date: Mon, 12 May 2025 13:44:10 +0300 Subject: [PATCH 014/122] Feat: add rsub, wise and dup with format optimization --- .../LAGraph_CFL_reachability_advanced.c | 96 ++++++++++++++++--- 1 file changed, 85 insertions(+), 11 deletions(-) diff --git a/experimental/algorithm/LAGraph_CFL_reachability_advanced.c b/experimental/algorithm/LAGraph_CFL_reachability_advanced.c index e4c8f03ca5..277111e779 100644 --- a/experimental/algorithm/LAGraph_CFL_reachability_advanced.c +++ b/experimental/algorithm/LAGraph_CFL_reachability_advanced.c @@ -140,6 +140,7 @@ typedef struct { GrB_Matrix base; + GrB_Matrix base_row; GrB_Matrix base_col; GrB_Index nvals; GrB_Index size; @@ -155,6 +156,7 @@ void matrix_update(Matrix *matrix) { Matrix matrix_from_base(GrB_Matrix matrix) { Matrix result; result.base = matrix; + result.base_row = matrix; result.base_col = NULL; result.nvals = 0; result.size = 0; @@ -163,14 +165,39 @@ Matrix matrix_from_base(GrB_Matrix matrix) { return result; } -// void matrix_to_row(Matrix matrix) { -// if (matrix.base == NULL) { -// matrix.base = matrix.base_col; -// matrix.base_col = NULL; -// matrix.format = GrB_ROWMAJOR; -// TO_ROW(matrix.base); -// } -// } +void matrix_to_row(Matrix *matrix) { + if (matrix->format == GrB_ROWMAJOR) { + return; + } + + if (matrix->format == GrB_BOTH) { + matrix->base = matrix->base_row; + return; + } + + matrix->format = GrB_ROWMAJOR; + matrix->base_row = matrix->base_col; + matrix->base_col = NULL; + TO_ROW(matrix->base_row); + matrix->base = matrix->base_row; +} + +void matrix_to_col(Matrix *matrix) { + if (matrix->format == GrB_COLMAJOR) { + return; + } + + if (matrix->format == GrB_BOTH) { + matrix->base = matrix->base_col; + return; + } + + matrix->format = GrB_COLMAJOR; + matrix->base_col = matrix->base_row; + matrix->base_row = NULL; + TO_COL(matrix->base_col); + matrix->base = matrix->base_col; +} // void matrix_to_col(Matrix matrix) { // if (matrix.base_col == NULL) { @@ -213,6 +240,18 @@ GrB_Info matrix_dup(Matrix output, Matrix input) { // GrB_Matrix_dup(&output->base, input.base); } +GrB_Info matrix_dup_format(Matrix output, Matrix input) { + return matrix_dup(output, input); +} + +GrB_Info matrix_dup_empty(Matrix output, Matrix input) { + if (input.nvals == 0) { + return GrB_Matrix_clear(output.base); + } + + return matrix_dup_format(output, input); +} + GrB_Info matrix_mxm(Matrix output, Matrix first, Matrix second, bool accum) { GrB_mxm(output.base, GrB_NULL, accum ? GxB_ANY_BOOL : NULL, GxB_ANY_PAIR_BOOL, first.base, second.base, GrB_NULL); @@ -253,6 +292,29 @@ GrB_Info matrix_wise(Matrix output, Matrix first, Matrix second, bool accum) { second.base, GrB_NULL); } +GrB_Info matrix_wise_format(Matrix output, Matrix first, Matrix second, bool accum) { + GrB_BinaryOp accum_op = accum ? GxB_ANY_BOOL : GrB_NULL; + GrB_Info result; + + if (first.format == GrB_ROWMAJOR || first.format == GrB_BOTH) { + matrix_to_row(&second); + matrix_to_row(&output); + result = matrix_wise(output, first, second, accum); + } + + if (result < GrB_SUCCESS) { + return result; + } + + if (first.format == GrB_COLMAJOR || first.format == GrB_BOTH) { + matrix_to_col(&second); + matrix_to_col(&output); + result = matrix_wise(output, first, second, accum); + } + + return result; +} + GrB_Info matrix_wise_empty(Matrix output, Matrix first, Matrix second, bool accum) { GrB_BinaryOp accum_op = accum ? GxB_ANY_BOOL : GrB_NULL; @@ -280,7 +342,7 @@ GrB_Info matrix_wise_empty(Matrix output, Matrix first, Matrix second, bool accu return matrix_dup(output, first); } - return matrix_wise(output, first, second, accum); + return matrix_wise_format(output, first, second, accum); } // GrB_Info matrix_wise_format(Matrix output, Matrix first, Matrix second, bool accum) { @@ -308,12 +370,24 @@ GrB_Info matrix_rsub(Matrix output, Matrix mask) { GrB_DESC_RSC); } +GrB_Info matrix_rsub_format(Matrix output, Matrix mask) { + if (mask.format == GrB_ROWMAJOR) { + matrix_to_row(&output); + matrix_to_row(&mask); + return matrix_rsub(output, mask); + } + + matrix_to_col(&output); + matrix_to_col(&mask); + return matrix_rsub(output, mask); +} + GrB_Info matrix_rsub_empty(Matrix output, Matrix mask) { if (mask.nvals == 0 || output.nvals == 0) { return GrB_SUCCESS; } - return matrix_rsub(output, mask); + return matrix_rsub_format(output, mask); } // GrB_Info matrix_wise(Matrix output, Matrix first, Matrix second, bool accum) { @@ -648,7 +722,7 @@ GrB_Info LAGraph_CFL_reachability_adv( TIMER_START(); for (size_t i = 0; i < nonterms_count; i++) { - matrix_dup(delta_matrices[i], temp_matrices[i]); + matrix_dup_empty(delta_matrices[i], temp_matrices[i]); } TIMER_STOP("WISE 2 (copy)", &wise2); From 4668c88def342f2da2d5b170e27212c143eb270b Mon Sep 17 00:00:00 2001 From: Homka122 Date: Wed, 14 May 2025 09:08:15 +0300 Subject: [PATCH 015/122] Feat: add mxm format optimization --- .../LAGraph_CFL_reachability_advanced.c | 226 +++++++++++------- 1 file changed, 146 insertions(+), 80 deletions(-) diff --git a/experimental/algorithm/LAGraph_CFL_reachability_advanced.c b/experimental/algorithm/LAGraph_CFL_reachability_advanced.c index 277111e779..4d33fd0453 100644 --- a/experimental/algorithm/LAGraph_CFL_reachability_advanced.c +++ b/experimental/algorithm/LAGraph_CFL_reachability_advanced.c @@ -199,31 +199,54 @@ void matrix_to_col(Matrix *matrix) { matrix->base = matrix->base_col; } -// void matrix_to_col(Matrix matrix) { -// if (matrix.base_col == NULL) { -// matrix.base_col = matrix.base; -// matrix.base = NULL; -// matrix.format = GrB_COLMAJOR; -// TO_COL(matrix.base_col); -// } -// } +void matrix_to_col_both(Matrix *matrix) { + if (matrix->format == GrB_BOTH) { + matrix->base = matrix->base_col; + return; + } -// void matrix_to_col_both(Matrix matrix) { -// if (matrix.base_col == NULL) { -// GrB_Matrix new_matrix; -// GrB_Matrix_new(&new_matrix, GrB_BOOL, matrix.size, matrix.size); -// TO_COL(new_matrix); -// matrix.base_col = new_matrix; -// matrix.format = GrB_BOTH; -// } -// } + if (matrix->format == GrB_COLMAJOR) { + return; + } + + if (matrix->format == GrB_ROWMAJOR) { + GrB_Matrix new_matrix; + GrB_Matrix_new(&new_matrix, GrB_BOOL, matrix->size, matrix->size); + TO_COL(new_matrix); + matrix->base_col = new_matrix; + matrix->base = matrix->base_col; + matrix->format = GrB_BOTH; + return; + } +} + +void matrix_to_row_both(Matrix *matrix) { + if (matrix->format == GrB_BOTH) { + matrix->base = matrix->base_row; + return; + } + + if (matrix->format == GrB_ROWMAJOR) { + return; + } + + if (matrix->format == GrB_COLMAJOR) { + GrB_Matrix new_matrix; + GrB_Matrix_new(&new_matrix, GrB_BOOL, matrix->size, matrix->size); + TO_ROW(new_matrix); + matrix->base_row = new_matrix; + matrix->base = matrix->base_row; + matrix->format = GrB_BOTH; + return; + } +} // GrB_Info matrix_apply_mask_i(GrB_Matrix matrix, GrB_Matrix mask, GrB_Index size) { // GrB_eWiseAdd(matrix, mask, GrB_NULL, GxB_ANY_BOOL, matrix, matrix, GrB_DESC_RSC); // IS_ISO(matrix, "RSUB RESULT"); // } -GrB_Info matrix_dup(Matrix output, Matrix input) { +GrB_Info matrix_dup(Matrix *output, Matrix *input) { // if (output.format == GrB_ROWMAJOR || output.format == GrB_BOTH) { // matrix_to_row(input); // GrB_Matrix_dup(&output.base, input.base); @@ -234,71 +257,114 @@ GrB_Info matrix_dup(Matrix output, Matrix input) { // GrB_Matrix_dup(&output.base_col, input.base_col); // } - GrB_Matrix_assign(output.base, GrB_NULL, GrB_NULL, input.base, GrB_ALL, input.size, - GrB_ALL, input.size, GrB_NULL); + GrB_Matrix_assign(output->base, GrB_NULL, GrB_NULL, input->base, GrB_ALL, input->size, + GrB_ALL, input->size, GrB_NULL); // GrB_Matrix_dup(&output->base, input.base); } -GrB_Info matrix_dup_format(Matrix output, Matrix input) { +GrB_Info matrix_dup_format(Matrix *output, Matrix *input) { return matrix_dup(output, input); } -GrB_Info matrix_dup_empty(Matrix output, Matrix input) { - if (input.nvals == 0) { - return GrB_Matrix_clear(output.base); +GrB_Info matrix_dup_empty(Matrix *output, Matrix *input) { + if (input->nvals == 0) { + return GrB_Matrix_clear(output->base); } return matrix_dup_format(output, input); } -GrB_Info matrix_mxm(Matrix output, Matrix first, Matrix second, bool accum) { - GrB_mxm(output.base, GrB_NULL, accum ? GxB_ANY_BOOL : NULL, GxB_ANY_PAIR_BOOL, - first.base, second.base, GrB_NULL); - IS_ISO(output.base, "MXM output"); +GrB_Info matrix_mxm(Matrix *output, Matrix *first, Matrix *second, bool accum) { + GrB_mxm(output->base, GrB_NULL, accum ? GxB_ANY_BOOL : NULL, GxB_ANY_PAIR_BOOL, + first->base, second->base, GrB_NULL); + IS_ISO(output->base, "MXM output"); } -// GrB_Info matrix_mxm_format(Matrix output, Matrix first, Matrix second, bool accum) { -// int32_t desired_orientation = -// first.nvals > second.nvals ? GrB_COLMAJOR : GrB_ROWMAJOR; +GrB_Info matrix_mxm_format(Matrix *output, Matrix *first, Matrix *second, bool accum) { + int32_t desired_orientation = + first->nvals > second->nvals ? GrB_COLMAJOR : GrB_ROWMAJOR; -// if (first.format == desired_orientation || first.format == GrB_BOTH) { -// GrB_set(second.base, desired_orientation, GrB_STORAGE_ORIENTATION_HINT); -// GrB_set(output.base, desired_orientation, GrB_STORAGE_ORIENTATION_HINT); -// return matrix_mxm(output, first, second, accum); -// } + if (first->format == desired_orientation || first->format == GrB_BOTH) { + if (desired_orientation == GrB_COLMAJOR) { + matrix_to_col(second); + matrix_to_col(output); + return matrix_mxm(output, first, second, accum); + } else { + matrix_to_row(second); + matrix_to_row(output); + return matrix_mxm(output, first, second, accum); + } + } -// if (first.nvals > second.nvals / 3.0) { -// matrix_to_col_both(first); -// matrix_to_row(second); -// matrix_to_row(output); -// return matrix_mxm(output, first, second, accum); -// } + if (first->nvals > second->nvals / 3.0) { + matrix_to_col_both(first); + matrix_to_row(second); + matrix_to_row(output); + return matrix_mxm(output, first, second, accum); + } -// return matrix_mxm(output, first, second, accum); -// } + return matrix_mxm(output, first, second, accum); +} + +GrB_Info matrix_rmxm_format(Matrix *output, Matrix *first, Matrix *second, bool accum) { + Matrix *temp = first; + second = first; + first = temp; + + int32_t desired_orientation = + first->nvals > second->nvals ? GrB_ROWMAJOR : GrB_COLMAJOR; + + if (first->format == desired_orientation || first->format == GrB_BOTH) { + if (desired_orientation == GrB_COLMAJOR) { + matrix_to_row(second); + matrix_to_row(output); + return matrix_mxm(output, first, second, accum); + } else { + matrix_to_col(second); + matrix_to_col(output); + return matrix_mxm(output, first, second, accum); + } + } + + if (first->nvals > second->nvals / 3.0) { + matrix_to_row_both(first); + matrix_to_col(second); + matrix_to_col(output); + return matrix_mxm(output, first, second, accum); + } + + return matrix_mxm(output, first, second, accum); +} + +GrB_Info matrix_mxm_empty(Matrix *output, Matrix *first, Matrix *second, bool accum) { + if (first->nvals == 0 || second->nvals == 0) + return GrB_SUCCESS; + + matrix_mxm_format(output, first, second, accum); +} -GrB_Info matrix_mxm_empty(Matrix output, Matrix first, Matrix second, bool accum) { - if (first.nvals == 0 || second.nvals == 0) +GrB_Info matrix_rmxm_empty(Matrix *output, Matrix *first, Matrix *second, bool accum) { + if (first->nvals == 0 || second->nvals == 0) return GrB_SUCCESS; - matrix_mxm(output, first, second, accum); + matrix_rmxm_format(output, first, second, accum); } -GrB_Info matrix_wise(Matrix output, Matrix first, Matrix second, bool accum) { +GrB_Info matrix_wise(Matrix *output, Matrix *first, Matrix *second, bool accum) { GrB_BinaryOp accum_op = accum ? GxB_ANY_BOOL : GrB_NULL; - return GrB_eWiseAdd(output.base, GrB_NULL, accum_op, GxB_ANY_BOOL, first.base, - second.base, GrB_NULL); + return GrB_eWiseAdd(output->base, GrB_NULL, accum_op, GxB_ANY_BOOL, first->base, + second->base, GrB_NULL); } -GrB_Info matrix_wise_format(Matrix output, Matrix first, Matrix second, bool accum) { +GrB_Info matrix_wise_format(Matrix *output, Matrix *first, Matrix *second, bool accum) { GrB_BinaryOp accum_op = accum ? GxB_ANY_BOOL : GrB_NULL; GrB_Info result; - if (first.format == GrB_ROWMAJOR || first.format == GrB_BOTH) { - matrix_to_row(&second); - matrix_to_row(&output); + if (first->format == GrB_ROWMAJOR || first->format == GrB_BOTH) { + matrix_to_row(second); + matrix_to_row(output); result = matrix_wise(output, first, second, accum); } @@ -306,27 +372,27 @@ GrB_Info matrix_wise_format(Matrix output, Matrix first, Matrix second, bool acc return result; } - if (first.format == GrB_COLMAJOR || first.format == GrB_BOTH) { - matrix_to_col(&second); - matrix_to_col(&output); + if (first->format == GrB_COLMAJOR || first->format == GrB_BOTH) { + matrix_to_col(second); + matrix_to_col(output); result = matrix_wise(output, first, second, accum); } return result; } -GrB_Info matrix_wise_empty(Matrix output, Matrix first, Matrix second, bool accum) { +GrB_Info matrix_wise_empty(Matrix *output, Matrix *first, Matrix *second, bool accum) { GrB_BinaryOp accum_op = accum ? GxB_ANY_BOOL : GrB_NULL; - if (first.nvals == 0 && second.nvals == 0) { + if (first->nvals == 0 && second->nvals == 0) { if (accum) { return GrB_SUCCESS; } - return GrB_Matrix_clear(output.base); + return GrB_Matrix_clear(output->base); } - if (first.nvals == 0) { + if (first->nvals == 0) { if (accum) { return matrix_wise(output, output, second, false); } @@ -334,7 +400,7 @@ GrB_Info matrix_wise_empty(Matrix output, Matrix first, Matrix second, bool accu return matrix_dup(output, second); } - if (second.nvals == 0) { + if (second->nvals == 0) { if (accum) { return matrix_wise(output, output, first, false); } @@ -365,25 +431,25 @@ GrB_Info matrix_wise_empty(Matrix output, Matrix first, Matrix second, bool accu // return GrB_SUCCESS; // } -GrB_Info matrix_rsub(Matrix output, Matrix mask) { - GrB_eWiseAdd(output.base, mask.base, GrB_NULL, GxB_ANY_BOOL, output.base, output.base, - GrB_DESC_RSC); +GrB_Info matrix_rsub(Matrix *output, Matrix *mask) { + return GrB_eWiseAdd(output->base, mask->base, GrB_NULL, GxB_ANY_BOOL, output->base, + output->base, GrB_DESC_RSC); } -GrB_Info matrix_rsub_format(Matrix output, Matrix mask) { - if (mask.format == GrB_ROWMAJOR) { - matrix_to_row(&output); - matrix_to_row(&mask); +GrB_Info matrix_rsub_format(Matrix *output, Matrix *mask) { + if (mask->format == GrB_ROWMAJOR) { + matrix_to_row(output); + matrix_to_row(mask); return matrix_rsub(output, mask); } - matrix_to_col(&output); - matrix_to_col(&mask); + matrix_to_col(output); + matrix_to_col(mask); return matrix_rsub(output, mask); } -GrB_Info matrix_rsub_empty(Matrix output, Matrix mask) { - if (mask.nvals == 0 || output.nvals == 0) { +GrB_Info matrix_rsub_empty(Matrix *output, Matrix *mask) { + if (mask->nvals == 0 || output->nvals == 0) { return GrB_SUCCESS; } @@ -696,15 +762,15 @@ GrB_Info LAGraph_CFL_reachability_adv( for (size_t i = 0; i < bin_rules_count; i++) { LAGraph_rule_WCNF bin_rule = rules[bin_rules[i]]; - matrix_mxm_empty(temp_matrices[bin_rule.nonterm], matrices[bin_rule.prod_A], - delta_matrices[bin_rule.prod_B], false); + matrix_mxm(&temp_matrices[bin_rule.nonterm], &matrices[bin_rule.prod_A], + &delta_matrices[bin_rule.prod_B], false); matrix_update(&temp_matrices[bin_rule.nonterm]); } TIMER_STOP("MXM 1", &mxm1); TIMER_START() for (size_t i = 0; i < nonterms_count; i++) { - matrix_wise_empty(matrices[i], matrices[i], delta_matrices[i], false); + matrix_wise_empty(&matrices[i], &matrices[i], &delta_matrices[i], false); matrix_update(&matrices[i]); } TIMER_STOP("WISE 1", &wise1); @@ -713,8 +779,8 @@ GrB_Info LAGraph_CFL_reachability_adv( for (size_t i = 0; i < bin_rules_count; i++) { LAGraph_rule_WCNF bin_rule = rules[bin_rules[i]]; - matrix_mxm_empty(temp_matrices[bin_rule.nonterm], - delta_matrices[bin_rule.prod_A], matrices[bin_rule.prod_B], + matrix_mxm_empty(&temp_matrices[bin_rule.nonterm], + &delta_matrices[bin_rule.prod_A], &matrices[bin_rule.prod_B], true); matrix_update(&temp_matrices[bin_rule.nonterm]); } @@ -722,13 +788,13 @@ GrB_Info LAGraph_CFL_reachability_adv( TIMER_START(); for (size_t i = 0; i < nonterms_count; i++) { - matrix_dup_empty(delta_matrices[i], temp_matrices[i]); + matrix_dup_empty(&delta_matrices[i], &temp_matrices[i]); } TIMER_STOP("WISE 2 (copy)", &wise2); TIMER_START(); for (size_t i = 0; i < nonterms_count; i++) { - matrix_rsub_empty(delta_matrices[i], matrices[i]); + matrix_rsub_empty(&delta_matrices[i], &matrices[i]); matrix_update(&delta_matrices[i]); } TIMER_STOP("WISE 3 (MASK)", &rsub); From 45aaf82d55fb8d5e3c233f0afdcd58d733f32ab2 Mon Sep 17 00:00:00 2001 From: Homka122 Date: Wed, 14 May 2025 09:09:51 +0300 Subject: [PATCH 016/122] Refactor: delete unused comments --- .../LAGraph_CFL_reachability_advanced.c | 37 ------------------- 1 file changed, 37 deletions(-) diff --git a/experimental/algorithm/LAGraph_CFL_reachability_advanced.c b/experimental/algorithm/LAGraph_CFL_reachability_advanced.c index 4d33fd0453..8823fb8b46 100644 --- a/experimental/algorithm/LAGraph_CFL_reachability_advanced.c +++ b/experimental/algorithm/LAGraph_CFL_reachability_advanced.c @@ -241,11 +241,6 @@ void matrix_to_row_both(Matrix *matrix) { } } -// GrB_Info matrix_apply_mask_i(GrB_Matrix matrix, GrB_Matrix mask, GrB_Index size) { -// GrB_eWiseAdd(matrix, mask, GrB_NULL, GxB_ANY_BOOL, matrix, matrix, GrB_DESC_RSC); -// IS_ISO(matrix, "RSUB RESULT"); -// } - GrB_Info matrix_dup(Matrix *output, Matrix *input) { // if (output.format == GrB_ROWMAJOR || output.format == GrB_BOTH) { // matrix_to_row(input); @@ -259,8 +254,6 @@ GrB_Info matrix_dup(Matrix *output, Matrix *input) { GrB_Matrix_assign(output->base, GrB_NULL, GrB_NULL, input->base, GrB_ALL, input->size, GrB_ALL, input->size, GrB_NULL); - - // GrB_Matrix_dup(&output->base, input.base); } GrB_Info matrix_dup_format(Matrix *output, Matrix *input) { @@ -411,26 +404,6 @@ GrB_Info matrix_wise_empty(Matrix *output, Matrix *first, Matrix *second, bool a return matrix_wise_format(output, first, second, accum); } -// GrB_Info matrix_wise_format(Matrix output, Matrix first, Matrix second, bool accum) { -// GrB_BinaryOp accum_op = accum ? GxB_ANY_BOOL : GrB_NULL; - -// if (first.format == GrB_ROWMAJOR || first.format == GrB_BOTH) { -// matrix_to_row(second); -// matrix_to_row(output); -// GrB_eWiseAdd(output.base, GrB_NULL, accum_op, GxB_ANY_BOOL, first.base, -// second.base, GrB_NULL); -// } - -// if (first.format == GrB_COLMAJOR || first.format == GrB_BOTH) { -// matrix_to_col(second); -// matrix_to_col(output); -// GrB_eWiseAdd(output.base_col, GrB_NULL, accum_op, GxB_ANY_BOOL, first.base_col, -// second.base_col, GrB_NULL); -// } - -// return GrB_SUCCESS; -// } - GrB_Info matrix_rsub(Matrix *output, Matrix *mask) { return GrB_eWiseAdd(output->base, mask->base, GrB_NULL, GxB_ANY_BOOL, output->base, output->base, GrB_DESC_RSC); @@ -456,16 +429,6 @@ GrB_Info matrix_rsub_empty(Matrix *output, Matrix *mask) { return matrix_rsub_format(output, mask); } -// GrB_Info matrix_wise(Matrix output, Matrix first, Matrix second, bool accum) { -// GrB_eWiseAdd(output.base, GrB_NULL, GrB_NULL, GxB_ANY_BOOL, matrices[i].base, -// delta_matrices[i].base, GrB_NULL); -// } - -// GrB_Info matrix_mxm_format(GrB_Matrix output, GrB_Matrix first, GrB_Matrix second) -// { - -// } - // LAGraph_CFL_reachability: Context-Free Language Reachability Matrix-Based Algorithm // // This function determines the set of vertex pairs (u, v) in a graph (represented by From fe16527a81b834cb867a0fd3e6ed33475d8a2c40 Mon Sep 17 00:00:00 2001 From: Homka122 Date: Wed, 14 May 2025 09:12:07 +0300 Subject: [PATCH 017/122] Fix: change NULL to GrB_NULL --- experimental/algorithm/LAGraph_CFL_reachability_advanced.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/experimental/algorithm/LAGraph_CFL_reachability_advanced.c b/experimental/algorithm/LAGraph_CFL_reachability_advanced.c index 8823fb8b46..03ef4011b6 100644 --- a/experimental/algorithm/LAGraph_CFL_reachability_advanced.c +++ b/experimental/algorithm/LAGraph_CFL_reachability_advanced.c @@ -269,7 +269,7 @@ GrB_Info matrix_dup_empty(Matrix *output, Matrix *input) { } GrB_Info matrix_mxm(Matrix *output, Matrix *first, Matrix *second, bool accum) { - GrB_mxm(output->base, GrB_NULL, accum ? GxB_ANY_BOOL : NULL, GxB_ANY_PAIR_BOOL, + GrB_mxm(output->base, GrB_NULL, accum ? GxB_ANY_BOOL : GrB_NULL, GxB_ANY_PAIR_BOOL, first->base, second->base, GrB_NULL); IS_ISO(output->base, "MXM output"); } From b198dd39de0dc38b05300e4b27d56b3898ae4b42 Mon Sep 17 00:00:00 2001 From: Homka122 Date: Wed, 14 May 2025 12:12:20 +0300 Subject: [PATCH 018/122] Fix: change dup method according to format optimization --- .../LAGraph_CFL_reachability_advanced.c | 41 ++++++++----------- 1 file changed, 17 insertions(+), 24 deletions(-) diff --git a/experimental/algorithm/LAGraph_CFL_reachability_advanced.c b/experimental/algorithm/LAGraph_CFL_reachability_advanced.c index 03ef4011b6..570a92bb6c 100644 --- a/experimental/algorithm/LAGraph_CFL_reachability_advanced.c +++ b/experimental/algorithm/LAGraph_CFL_reachability_advanced.c @@ -145,6 +145,7 @@ typedef struct { GrB_Index nvals; GrB_Index size; int32_t format; + bool is_both; } Matrix; void matrix_update(Matrix *matrix) { @@ -161,6 +162,7 @@ Matrix matrix_from_base(GrB_Matrix matrix) { result.nvals = 0; result.size = 0; result.format = GrB_ROWMAJOR; + result.is_both = false; matrix_update(&result); return result; } @@ -230,39 +232,30 @@ void matrix_to_row_both(Matrix *matrix) { return; } - if (matrix->format == GrB_COLMAJOR) { - GrB_Matrix new_matrix; - GrB_Matrix_new(&new_matrix, GrB_BOOL, matrix->size, matrix->size); - TO_ROW(new_matrix); - matrix->base_row = new_matrix; - matrix->base = matrix->base_row; - matrix->format = GrB_BOTH; - return; - } -} - GrB_Info matrix_dup(Matrix *output, Matrix *input) { - // if (output.format == GrB_ROWMAJOR || output.format == GrB_BOTH) { - // matrix_to_row(input); - // GrB_Matrix_dup(&output.base, input.base); - // } - - // if (output.format == GrB_COLMAJOR || output.format == GrB_BOTH) { - // matrix_to_col(input); - // GrB_Matrix_dup(&output.base_col, input.base_col); - // } - - GrB_Matrix_assign(output->base, GrB_NULL, GrB_NULL, input->base, GrB_ALL, input->size, - GrB_ALL, input->size, GrB_NULL); + return GrB_Matrix_assign(output->base, GrB_NULL, GrB_NULL, input->base, GrB_ALL, + input->size, GrB_ALL, input->size, GrB_NULL); } GrB_Info matrix_dup_format(Matrix *output, Matrix *input) { + if (!output->is_both) { + return matrix_dup(output, input); + } + + matrix_to_format(output, GrB_ROWMAJOR, false); + GrB_Info result = matrix_dup(output, input); + + if (result < GrB_SUCCESS) { + return result; + } + + matrix_to_format(output, GrB_COLMAJOR, false); return matrix_dup(output, input); } GrB_Info matrix_dup_empty(Matrix *output, Matrix *input) { if (input->nvals == 0) { - return GrB_Matrix_clear(output->base); + return matrix_clear_empty(output); } return matrix_dup_format(output, input); From 54ba2b8a04454664bfa6848938b431d7a5214e7e Mon Sep 17 00:00:00 2001 From: Homka122 Date: Wed, 14 May 2025 12:13:07 +0300 Subject: [PATCH 019/122] Feat: add clear methods with optimization --- .../LAGraph_CFL_reachability_advanced.c | 35 ++++++++++--------- 1 file changed, 18 insertions(+), 17 deletions(-) diff --git a/experimental/algorithm/LAGraph_CFL_reachability_advanced.c b/experimental/algorithm/LAGraph_CFL_reachability_advanced.c index 570a92bb6c..8e0e7ab811 100644 --- a/experimental/algorithm/LAGraph_CFL_reachability_advanced.c +++ b/experimental/algorithm/LAGraph_CFL_reachability_advanced.c @@ -207,30 +207,31 @@ void matrix_to_col_both(Matrix *matrix) { return; } - if (matrix->format == GrB_COLMAJOR) { - return; +GrB_Info matrix_clear(Matrix *A) { return GrB_Matrix_clear(A); } + +GrB_Info matrix_clear_format(Matrix *A) { + if (!A->is_both) { + matrix_clear(A); } - if (matrix->format == GrB_ROWMAJOR) { - GrB_Matrix new_matrix; - GrB_Matrix_new(&new_matrix, GrB_BOOL, matrix->size, matrix->size); - TO_COL(new_matrix); - matrix->base_col = new_matrix; - matrix->base = matrix->base_col; - matrix->format = GrB_BOTH; - return; + matrix_to_format(A, GrB_ROWMAJOR, false); + GrB_Info result = matrix_clear(A); + + if (result < GrB_SUCCESS) { + return result; } + + matrix_to_format(A, GrB_COLMAJOR, false); + return matrix_clear(A); } -void matrix_to_row_both(Matrix *matrix) { - if (matrix->format == GrB_BOTH) { - matrix->base = matrix->base_row; - return; +GrB_Info matrix_clear_empty(Matrix *A) { + if (A->nvals == 0) { + return GrB_SUCCESS; } - if (matrix->format == GrB_ROWMAJOR) { - return; - } + return matrix_clear_format(A); +} GrB_Info matrix_dup(Matrix *output, Matrix *input) { return GrB_Matrix_assign(output->base, GrB_NULL, GrB_NULL, input->base, GrB_ALL, From 9c7c92332852d63387501b3f951e2b291fc2c830 Mon Sep 17 00:00:00 2001 From: Homka122 Date: Wed, 14 May 2025 12:13:40 +0300 Subject: [PATCH 020/122] Feat: add change format methods --- .../LAGraph_CFL_reachability_advanced.c | 77 +++++++++++++------ 1 file changed, 52 insertions(+), 25 deletions(-) diff --git a/experimental/algorithm/LAGraph_CFL_reachability_advanced.c b/experimental/algorithm/LAGraph_CFL_reachability_advanced.c index 8e0e7ab811..bcdd58ab51 100644 --- a/experimental/algorithm/LAGraph_CFL_reachability_advanced.c +++ b/experimental/algorithm/LAGraph_CFL_reachability_advanced.c @@ -167,46 +167,73 @@ Matrix matrix_from_base(GrB_Matrix matrix) { return result; } -void matrix_to_row(Matrix *matrix) { - if (matrix->format == GrB_ROWMAJOR) { - return; - } +void matrix_format_sync(Matrix *matrix) { + if (!matrix->is_both) { + // if (matrix->format == GrB_ROWMAJOR) { + // GrB_Matrix_assign(matrix->base_row, GrB_NULL, GrB_NULL, matrix->base, + // GrB_ALL, + // matrix->size, GrB_ALL, matrix->size, GrB_NULL); + // } else { + // GrB_Matrix_assign(matrix->base_col, GrB_NULL, GrB_NULL, matrix->base, + // GrB_ALL, + // matrix->size, GrB_ALL, matrix->size, GrB_NULL); + // } - if (matrix->format == GrB_BOTH) { - matrix->base = matrix->base_row; return; } - matrix->format = GrB_ROWMAJOR; - matrix->base_row = matrix->base_col; - matrix->base_col = NULL; - TO_ROW(matrix->base_row); - matrix->base = matrix->base_row; + // GrB_Matrix_assign(matrix->base_row, GrB_NULL, GrB_NULL, matrix->base, GrB_ALL, + // matrix->size, GrB_ALL, matrix->size, GrB_NULL); + // GrB_Matrix_assign(matrix->base_col, GrB_NULL, GrB_NULL, matrix->base, GrB_ALL, + // matrix->size, GrB_ALL, matrix->size, GrB_NULL); + + GrB_Matrix *new_matrix = + matrix->format == GrB_ROWMAJOR ? &matrix->base_col : &matrix->base_row; + GrB_Matrix *old_matrix = + matrix->format == GrB_ROWMAJOR ? &matrix->base_row : &matrix->base_col; + + GrB_Matrix_assign(*new_matrix, GrB_NULL, GrB_NULL, *old_matrix, GrB_ALL, matrix->size, + GrB_ALL, matrix->size, GrB_NULL); + + // is_matrix_equal(matrix->base_row, matrix->base_col); + // is_matrix_equal(matrix->base_row, matrix->base); } -void matrix_to_col(Matrix *matrix) { - if (matrix->format == GrB_COLMAJOR) { +void matrix_to_format(Matrix *matrix, int32_t format, bool is_both) { + // Matrix contain both formats so just switch base matrix + if (matrix->is_both) { + matrix->base = format == GrB_ROWMAJOR ? matrix->base_row : matrix->base_col; + matrix->format = format; return; } - if (matrix->format == GrB_BOTH) { - matrix->base = matrix->base_col; + // No changes required + if (matrix->format == format) { return; } - matrix->format = GrB_COLMAJOR; - matrix->base_col = matrix->base_row; - matrix->base_row = NULL; - TO_COL(matrix->base_col); - matrix->base = matrix->base_col; -} + // Matrix contain just one matrix and format is not same + GrB_Matrix *new_matrix = + matrix->format == GrB_ROWMAJOR ? &matrix->base_col : &matrix->base_row; + GrB_Matrix *old_matrix = + matrix->format == GrB_ROWMAJOR ? &matrix->base_row : &matrix->base_col; -void matrix_to_col_both(Matrix *matrix) { - if (matrix->format == GrB_BOTH) { - matrix->base = matrix->base_col; - return; + if (is_both) { + GrB_Matrix_new(new_matrix, GrB_BOOL, matrix->size, matrix->size); + GrB_Matrix_assign(*new_matrix, GrB_NULL, GrB_NULL, *old_matrix, GrB_ALL, + matrix->size, GrB_ALL, matrix->size, GrB_NULL); + matrix->is_both = true; + } else { + *new_matrix = *old_matrix; + *old_matrix = NULL; } + matrix->base = format == GrB_ROWMAJOR ? matrix->base_row : matrix->base_col; + format == GrB_ROWMAJOR ? TO_ROW(matrix->base) : TO_COL(matrix->base); + matrix->format = format; + return; +} + GrB_Info matrix_clear(Matrix *A) { return GrB_Matrix_clear(A); } GrB_Info matrix_clear_format(Matrix *A) { From 067fb3a871c0c57e0a078f1256f2ff4715296e9d Mon Sep 17 00:00:00 2001 From: Homka122 Date: Wed, 14 May 2025 12:14:20 +0300 Subject: [PATCH 021/122] Feat: process result of matrix_mxm --- experimental/algorithm/LAGraph_CFL_reachability_advanced.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/experimental/algorithm/LAGraph_CFL_reachability_advanced.c b/experimental/algorithm/LAGraph_CFL_reachability_advanced.c index bcdd58ab51..f67e7d53a0 100644 --- a/experimental/algorithm/LAGraph_CFL_reachability_advanced.c +++ b/experimental/algorithm/LAGraph_CFL_reachability_advanced.c @@ -290,9 +290,10 @@ GrB_Info matrix_dup_empty(Matrix *output, Matrix *input) { } GrB_Info matrix_mxm(Matrix *output, Matrix *first, Matrix *second, bool accum) { - GrB_mxm(output->base, GrB_NULL, accum ? GxB_ANY_BOOL : GrB_NULL, GxB_ANY_PAIR_BOOL, - first->base, second->base, GrB_NULL); + GrB_Info result = GrB_mxm(output->base, GrB_NULL, accum ? GxB_ANY_BOOL : GrB_NULL, + GxB_ANY_PAIR_BOOL, first->base, second->base, GrB_NULL); IS_ISO(output->base, "MXM output"); + return result; } GrB_Info matrix_mxm_format(Matrix *output, Matrix *first, Matrix *second, bool accum) { From ba335af4d88a5a0a98e2bf6b48ef195e998d174b Mon Sep 17 00:00:00 2001 From: Homka122 Date: Wed, 14 May 2025 12:15:27 +0300 Subject: [PATCH 022/122] Fix: now all methods in empty wise use format methods --- .../algorithm/LAGraph_CFL_reachability_advanced.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/experimental/algorithm/LAGraph_CFL_reachability_advanced.c b/experimental/algorithm/LAGraph_CFL_reachability_advanced.c index f67e7d53a0..2d8ce0ba05 100644 --- a/experimental/algorithm/LAGraph_CFL_reachability_advanced.c +++ b/experimental/algorithm/LAGraph_CFL_reachability_advanced.c @@ -397,30 +397,28 @@ GrB_Info matrix_wise_format(Matrix *output, Matrix *first, Matrix *second, bool } GrB_Info matrix_wise_empty(Matrix *output, Matrix *first, Matrix *second, bool accum) { - GrB_BinaryOp accum_op = accum ? GxB_ANY_BOOL : GrB_NULL; - if (first->nvals == 0 && second->nvals == 0) { if (accum) { return GrB_SUCCESS; } - return GrB_Matrix_clear(output->base); + return matrix_clear_format(output); } if (first->nvals == 0) { if (accum) { - return matrix_wise(output, output, second, false); + return matrix_wise_format(output, output, second, false); } - return matrix_dup(output, second); + return matrix_dup_format(output, second); } if (second->nvals == 0) { if (accum) { - return matrix_wise(output, output, first, false); + return matrix_wise_format(output, output, first, false); } - return matrix_dup(output, first); + return matrix_dup_format(output, first); } return matrix_wise_format(output, first, second, accum); From 88774691b27279b2305682aa9ebcfb78aa110948 Mon Sep 17 00:00:00 2001 From: Homka122 Date: Wed, 14 May 2025 12:17:46 +0300 Subject: [PATCH 023/122] Refactor: change rsub method with format optim --- .../algorithm/LAGraph_CFL_reachability_advanced.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/experimental/algorithm/LAGraph_CFL_reachability_advanced.c b/experimental/algorithm/LAGraph_CFL_reachability_advanced.c index 2d8ce0ba05..f9e1398065 100644 --- a/experimental/algorithm/LAGraph_CFL_reachability_advanced.c +++ b/experimental/algorithm/LAGraph_CFL_reachability_advanced.c @@ -430,14 +430,18 @@ GrB_Info matrix_rsub(Matrix *output, Matrix *mask) { } GrB_Info matrix_rsub_format(Matrix *output, Matrix *mask) { - if (mask->format == GrB_ROWMAJOR) { - matrix_to_row(output); - matrix_to_row(mask); + if (!output->is_both) { return matrix_rsub(output, mask); } - matrix_to_col(output); - matrix_to_col(mask); + matrix_to_format(output, GrB_ROWMAJOR, false); + GrB_Info result = matrix_rsub(output, mask); + + if (result < GrB_SUCCESS) { + return result; + } + + matrix_to_format(output, GrB_COLMAJOR, false); return matrix_rsub(output, mask); } From a5b9f0e4ffb72335cc5d433c55c36fea41820c15 Mon Sep 17 00:00:00 2001 From: Homka122 Date: Wed, 14 May 2025 12:19:45 +0300 Subject: [PATCH 024/122] Refactor: change wise method with format optimization --- .../LAGraph_CFL_reachability_advanced.c | 21 +++++++------------ 1 file changed, 7 insertions(+), 14 deletions(-) diff --git a/experimental/algorithm/LAGraph_CFL_reachability_advanced.c b/experimental/algorithm/LAGraph_CFL_reachability_advanced.c index f9e1398065..a3ad1f2dc6 100644 --- a/experimental/algorithm/LAGraph_CFL_reachability_advanced.c +++ b/experimental/algorithm/LAGraph_CFL_reachability_advanced.c @@ -374,26 +374,19 @@ GrB_Info matrix_wise(Matrix *output, Matrix *first, Matrix *second, bool accum) } GrB_Info matrix_wise_format(Matrix *output, Matrix *first, Matrix *second, bool accum) { - GrB_BinaryOp accum_op = accum ? GxB_ANY_BOOL : GrB_NULL; - GrB_Info result; - - if (first->format == GrB_ROWMAJOR || first->format == GrB_BOTH) { - matrix_to_row(second); - matrix_to_row(output); - result = matrix_wise(output, first, second, accum); + if (!output->is_both) { + return matrix_wise(output, first, second, accum); } + matrix_to_format(output, GrB_ROWMAJOR, false); + GrB_Info result = matrix_wise(output, first, second, accum); + if (result < GrB_SUCCESS) { return result; } - if (first->format == GrB_COLMAJOR || first->format == GrB_BOTH) { - matrix_to_col(second); - matrix_to_col(output); - result = matrix_wise(output, first, second, accum); - } - - return result; + matrix_to_format(output, GrB_COLMAJOR, false); + return matrix_wise(output, first, second, accum); } GrB_Info matrix_wise_empty(Matrix *output, Matrix *first, Matrix *second, bool accum) { From 0a59d20a65893ca86b4d46e38f703be0560d1f0c Mon Sep 17 00:00:00 2001 From: Homka122 Date: Wed, 14 May 2025 13:14:21 +0300 Subject: [PATCH 025/122] Fix: fix wrong type in for cycle --- .../algorithm/LAGraph_CFL_reachability_advanced.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/experimental/algorithm/LAGraph_CFL_reachability_advanced.c b/experimental/algorithm/LAGraph_CFL_reachability_advanced.c index a3ad1f2dc6..46c8ffffc8 100644 --- a/experimental/algorithm/LAGraph_CFL_reachability_advanced.c +++ b/experimental/algorithm/LAGraph_CFL_reachability_advanced.c @@ -749,7 +749,7 @@ GrB_Info LAGraph_CFL_reachability_adv( TIMER_STOP("MXM 1", &mxm1); TIMER_START() - for (size_t i = 0; i < nonterms_count; i++) { + for (int32_t i = 0; i < nonterms_count; i++) { matrix_wise_empty(&matrices[i], &matrices[i], &delta_matrices[i], false); matrix_update(&matrices[i]); } @@ -767,19 +767,19 @@ GrB_Info LAGraph_CFL_reachability_adv( TIMER_STOP("MXM 2", &mxm2); TIMER_START(); - for (size_t i = 0; i < nonterms_count; i++) { + for (int32_t i = 0; i < nonterms_count; i++) { matrix_dup_empty(&delta_matrices[i], &temp_matrices[i]); } TIMER_STOP("WISE 2 (copy)", &wise2); TIMER_START(); - for (size_t i = 0; i < nonterms_count; i++) { + for (int32_t i = 0; i < nonterms_count; i++) { matrix_rsub_empty(&delta_matrices[i], &matrices[i]); matrix_update(&delta_matrices[i]); } TIMER_STOP("WISE 3 (MASK)", &rsub); - for (size_t i = 0; i < nonterms_count; i++) { + for (int32_t i = 0; i < nonterms_count; i++) { GrB_Index new_nnz; GRB_TRY(GrB_Matrix_nvals(&new_nnz, matrices[i].base)); if (new_nnz != 0) From 0bc599fd7e66b5e808b02b31e4d85759b248b821 Mon Sep 17 00:00:00 2001 From: Homka122 Date: Wed, 14 May 2025 13:14:41 +0300 Subject: [PATCH 026/122] Fix: change GrB clear method to mine --- experimental/algorithm/LAGraph_CFL_reachability_advanced.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/experimental/algorithm/LAGraph_CFL_reachability_advanced.c b/experimental/algorithm/LAGraph_CFL_reachability_advanced.c index 46c8ffffc8..e89ebd5f2b 100644 --- a/experimental/algorithm/LAGraph_CFL_reachability_advanced.c +++ b/experimental/algorithm/LAGraph_CFL_reachability_advanced.c @@ -734,7 +734,7 @@ GrB_Info LAGraph_CFL_reachability_adv( #endif for (size_t i = 0; i < nonterms_count; i++) { - GRB_TRY(GrB_Matrix_clear(temp_matrices[i].base)); + GRB_TRY(matrix_clear_empty(&temp_matrices[i])); matrix_update(&temp_matrices[i]); } From 135ba928fbb8867806650a0b121ef153ec9ae310 Mon Sep 17 00:00:00 2001 From: Homka122 Date: Wed, 14 May 2025 13:49:17 +0300 Subject: [PATCH 027/122] Feat: add rmxm method --- .../LAGraph_CFL_reachability_advanced.c | 90 ++++++++----------- 1 file changed, 39 insertions(+), 51 deletions(-) diff --git a/experimental/algorithm/LAGraph_CFL_reachability_advanced.c b/experimental/algorithm/LAGraph_CFL_reachability_advanced.c index e89ebd5f2b..1e7232005f 100644 --- a/experimental/algorithm/LAGraph_CFL_reachability_advanced.c +++ b/experimental/algorithm/LAGraph_CFL_reachability_advanced.c @@ -234,7 +234,7 @@ void matrix_to_format(Matrix *matrix, int32_t format, bool is_both) { return; } -GrB_Info matrix_clear(Matrix *A) { return GrB_Matrix_clear(A); } +GrB_Info matrix_clear(Matrix *A) { return GrB_Matrix_clear(A->base); } GrB_Info matrix_clear_format(Matrix *A) { if (!A->is_both) { @@ -300,70 +300,52 @@ GrB_Info matrix_mxm_format(Matrix *output, Matrix *first, Matrix *second, bool a int32_t desired_orientation = first->nvals > second->nvals ? GrB_COLMAJOR : GrB_ROWMAJOR; - if (first->format == desired_orientation || first->format == GrB_BOTH) { - if (desired_orientation == GrB_COLMAJOR) { - matrix_to_col(second); - matrix_to_col(output); - return matrix_mxm(output, first, second, accum); - } else { - matrix_to_row(second); - matrix_to_row(output); - return matrix_mxm(output, first, second, accum); - } + if (!first->is_both && first->format != desired_orientation && + !(first->nvals > second->nvals / 3.0)) { + GrB_Info result = matrix_mxm(output, first, second, accum); + return result; } - if (first->nvals > second->nvals / 3.0) { - matrix_to_col_both(first); - matrix_to_row(second); - matrix_to_row(output); - return matrix_mxm(output, first, second, accum); - } + matrix_to_format(first, desired_orientation, true); + matrix_to_format(second, desired_orientation, false); + matrix_to_format(output, desired_orientation, false); + GrB_Info result = matrix_mxm(output, first, second, accum); + return result; +} - return matrix_mxm(output, first, second, accum); +GrB_Info matrix_mxm_empty(Matrix *output, Matrix *first, Matrix *second, bool accum) { + if (first->nvals == 0 || second->nvals == 0) + return GrB_SUCCESS; + + return matrix_mxm_format(output, first, second, accum); } GrB_Info matrix_rmxm_format(Matrix *output, Matrix *first, Matrix *second, bool accum) { Matrix *temp = first; - second = first; - first = temp; + first = second; + second = temp; int32_t desired_orientation = first->nvals > second->nvals ? GrB_ROWMAJOR : GrB_COLMAJOR; - if (first->format == desired_orientation || first->format == GrB_BOTH) { - if (desired_orientation == GrB_COLMAJOR) { - matrix_to_row(second); - matrix_to_row(output); - return matrix_mxm(output, first, second, accum); - } else { - matrix_to_col(second); - matrix_to_col(output); - return matrix_mxm(output, first, second, accum); - } - } - - if (first->nvals > second->nvals / 3.0) { - matrix_to_row_both(first); - matrix_to_col(second); - matrix_to_col(output); - return matrix_mxm(output, first, second, accum); + if (!first->is_both && first->format != desired_orientation && + !(first->nvals > second->nvals / 3.0)) { + GrB_Info result = matrix_mxm(output, second, first, accum); + return result; } - return matrix_mxm(output, first, second, accum); -} - -GrB_Info matrix_mxm_empty(Matrix *output, Matrix *first, Matrix *second, bool accum) { - if (first->nvals == 0 || second->nvals == 0) - return GrB_SUCCESS; - - matrix_mxm_format(output, first, second, accum); + matrix_to_format(first, desired_orientation, true); + matrix_to_format(second, desired_orientation, false); + matrix_to_format(output, desired_orientation, false); + GrB_Info result = matrix_mxm(output, second, first, accum); + return result; } GrB_Info matrix_rmxm_empty(Matrix *output, Matrix *first, Matrix *second, bool accum) { if (first->nvals == 0 || second->nvals == 0) return GrB_SUCCESS; - matrix_rmxm_format(output, first, second, accum); + return matrix_rmxm_format(output, first, second, accum); } GrB_Info matrix_wise(Matrix *output, Matrix *first, Matrix *second, bool accum) { @@ -423,10 +405,16 @@ GrB_Info matrix_rsub(Matrix *output, Matrix *mask) { } GrB_Info matrix_rsub_format(Matrix *output, Matrix *mask) { + Matrix *larger_matrix = output->nvals > mask->nvals ? output : mask; + matrix_to_format(output, larger_matrix->format, false); + matrix_to_format(mask, larger_matrix->format, false); + if (!output->is_both) { return matrix_rsub(output, mask); } + printf("LOOOOOO\n\n"); + matrix_to_format(output, GrB_ROWMAJOR, false); GrB_Info result = matrix_rsub(output, mask); @@ -742,8 +730,8 @@ GrB_Info LAGraph_CFL_reachability_adv( for (size_t i = 0; i < bin_rules_count; i++) { LAGraph_rule_WCNF bin_rule = rules[bin_rules[i]]; - matrix_mxm(&temp_matrices[bin_rule.nonterm], &matrices[bin_rule.prod_A], - &delta_matrices[bin_rule.prod_B], false); + matrix_mxm_empty(&temp_matrices[bin_rule.nonterm], &matrices[bin_rule.prod_A], + &delta_matrices[bin_rule.prod_B], false); matrix_update(&temp_matrices[bin_rule.nonterm]); } TIMER_STOP("MXM 1", &mxm1); @@ -759,9 +747,9 @@ GrB_Info LAGraph_CFL_reachability_adv( for (size_t i = 0; i < bin_rules_count; i++) { LAGraph_rule_WCNF bin_rule = rules[bin_rules[i]]; - matrix_mxm_empty(&temp_matrices[bin_rule.nonterm], - &delta_matrices[bin_rule.prod_A], &matrices[bin_rule.prod_B], - true); + matrix_rmxm_empty(&temp_matrices[bin_rule.nonterm], + &delta_matrices[bin_rule.prod_A], + &matrices[bin_rule.prod_B], true); matrix_update(&temp_matrices[bin_rule.nonterm]); } TIMER_STOP("MXM 2", &mxm2); From e85a7c1858825dc39acffc4545c74fab1900505c Mon Sep 17 00:00:00 2001 From: Homka122 Date: Wed, 14 May 2025 13:53:37 +0300 Subject: [PATCH 028/122] Fix: incompitible type of for cycle --- experimental/algorithm/LAGraph_CFL_reachability_advanced.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/experimental/algorithm/LAGraph_CFL_reachability_advanced.c b/experimental/algorithm/LAGraph_CFL_reachability_advanced.c index 1e7232005f..5a5a9babb7 100644 --- a/experimental/algorithm/LAGraph_CFL_reachability_advanced.c +++ b/experimental/algorithm/LAGraph_CFL_reachability_advanced.c @@ -721,7 +721,7 @@ GrB_Info LAGraph_CFL_reachability_adv( printf("\n--- ITERATARION %ld ---\n", iteration); #endif - for (size_t i = 0; i < nonterms_count; i++) { + for (int32_t i = 0; i < nonterms_count; i++) { GRB_TRY(matrix_clear_empty(&temp_matrices[i])); matrix_update(&temp_matrices[i]); } From e95dbad5c7064cc6b24978854a3d2a2f297201ca Mon Sep 17 00:00:00 2001 From: Homka122 Date: Wed, 14 May 2025 13:55:15 +0300 Subject: [PATCH 029/122] Refactor: delete unused variables --- .../algorithm/LAGraph_CFL_reachability_advanced.c | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/experimental/algorithm/LAGraph_CFL_reachability_advanced.c b/experimental/algorithm/LAGraph_CFL_reachability_advanced.c index 5a5a9babb7..bad21f97a0 100644 --- a/experimental/algorithm/LAGraph_CFL_reachability_advanced.c +++ b/experimental/algorithm/LAGraph_CFL_reachability_advanced.c @@ -504,12 +504,10 @@ GrB_Info LAGraph_CFL_reachability_adv( Matrix *delta_matrices; Matrix *matrices; Matrix *temp_matrices; - bool t_empty_flags[nonterms_count]; // t_empty_flags[i] == true <=> T[i] is empty GrB_Matrix identity_matrix = NULL; uint64_t *nnzs = NULL; LG_CLEAR_MSG; size_t msg_len = 0; // For error formatting - bool iso_flag = false; GrB_Index *indexes = NULL; GrB_Scalar true_scalar; @@ -570,8 +568,6 @@ GrB_Info LAGraph_CFL_reachability_adv( GRB_TRY(GrB_Matrix_new(&matrix, GrB_BOOL, n, n)); temp_matrices[i] = matrix_from_base(matrix); - - t_empty_flags[i] = true; } // Arrays for processing rules @@ -670,8 +666,6 @@ GrB_Info LAGraph_CFL_reachability_adv( adj_matrices[term_rule.prod_A], true_scalar, GrB_NULL); matrix_update(&delta_matrices[term_rule.nonterm]); - t_empty_flags[term_rule.nonterm] = false; - #ifdef DEBUG_CFL_REACHBILITY GxB_Matrix_iso(&iso_flag, T[term_rule.nonterm]); printf("[TERM] eWiseUnion: NONTERM: %d (ISO: %d)\n", term_rule.nonterm, iso_flag); @@ -693,8 +687,6 @@ GrB_Info LAGraph_CFL_reachability_adv( identity_matrix, true_scalar, GrB_NULL); matrix_update(&delta_matrices[eps_rule.nonterm]); - t_empty_flags[eps_rule.nonterm] = false; - #ifdef DEBUG_CFL_REACHBILITY GxB_Matrix_iso(&iso_flag, T[eps_rule.nonterm]); printf("[EPS] eWiseUnion: NONTERM: %d (ISO: %d)\n", eps_rule.nonterm, iso_flag); @@ -712,7 +704,6 @@ GrB_Info LAGraph_CFL_reachability_adv( double mxm2 = 0.0; double wise2 = 0.0; double rsub = 0.0; - GrB_Index new_nnz; while (changed) { iteration++; changed = false; @@ -770,8 +761,6 @@ GrB_Info LAGraph_CFL_reachability_adv( for (int32_t i = 0; i < nonterms_count; i++) { GrB_Index new_nnz; GRB_TRY(GrB_Matrix_nvals(&new_nnz, matrices[i].base)); - if (new_nnz != 0) - t_empty_flags[i] = false; changed = changed || (nnzs[i] != new_nnz); nnzs[i] = new_nnz; From 3756ed9d19db3da5744b9441ea40588f6e30f7d2 Mon Sep 17 00:00:00 2001 From: Homka122 Date: Wed, 14 May 2025 18:15:20 +0300 Subject: [PATCH 030/122] Feat: delete unused sync format method --- .../LAGraph_CFL_reachability_advanced.c | 32 ------------------- 1 file changed, 32 deletions(-) diff --git a/experimental/algorithm/LAGraph_CFL_reachability_advanced.c b/experimental/algorithm/LAGraph_CFL_reachability_advanced.c index bad21f97a0..f865c331ca 100644 --- a/experimental/algorithm/LAGraph_CFL_reachability_advanced.c +++ b/experimental/algorithm/LAGraph_CFL_reachability_advanced.c @@ -167,38 +167,6 @@ Matrix matrix_from_base(GrB_Matrix matrix) { return result; } -void matrix_format_sync(Matrix *matrix) { - if (!matrix->is_both) { - // if (matrix->format == GrB_ROWMAJOR) { - // GrB_Matrix_assign(matrix->base_row, GrB_NULL, GrB_NULL, matrix->base, - // GrB_ALL, - // matrix->size, GrB_ALL, matrix->size, GrB_NULL); - // } else { - // GrB_Matrix_assign(matrix->base_col, GrB_NULL, GrB_NULL, matrix->base, - // GrB_ALL, - // matrix->size, GrB_ALL, matrix->size, GrB_NULL); - // } - - return; - } - - // GrB_Matrix_assign(matrix->base_row, GrB_NULL, GrB_NULL, matrix->base, GrB_ALL, - // matrix->size, GrB_ALL, matrix->size, GrB_NULL); - // GrB_Matrix_assign(matrix->base_col, GrB_NULL, GrB_NULL, matrix->base, GrB_ALL, - // matrix->size, GrB_ALL, matrix->size, GrB_NULL); - - GrB_Matrix *new_matrix = - matrix->format == GrB_ROWMAJOR ? &matrix->base_col : &matrix->base_row; - GrB_Matrix *old_matrix = - matrix->format == GrB_ROWMAJOR ? &matrix->base_row : &matrix->base_col; - - GrB_Matrix_assign(*new_matrix, GrB_NULL, GrB_NULL, *old_matrix, GrB_ALL, matrix->size, - GrB_ALL, matrix->size, GrB_NULL); - - // is_matrix_equal(matrix->base_row, matrix->base_col); - // is_matrix_equal(matrix->base_row, matrix->base); -} - void matrix_to_format(Matrix *matrix, int32_t format, bool is_both) { // Matrix contain both formats so just switch base matrix if (matrix->is_both) { From 539260dabdd40c3ec90edd651c29ed039c7032ad Mon Sep 17 00:00:00 2001 From: Homka122 Date: Wed, 14 May 2025 18:30:46 +0300 Subject: [PATCH 031/122] Feat: use more optimize methods in wise method --- .../algorithm/LAGraph_CFL_reachability_advanced.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/experimental/algorithm/LAGraph_CFL_reachability_advanced.c b/experimental/algorithm/LAGraph_CFL_reachability_advanced.c index f865c331ca..b6aaafb06f 100644 --- a/experimental/algorithm/LAGraph_CFL_reachability_advanced.c +++ b/experimental/algorithm/LAGraph_CFL_reachability_advanced.c @@ -345,23 +345,23 @@ GrB_Info matrix_wise_empty(Matrix *output, Matrix *first, Matrix *second, bool a return GrB_SUCCESS; } - return matrix_clear_format(output); + return matrix_clear_empty(output); } if (first->nvals == 0) { if (accum) { - return matrix_wise_format(output, output, second, false); + return matrix_wise_empty(output, output, second, false); } - return matrix_dup_format(output, second); + return matrix_dup_empty(output, second); } if (second->nvals == 0) { if (accum) { - return matrix_wise_format(output, output, first, false); + return matrix_wise_empty(output, output, first, false); } - return matrix_dup_format(output, first); + return matrix_dup_empty(output, first); } return matrix_wise_format(output, first, second, accum); From 007c6b734b6ede6703734fe8a4131d564105a447 Mon Sep 17 00:00:00 2001 From: Homka122 Date: Wed, 14 May 2025 18:31:12 +0300 Subject: [PATCH 032/122] Feat: manually choose format in wise and dup method --- .../LAGraph_CFL_reachability_advanced.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/experimental/algorithm/LAGraph_CFL_reachability_advanced.c b/experimental/algorithm/LAGraph_CFL_reachability_advanced.c index b6aaafb06f..e72dd5e5b6 100644 --- a/experimental/algorithm/LAGraph_CFL_reachability_advanced.c +++ b/experimental/algorithm/LAGraph_CFL_reachability_advanced.c @@ -235,6 +235,11 @@ GrB_Info matrix_dup(Matrix *output, Matrix *input) { GrB_Info matrix_dup_format(Matrix *output, Matrix *input) { if (!output->is_both) { + Matrix *larger = output->nvals > input->nvals ? output : input; + + matrix_to_format(output, larger->format, false); + matrix_to_format(input, larger->format, false); + return matrix_dup(output, input); } @@ -325,10 +330,19 @@ GrB_Info matrix_wise(Matrix *output, Matrix *first, Matrix *second, bool accum) GrB_Info matrix_wise_format(Matrix *output, Matrix *first, Matrix *second, bool accum) { if (!output->is_both) { + Matrix *larger = output->nvals > first->nvals ? output : first; + larger = larger->nvals > second->nvals ? larger : second; + + matrix_to_format(output, larger->format, false); + matrix_to_format(first, larger->format, false); + matrix_to_format(second, larger->format, false); + return matrix_wise(output, first, second, accum); } matrix_to_format(output, GrB_ROWMAJOR, false); + matrix_to_format(first, output->format, false); + matrix_to_format(second, output->format, false); GrB_Info result = matrix_wise(output, first, second, accum); if (result < GrB_SUCCESS) { @@ -336,6 +350,8 @@ GrB_Info matrix_wise_format(Matrix *output, Matrix *first, Matrix *second, bool } matrix_to_format(output, GrB_COLMAJOR, false); + matrix_to_format(first, output->format, false); + matrix_to_format(second, output->format, false); return matrix_wise(output, first, second, accum); } From 36ffc72f0928d502b86c9fb80031072d51a77d6c Mon Sep 17 00:00:00 2001 From: Homka122 Date: Wed, 14 May 2025 18:56:14 +0300 Subject: [PATCH 033/122] Fix: wrong type in for cycle --- experimental/algorithm/LAGraph_CFL_reachability_advanced.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/experimental/algorithm/LAGraph_CFL_reachability_advanced.c b/experimental/algorithm/LAGraph_CFL_reachability_advanced.c index e72dd5e5b6..5337aeb02c 100644 --- a/experimental/algorithm/LAGraph_CFL_reachability_advanced.c +++ b/experimental/algorithm/LAGraph_CFL_reachability_advanced.c @@ -26,7 +26,7 @@ #define LG_FREE_ALL \ { \ - for (size_t i = 0; i < nonterms_count; i++) { \ + for (int32_t i = 0; i < nonterms_count; i++) { \ GrB_free(&T[i]); \ } \ \ From a1806243922083fd47cccba14d7342980205fe30 Mon Sep 17 00:00:00 2001 From: Homka122 Date: Wed, 14 May 2025 18:57:49 +0300 Subject: [PATCH 034/122] Feat: now update Matrix object in place --- .../LAGraph_CFL_reachability_advanced.c | 38 ++++++++++++------- 1 file changed, 24 insertions(+), 14 deletions(-) diff --git a/experimental/algorithm/LAGraph_CFL_reachability_advanced.c b/experimental/algorithm/LAGraph_CFL_reachability_advanced.c index 5337aeb02c..7addd2f5bb 100644 --- a/experimental/algorithm/LAGraph_CFL_reachability_advanced.c +++ b/experimental/algorithm/LAGraph_CFL_reachability_advanced.c @@ -151,7 +151,7 @@ typedef struct { void matrix_update(Matrix *matrix) { GrB_Matrix_nvals(&matrix->nvals, matrix->base); GrB_Matrix_nrows(&matrix->size, matrix->base); - GrB_get(matrix->base, &matrix->format, GrB_STORAGE_ORIENTATION_HINT); + // GrB_get(matrix->base, &matrix->format, GrB_STORAGE_ORIENTATION_HINT); } Matrix matrix_from_base(GrB_Matrix matrix) { @@ -202,11 +202,15 @@ void matrix_to_format(Matrix *matrix, int32_t format, bool is_both) { return; } -GrB_Info matrix_clear(Matrix *A) { return GrB_Matrix_clear(A->base); } +GrB_Info matrix_clear(Matrix *A) { + GrB_Info result = GrB_Matrix_clear(A->base); + matrix_update(A); + return result; +} GrB_Info matrix_clear_format(Matrix *A) { if (!A->is_both) { - matrix_clear(A); + return matrix_clear(A); } matrix_to_format(A, GrB_ROWMAJOR, false); @@ -229,8 +233,12 @@ GrB_Info matrix_clear_empty(Matrix *A) { } GrB_Info matrix_dup(Matrix *output, Matrix *input) { - return GrB_Matrix_assign(output->base, GrB_NULL, GrB_NULL, input->base, GrB_ALL, - input->size, GrB_ALL, input->size, GrB_NULL); + GrB_Info result = + GrB_Matrix_assign(output->base, GrB_NULL, GrB_NULL, input->base, GrB_ALL, + input->size, GrB_ALL, input->size, GrB_NULL); + + matrix_update(output); + return result; } GrB_Info matrix_dup_format(Matrix *output, Matrix *input) { @@ -266,6 +274,7 @@ GrB_Info matrix_mxm(Matrix *output, Matrix *first, Matrix *second, bool accum) { GrB_Info result = GrB_mxm(output->base, GrB_NULL, accum ? GxB_ANY_BOOL : GrB_NULL, GxB_ANY_PAIR_BOOL, first->base, second->base, GrB_NULL); IS_ISO(output->base, "MXM output"); + matrix_update(output); return result; } @@ -324,8 +333,11 @@ GrB_Info matrix_rmxm_empty(Matrix *output, Matrix *first, Matrix *second, bool a GrB_Info matrix_wise(Matrix *output, Matrix *first, Matrix *second, bool accum) { GrB_BinaryOp accum_op = accum ? GxB_ANY_BOOL : GrB_NULL; - return GrB_eWiseAdd(output->base, GrB_NULL, accum_op, GxB_ANY_BOOL, first->base, - second->base, GrB_NULL); + GrB_Info result = GrB_eWiseAdd(output->base, GrB_NULL, accum_op, GxB_ANY_BOOL, + first->base, second->base, GrB_NULL); + + matrix_update(output); + return result; } GrB_Info matrix_wise_format(Matrix *output, Matrix *first, Matrix *second, bool accum) { @@ -384,8 +396,11 @@ GrB_Info matrix_wise_empty(Matrix *output, Matrix *first, Matrix *second, bool a } GrB_Info matrix_rsub(Matrix *output, Matrix *mask) { - return GrB_eWiseAdd(output->base, mask->base, GrB_NULL, GxB_ANY_BOOL, output->base, - output->base, GrB_DESC_RSC); + GrB_Info result = GrB_eWiseAdd(output->base, mask->base, GrB_NULL, GxB_ANY_BOOL, + output->base, output->base, GrB_DESC_RSC); + + matrix_update(output); + return result; } GrB_Info matrix_rsub_format(Matrix *output, Matrix *mask) { @@ -698,7 +713,6 @@ GrB_Info LAGraph_CFL_reachability_adv( for (int32_t i = 0; i < nonterms_count; i++) { GRB_TRY(matrix_clear_empty(&temp_matrices[i])); - matrix_update(&temp_matrices[i]); } TIMER_START(); @@ -707,14 +721,12 @@ GrB_Info LAGraph_CFL_reachability_adv( matrix_mxm_empty(&temp_matrices[bin_rule.nonterm], &matrices[bin_rule.prod_A], &delta_matrices[bin_rule.prod_B], false); - matrix_update(&temp_matrices[bin_rule.nonterm]); } TIMER_STOP("MXM 1", &mxm1); TIMER_START() for (int32_t i = 0; i < nonterms_count; i++) { matrix_wise_empty(&matrices[i], &matrices[i], &delta_matrices[i], false); - matrix_update(&matrices[i]); } TIMER_STOP("WISE 1", &wise1); @@ -725,7 +737,6 @@ GrB_Info LAGraph_CFL_reachability_adv( matrix_rmxm_empty(&temp_matrices[bin_rule.nonterm], &delta_matrices[bin_rule.prod_A], &matrices[bin_rule.prod_B], true); - matrix_update(&temp_matrices[bin_rule.nonterm]); } TIMER_STOP("MXM 2", &mxm2); @@ -738,7 +749,6 @@ GrB_Info LAGraph_CFL_reachability_adv( TIMER_START(); for (int32_t i = 0; i < nonterms_count; i++) { matrix_rsub_empty(&delta_matrices[i], &matrices[i]); - matrix_update(&delta_matrices[i]); } TIMER_STOP("WISE 3 (MASK)", &rsub); From cf89d6a0d3ed9d5800dd078ce67a9c077b87af9a Mon Sep 17 00:00:00 2001 From: Homka122 Date: Wed, 14 May 2025 21:24:51 +0300 Subject: [PATCH 035/122] Feat: delete seperate rmxm method --- .../LAGraph_CFL_reachability_advanced.c | 42 ++++++++++++++----- 1 file changed, 31 insertions(+), 11 deletions(-) diff --git a/experimental/algorithm/LAGraph_CFL_reachability_advanced.c b/experimental/algorithm/LAGraph_CFL_reachability_advanced.c index 7addd2f5bb..0d0546c382 100644 --- a/experimental/algorithm/LAGraph_CFL_reachability_advanced.c +++ b/experimental/algorithm/LAGraph_CFL_reachability_advanced.c @@ -270,36 +270,55 @@ GrB_Info matrix_dup_empty(Matrix *output, Matrix *input) { return matrix_dup_format(output, input); } -GrB_Info matrix_mxm(Matrix *output, Matrix *first, Matrix *second, bool accum) { +GrB_Info matrix_wise_empty(Matrix *output, Matrix *first, Matrix *second, bool accum); + +GrB_Info matrix_mxm(Matrix *output, Matrix *first, Matrix *second, bool accum, + bool swap) { + Matrix *left = swap ? second : first; + Matrix *right = swap ? first : second; + GrB_Info result = GrB_mxm(output->base, GrB_NULL, accum ? GxB_ANY_BOOL : GrB_NULL, - GxB_ANY_PAIR_BOOL, first->base, second->base, GrB_NULL); + GxB_ANY_PAIR_BOOL, left->base, right->base, GrB_NULL); IS_ISO(output->base, "MXM output"); matrix_update(output); return result; } -GrB_Info matrix_mxm_format(Matrix *output, Matrix *first, Matrix *second, bool accum) { +GrB_Info matrix_mxm_format(Matrix *output, Matrix *first, Matrix *second, bool accum, + bool swap) { + if (swap) { + Matrix *temp = first; + first = second; + second = temp; + } + int32_t desired_orientation = first->nvals > second->nvals ? GrB_COLMAJOR : GrB_ROWMAJOR; + if (swap) { + desired_orientation = + desired_orientation == GrB_ROWMAJOR ? GrB_COLMAJOR : GrB_ROWMAJOR; + } + if (!first->is_both && first->format != desired_orientation && !(first->nvals > second->nvals / 3.0)) { - GrB_Info result = matrix_mxm(output, first, second, accum); + GrB_Info result = matrix_mxm(output, first, second, accum, swap); return result; } matrix_to_format(first, desired_orientation, true); matrix_to_format(second, desired_orientation, false); matrix_to_format(output, desired_orientation, false); - GrB_Info result = matrix_mxm(output, first, second, accum); + GrB_Info result = matrix_mxm(output, first, second, accum, swap); return result; } -GrB_Info matrix_mxm_empty(Matrix *output, Matrix *first, Matrix *second, bool accum) { +GrB_Info matrix_mxm_empty(Matrix *output, Matrix *first, Matrix *second, bool accum, + bool swap) { if (first->nvals == 0 || second->nvals == 0) return GrB_SUCCESS; - return matrix_mxm_format(output, first, second, accum); + return matrix_mxm_format(output, first, second, accum, swap); } GrB_Info matrix_rmxm_format(Matrix *output, Matrix *first, Matrix *second, bool accum) { @@ -395,6 +414,7 @@ GrB_Info matrix_wise_empty(Matrix *output, Matrix *first, Matrix *second, bool a return matrix_wise_format(output, first, second, accum); } + printf(""); GrB_Info matrix_rsub(Matrix *output, Matrix *mask) { GrB_Info result = GrB_eWiseAdd(output->base, mask->base, GrB_NULL, GxB_ANY_BOOL, output->base, output->base, GrB_DESC_RSC); @@ -720,7 +740,7 @@ GrB_Info LAGraph_CFL_reachability_adv( LAGraph_rule_WCNF bin_rule = rules[bin_rules[i]]; matrix_mxm_empty(&temp_matrices[bin_rule.nonterm], &matrices[bin_rule.prod_A], - &delta_matrices[bin_rule.prod_B], false); + &delta_matrices[bin_rule.prod_B], false, false); } TIMER_STOP("MXM 1", &mxm1); @@ -734,9 +754,9 @@ GrB_Info LAGraph_CFL_reachability_adv( for (size_t i = 0; i < bin_rules_count; i++) { LAGraph_rule_WCNF bin_rule = rules[bin_rules[i]]; - matrix_rmxm_empty(&temp_matrices[bin_rule.nonterm], - &delta_matrices[bin_rule.prod_A], - &matrices[bin_rule.prod_B], true); + matrix_mxm_empty(&temp_matrices[bin_rule.nonterm], + &delta_matrices[bin_rule.prod_A], &matrices[bin_rule.prod_B], + true, true); } TIMER_STOP("MXM 2", &mxm2); From 901323df60b7a58c2244dc3c7e664aaeea76acc0 Mon Sep 17 00:00:00 2001 From: Homka122 Date: Wed, 14 May 2025 21:52:42 +0300 Subject: [PATCH 036/122] Refactor: matrix mxm with swap operation --- .../LAGraph_CFL_reachability_advanced.c | 20 +++++-------------- 1 file changed, 5 insertions(+), 15 deletions(-) diff --git a/experimental/algorithm/LAGraph_CFL_reachability_advanced.c b/experimental/algorithm/LAGraph_CFL_reachability_advanced.c index 0d0546c382..18fb758de3 100644 --- a/experimental/algorithm/LAGraph_CFL_reachability_advanced.c +++ b/experimental/algorithm/LAGraph_CFL_reachability_advanced.c @@ -286,19 +286,10 @@ GrB_Info matrix_mxm(Matrix *output, Matrix *first, Matrix *second, bool accum, GrB_Info matrix_mxm_format(Matrix *output, Matrix *first, Matrix *second, bool accum, bool swap) { - if (swap) { - Matrix *temp = first; - first = second; - second = temp; - } - - int32_t desired_orientation = - first->nvals > second->nvals ? GrB_COLMAJOR : GrB_ROWMAJOR; + GrB_Index left_nvals = swap ? second->nvals : first->nvals; + GrB_Index right_nvals = swap ? first->nvals : second->nvals; - if (swap) { - desired_orientation = - desired_orientation == GrB_ROWMAJOR ? GrB_COLMAJOR : GrB_ROWMAJOR; - } + int32_t desired_orientation = left_nvals < right_nvals ? GrB_ROWMAJOR : GrB_COLMAJOR; if (!first->is_both && first->format != desired_orientation && !(first->nvals > second->nvals / 3.0)) { @@ -754,9 +745,8 @@ GrB_Info LAGraph_CFL_reachability_adv( for (size_t i = 0; i < bin_rules_count; i++) { LAGraph_rule_WCNF bin_rule = rules[bin_rules[i]]; - matrix_mxm_empty(&temp_matrices[bin_rule.nonterm], - &delta_matrices[bin_rule.prod_A], &matrices[bin_rule.prod_B], - true, true); + matrix_mxm_empty(&temp_matrices[bin_rule.nonterm], &matrices[bin_rule.prod_B], + &delta_matrices[bin_rule.prod_A], true, true); } TIMER_STOP("MXM 2", &mxm2); From 61f90aab55f67d0acf4f8217b2327e3fb11d06f9 Mon Sep 17 00:00:00 2001 From: Homka122 Date: Wed, 14 May 2025 21:53:05 +0300 Subject: [PATCH 037/122] Feat: add lazy optimization --- .../LAGraph_CFL_reachability_advanced.c | 103 ++++++++++++++---- 1 file changed, 81 insertions(+), 22 deletions(-) diff --git a/experimental/algorithm/LAGraph_CFL_reachability_advanced.c b/experimental/algorithm/LAGraph_CFL_reachability_advanced.c index 18fb758de3..9c06fb51e7 100644 --- a/experimental/algorithm/LAGraph_CFL_reachability_advanced.c +++ b/experimental/algorithm/LAGraph_CFL_reachability_advanced.c @@ -138,14 +138,17 @@ } \ } -typedef struct { +typedef struct Matrix { GrB_Matrix base; GrB_Matrix base_row; GrB_Matrix base_col; + struct Matrix *base_matrices; + size_t base_matrices_count; GrB_Index nvals; GrB_Index size; int32_t format; bool is_both; + bool is_lazy; } Matrix; void matrix_update(Matrix *matrix) { @@ -159,6 +162,8 @@ Matrix matrix_from_base(GrB_Matrix matrix) { result.base = matrix; result.base_row = matrix; result.base_col = NULL; + result.base_matrices = NULL; + result.base_matrices_count = 0; result.nvals = 0; result.size = 0; result.format = GrB_ROWMAJOR; @@ -312,32 +317,38 @@ GrB_Info matrix_mxm_empty(Matrix *output, Matrix *first, Matrix *second, bool ac return matrix_mxm_format(output, first, second, accum, swap); } -GrB_Info matrix_rmxm_format(Matrix *output, Matrix *first, Matrix *second, bool accum) { - Matrix *temp = first; - first = second; - second = temp; +GrB_Info matrix_mxm_lazy(Matrix *output, Matrix *first, Matrix *second, bool accum, + bool swap) { + if (swap) { + Matrix *temp = first; + first = second; + second = temp; + } - int32_t desired_orientation = - first->nvals > second->nvals ? GrB_ROWMAJOR : GrB_COLMAJOR; + if (first->base_matrices_count == 0) { + return matrix_mxm_empty(output, first, second, accum, swap); + } - if (!first->is_both && first->format != desired_orientation && - !(first->nvals > second->nvals / 3.0)) { - GrB_Info result = matrix_mxm(output, second, first, accum); - return result; + GrB_Matrix *accs = malloc(sizeof(GrB_Matrix) * first->base_matrices_count); + Matrix *acc_matrices = malloc(sizeof(Matrix) * first->base_matrices_count); + for (size_t i = 0; i < first->base_matrices_count; i++) { + GrB_Matrix_new(&accs[i], GrB_BOOL, output->size, output->size); + acc_matrices[i] = matrix_from_base(accs[i]); } - matrix_to_format(first, desired_orientation, true); - matrix_to_format(second, desired_orientation, false); - matrix_to_format(output, desired_orientation, false); - GrB_Info result = matrix_mxm(output, second, first, accum); - return result; -} + for (size_t i = 0; i < first->base_matrices_count; i++) { + matrix_mxm_empty(&acc_matrices[i], &first->base_matrices[i], second, accum, swap); + } -GrB_Info matrix_rmxm_empty(Matrix *output, Matrix *first, Matrix *second, bool accum) { - if (first->nvals == 0 || second->nvals == 0) - return GrB_SUCCESS; + GrB_Matrix acc; + GrB_Matrix_new(&acc, GrB_BOOL, first->size, first->size); + Matrix acc_matrix = matrix_from_base(acc); - return matrix_rmxm_format(output, first, second, accum); + for (size_t i = 0; i < first->base_matrices_count; i++) { + matrix_wise_empty(&acc_matrix, &acc_matrix, &acc_matrices[i], false); + } + + return matrix_dup_empty(output, &acc_matrix); } GrB_Info matrix_wise(Matrix *output, Matrix *first, Matrix *second, bool accum) { @@ -405,7 +416,43 @@ GrB_Info matrix_wise_empty(Matrix *output, Matrix *first, Matrix *second, bool a return matrix_wise_format(output, first, second, accum); } - printf(""); +GrB_Info matrix_wise_lazy(Matrix *output, Matrix *first, Matrix *second, bool accum) { + if (first->base_matrices_count == 0) { + return matrix_wise_empty(output, first, second, accum); + } + + GrB_Matrix _other; + GrB_Matrix_new(&_other, GrB_BOOL, output->size, output->size); + Matrix other = matrix_from_base(_other); + matrix_dup_empty(&other, second); + + while (true) { + bool found = false; + + for (size_t i = 0; i < first->base_matrices_count; i++) { + if (other.nvals / 10 < first->base_matrices[i].nvals && + first->base_matrices[i].nvals < other.nvals * 10) { + matrix_wise_empty(&other, &other, &first->base_matrices[i], false); + for (size_t j = i + 1; j < first->base_matrices_count; j++) { + first->base_matrices[j - 1] = first->base_matrices[j]; + } + first->base_matrices_count--; + found = true; + break; + } + } + + if (found) { + continue; + } + + first->base_matrices[first->base_matrices_count++] = other; + break; + } + + return GrB_SUCCESS; +} + GrB_Info matrix_rsub(Matrix *output, Matrix *mask) { GrB_Info result = GrB_eWiseAdd(output->base, mask->base, GrB_NULL, GxB_ANY_BOOL, output->base, output->base, GrB_DESC_RSC); @@ -444,6 +491,18 @@ GrB_Info matrix_rsub_empty(Matrix *output, Matrix *mask) { return matrix_rsub_format(output, mask); } +GrB_Info matrix_rsub_lazy(Matrix *output, Matrix *mask) { + if (mask->base_matrices_count == 0) { + return matrix_rsub_empty(output, mask); + } + + for (size_t i = 0; i < mask->base_matrices_count; i++) { + matrix_rsub_empty(output, &mask->base_matrices[i]); + } + + return GrB_SUCCESS; +} + // LAGraph_CFL_reachability: Context-Free Language Reachability Matrix-Based Algorithm // // This function determines the set of vertex pairs (u, v) in a graph (represented by From fd2502e69748eb7abf9af62a8010b7ef1f732800 Mon Sep 17 00:00:00 2001 From: Homka122 Date: Thu, 15 May 2025 10:39:02 +0300 Subject: [PATCH 038/122] Fix: change < to <= --- experimental/algorithm/LAGraph_CFL_reachability_advanced.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/experimental/algorithm/LAGraph_CFL_reachability_advanced.c b/experimental/algorithm/LAGraph_CFL_reachability_advanced.c index 9c06fb51e7..b4c79b8507 100644 --- a/experimental/algorithm/LAGraph_CFL_reachability_advanced.c +++ b/experimental/algorithm/LAGraph_CFL_reachability_advanced.c @@ -294,7 +294,7 @@ GrB_Info matrix_mxm_format(Matrix *output, Matrix *first, Matrix *second, bool a GrB_Index left_nvals = swap ? second->nvals : first->nvals; GrB_Index right_nvals = swap ? first->nvals : second->nvals; - int32_t desired_orientation = left_nvals < right_nvals ? GrB_ROWMAJOR : GrB_COLMAJOR; + int32_t desired_orientation = left_nvals <= right_nvals ? GrB_ROWMAJOR : GrB_COLMAJOR; if (!first->is_both && first->format != desired_orientation && !(first->nvals > second->nvals / 3.0)) { From 7b0a5e192a0cea2a244952c80f2a5b06b62ebd1c Mon Sep 17 00:00:00 2001 From: Homka122 Date: Thu, 15 May 2025 11:13:52 +0300 Subject: [PATCH 039/122] Feat: use lazy optimization --- .../LAGraph_CFL_reachability_advanced.c | 49 +++++++++++++------ 1 file changed, 33 insertions(+), 16 deletions(-) diff --git a/experimental/algorithm/LAGraph_CFL_reachability_advanced.c b/experimental/algorithm/LAGraph_CFL_reachability_advanced.c index b4c79b8507..910918d017 100644 --- a/experimental/algorithm/LAGraph_CFL_reachability_advanced.c +++ b/experimental/algorithm/LAGraph_CFL_reachability_advanced.c @@ -162,7 +162,7 @@ Matrix matrix_from_base(GrB_Matrix matrix) { result.base = matrix; result.base_row = matrix; result.base_col = NULL; - result.base_matrices = NULL; + result.base_matrices = malloc(sizeof(Matrix) * 10); result.base_matrices_count = 0; result.nvals = 0; result.size = 0; @@ -319,12 +319,6 @@ GrB_Info matrix_mxm_empty(Matrix *output, Matrix *first, Matrix *second, bool ac GrB_Info matrix_mxm_lazy(Matrix *output, Matrix *first, Matrix *second, bool accum, bool swap) { - if (swap) { - Matrix *temp = first; - first = second; - second = temp; - } - if (first->base_matrices_count == 0) { return matrix_mxm_empty(output, first, second, accum, swap); } @@ -418,7 +412,8 @@ GrB_Info matrix_wise_empty(Matrix *output, Matrix *first, Matrix *second, bool a GrB_Info matrix_wise_lazy(Matrix *output, Matrix *first, Matrix *second, bool accum) { if (first->base_matrices_count == 0) { - return matrix_wise_empty(output, first, second, accum); + first->base_matrices_count = 1; + first->base_matrices[0] = matrix_from_base(first->base); } GrB_Matrix _other; @@ -503,6 +498,25 @@ GrB_Info matrix_rsub_lazy(Matrix *output, Matrix *mask) { return GrB_SUCCESS; } +void matrix_print_lazy(Matrix A) { + if (A.base_matrices_count == 0) { + GxB_print(A.base, 1); + } + + if (A.base_matrices_count == 1) { + GxB_print(A.base_matrices[0].base, 1); + } + + GrB_Matrix _temp; + GrB_Matrix_new(&_temp, GrB_BOOL, A.size, A.size); + Matrix temp = matrix_from_base(_temp); + for (size_t i = 0; i < A.base_matrices_count; i++) { + matrix_wise_empty(&temp, &temp, &A.base_matrices[i], false); + } + + GxB_print(temp.base, 1); +} + // LAGraph_CFL_reachability: Context-Free Language Reachability Matrix-Based Algorithm // // This function determines the set of vertex pairs (u, v) in a graph (represented by @@ -789,14 +803,15 @@ GrB_Info LAGraph_CFL_reachability_adv( for (size_t i = 0; i < bin_rules_count; i++) { LAGraph_rule_WCNF bin_rule = rules[bin_rules[i]]; - matrix_mxm_empty(&temp_matrices[bin_rule.nonterm], &matrices[bin_rule.prod_A], - &delta_matrices[bin_rule.prod_B], false, false); + matrix_mxm_lazy(&temp_matrices[bin_rule.nonterm], &matrices[bin_rule.prod_A], + &delta_matrices[bin_rule.prod_B], false, false); + matrix_print_lazy(temp_matrices[bin_rule.nonterm]); } TIMER_STOP("MXM 1", &mxm1); TIMER_START() for (int32_t i = 0; i < nonterms_count; i++) { - matrix_wise_empty(&matrices[i], &matrices[i], &delta_matrices[i], false); + matrix_wise_lazy(&matrices[i], &matrices[i], &delta_matrices[i], false); } TIMER_STOP("WISE 1", &wise1); @@ -804,8 +819,8 @@ GrB_Info LAGraph_CFL_reachability_adv( for (size_t i = 0; i < bin_rules_count; i++) { LAGraph_rule_WCNF bin_rule = rules[bin_rules[i]]; - matrix_mxm_empty(&temp_matrices[bin_rule.nonterm], &matrices[bin_rule.prod_B], - &delta_matrices[bin_rule.prod_A], true, true); + matrix_mxm_lazy(&temp_matrices[bin_rule.nonterm], &matrices[bin_rule.prod_B], + &delta_matrices[bin_rule.prod_A], true, true); } TIMER_STOP("MXM 2", &mxm2); @@ -817,13 +832,15 @@ GrB_Info LAGraph_CFL_reachability_adv( TIMER_START(); for (int32_t i = 0; i < nonterms_count; i++) { - matrix_rsub_empty(&delta_matrices[i], &matrices[i]); + matrix_rsub_lazy(&delta_matrices[i], &matrices[i]); } TIMER_STOP("WISE 3 (MASK)", &rsub); for (int32_t i = 0; i < nonterms_count; i++) { - GrB_Index new_nnz; - GRB_TRY(GrB_Matrix_nvals(&new_nnz, matrices[i].base)); + size_t new_nnz = 0; + for (size_t j = 0; j < matrices[i].base_matrices_count; j++) { + new_nnz += matrices[i].base_matrices[j].nvals; + } changed = changed || (nnzs[i] != new_nnz); nnzs[i] = new_nnz; From 935baef51e09d6b6553353a95debdfba50af2eeb Mon Sep 17 00:00:00 2001 From: Homka122 Date: Thu, 15 May 2025 11:44:15 +0300 Subject: [PATCH 040/122] Feat: add flags for turn on optimizations on runtime --- .../LAGraph_CFL_reachability_advanced.c | 64 +++++++++++++++---- 1 file changed, 51 insertions(+), 13 deletions(-) diff --git a/experimental/algorithm/LAGraph_CFL_reachability_advanced.c b/experimental/algorithm/LAGraph_CFL_reachability_advanced.c index 910918d017..77646c9290 100644 --- a/experimental/algorithm/LAGraph_CFL_reachability_advanced.c +++ b/experimental/algorithm/LAGraph_CFL_reachability_advanced.c @@ -121,6 +121,10 @@ #endif // clang-format on +#define OPT_EMPTY (1 << 0) +#define OPT_FORMAT (1 << 1) +#define OPT_LAZY (1 << 2) + #define SKIP_IF_NULL(matrix) \ GrB_Matrix_nvals(&new_nnz, matrix); \ if (new_nnz == 0) { \ @@ -501,10 +505,12 @@ GrB_Info matrix_rsub_lazy(Matrix *output, Matrix *mask) { void matrix_print_lazy(Matrix A) { if (A.base_matrices_count == 0) { GxB_print(A.base, 1); + return; } if (A.base_matrices_count == 1) { GxB_print(A.base_matrices[0].base, 1); + return; } GrB_Matrix _temp; @@ -580,7 +586,8 @@ GrB_Info LAGraph_CFL_reachability_adv( int32_t nonterms_count, // The total number of non-terminal symbols in the CFG. const LAGraph_rule_WCNF *rules, // The rules of the CFG. size_t rules_count, // The total number of rules in the CFG. - char *msg // Message string for error reporting. + char *msg, // Message string for error reporting. + int8_t optimizations // Optimizations flags ) { // Declare workspace and clear the msg string, if not NULL GrB_Matrix *T; @@ -779,6 +786,34 @@ GrB_Info LAGraph_CFL_reachability_adv( // Rule [Variable -> Variable1 Variable2] LG_TRY(LAGraph_Calloc((void **)&nnzs, nonterms_count, sizeof(uint64_t), msg)); + typedef GrB_Info (*matrix_mxm_fn)(Matrix *output, Matrix *first, Matrix *second, + bool accum, bool swap); + typedef GrB_Info (*matrix_wise_fn)(Matrix *output, Matrix *first, Matrix *second, + bool accum); + typedef GrB_Info (*matrix_rsub_fn)(Matrix *input, Matrix *mask); + + matrix_mxm_fn mxm; + matrix_wise_fn wise; + matrix_rsub_fn rsub; + + if (optimizations & OPT_LAZY) { + mxm = matrix_mxm_lazy; + wise = matrix_wise_lazy; + rsub = matrix_rsub_lazy; + } else if (optimizations & OPT_EMPTY) { + mxm = matrix_mxm_empty; + wise = matrix_wise_empty; + rsub = matrix_rsub_empty; + } else if (optimizations & OPT_FORMAT) { + mxm = matrix_mxm_format; + wise = matrix_wise_format; + rsub = matrix_rsub_format; + } else { + mxm = matrix_mxm; + wise = matrix_wise; + rsub = matrix_rsub; + } + double start_time, end_time; bool changed = true; size_t iteration = 0; @@ -786,7 +821,7 @@ GrB_Info LAGraph_CFL_reachability_adv( double wise1 = 0.0; double mxm2 = 0.0; double wise2 = 0.0; - double rsub = 0.0; + double rsubt = 0.0; while (changed) { iteration++; changed = false; @@ -803,15 +838,14 @@ GrB_Info LAGraph_CFL_reachability_adv( for (size_t i = 0; i < bin_rules_count; i++) { LAGraph_rule_WCNF bin_rule = rules[bin_rules[i]]; - matrix_mxm_lazy(&temp_matrices[bin_rule.nonterm], &matrices[bin_rule.prod_A], - &delta_matrices[bin_rule.prod_B], false, false); - matrix_print_lazy(temp_matrices[bin_rule.nonterm]); + mxm(&temp_matrices[bin_rule.nonterm], &matrices[bin_rule.prod_A], + &delta_matrices[bin_rule.prod_B], false, false); } TIMER_STOP("MXM 1", &mxm1); TIMER_START() for (int32_t i = 0; i < nonterms_count; i++) { - matrix_wise_lazy(&matrices[i], &matrices[i], &delta_matrices[i], false); + wise(&matrices[i], &matrices[i], &delta_matrices[i], false); } TIMER_STOP("WISE 1", &wise1); @@ -819,8 +853,8 @@ GrB_Info LAGraph_CFL_reachability_adv( for (size_t i = 0; i < bin_rules_count; i++) { LAGraph_rule_WCNF bin_rule = rules[bin_rules[i]]; - matrix_mxm_lazy(&temp_matrices[bin_rule.nonterm], &matrices[bin_rule.prod_B], - &delta_matrices[bin_rule.prod_A], true, true); + mxm(&temp_matrices[bin_rule.nonterm], &matrices[bin_rule.prod_B], + &delta_matrices[bin_rule.prod_A], true, true); } TIMER_STOP("MXM 2", &mxm2); @@ -832,14 +866,18 @@ GrB_Info LAGraph_CFL_reachability_adv( TIMER_START(); for (int32_t i = 0; i < nonterms_count; i++) { - matrix_rsub_lazy(&delta_matrices[i], &matrices[i]); + rsub(&delta_matrices[i], &matrices[i]); } - TIMER_STOP("WISE 3 (MASK)", &rsub); + TIMER_STOP("WISE 3 (MASK)", &rsubt); for (int32_t i = 0; i < nonterms_count; i++) { size_t new_nnz = 0; - for (size_t j = 0; j < matrices[i].base_matrices_count; j++) { - new_nnz += matrices[i].base_matrices[j].nvals; + if (matrices[i].base_matrices_count == 0) { + new_nnz = matrices[i].nvals; + } else { + for (size_t j = 0; j < matrices[i].base_matrices_count; j++) { + new_nnz += matrices[i].base_matrices[j].nvals; + } } changed = changed || (nnzs[i] != new_nnz); @@ -856,7 +894,7 @@ GrB_Info LAGraph_CFL_reachability_adv( #if BENCH_CFL_REACHBILITY printf("MXM1: %.3f, wise1: %.3f, MXM2: %.3f, wise2: %.3f, rsub: %.3f", mxm1, wise1, - mxm2, wise2, rsub); + mxm2, wise2, rsubt); #endif #ifdef DEBUG_CFL_REACHBILITY From aa0dd4a778524bd1b41b0c3419db9b81c4cb4a67 Mon Sep 17 00:00:00 2001 From: Homka122 Date: Thu, 15 May 2025 11:54:37 +0300 Subject: [PATCH 041/122] Feat: matrix_print_lazy now accepts pointer --- .../LAGraph_CFL_reachability_advanced.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/experimental/algorithm/LAGraph_CFL_reachability_advanced.c b/experimental/algorithm/LAGraph_CFL_reachability_advanced.c index 77646c9290..a7f04101c1 100644 --- a/experimental/algorithm/LAGraph_CFL_reachability_advanced.c +++ b/experimental/algorithm/LAGraph_CFL_reachability_advanced.c @@ -502,22 +502,22 @@ GrB_Info matrix_rsub_lazy(Matrix *output, Matrix *mask) { return GrB_SUCCESS; } -void matrix_print_lazy(Matrix A) { - if (A.base_matrices_count == 0) { - GxB_print(A.base, 1); +void matrix_print_lazy(Matrix *A) { + if (A->base_matrices_count == 0) { + GxB_print(A->base, 1); return; } - if (A.base_matrices_count == 1) { - GxB_print(A.base_matrices[0].base, 1); + if (A->base_matrices_count == 1) { + GxB_print(A->base_matrices[0].base, 1); return; } GrB_Matrix _temp; - GrB_Matrix_new(&_temp, GrB_BOOL, A.size, A.size); + GrB_Matrix_new(&_temp, GrB_BOOL, A->size, A->size); Matrix temp = matrix_from_base(_temp); - for (size_t i = 0; i < A.base_matrices_count; i++) { - matrix_wise_empty(&temp, &temp, &A.base_matrices[i], false); + for (size_t i = 0; i < A->base_matrices_count; i++) { + matrix_wise_empty(&temp, &temp, &A->base_matrices[i], false); } GxB_print(temp.base, 1); From 7184953128e765820022fcfb3fcbddaa5f3f887e Mon Sep 17 00:00:00 2001 From: Homka122 Date: Thu, 15 May 2025 11:58:27 +0300 Subject: [PATCH 042/122] Feat: add naming for matrices in methods --- .../LAGraph_CFL_reachability_advanced.c | 22 ++++++++++++++----- 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/experimental/algorithm/LAGraph_CFL_reachability_advanced.c b/experimental/algorithm/LAGraph_CFL_reachability_advanced.c index a7f04101c1..b0ded1343c 100644 --- a/experimental/algorithm/LAGraph_CFL_reachability_advanced.c +++ b/experimental/algorithm/LAGraph_CFL_reachability_advanced.c @@ -837,24 +837,31 @@ GrB_Info LAGraph_CFL_reachability_adv( TIMER_START(); for (size_t i = 0; i < bin_rules_count; i++) { LAGraph_rule_WCNF bin_rule = rules[bin_rules[i]]; + Matrix *A = &matrices[bin_rule.prod_A]; + Matrix *B = &delta_matrices[bin_rule.prod_B]; + Matrix *C = &temp_matrices[bin_rule.nonterm]; - mxm(&temp_matrices[bin_rule.nonterm], &matrices[bin_rule.prod_A], - &delta_matrices[bin_rule.prod_B], false, false); + mxm(C, A, B, false, false); } TIMER_STOP("MXM 1", &mxm1); TIMER_START() for (int32_t i = 0; i < nonterms_count; i++) { - wise(&matrices[i], &matrices[i], &delta_matrices[i], false); + Matrix *A = &delta_matrices[i]; + Matrix *C = &matrices[i]; + + wise(C, C, A, false); } TIMER_STOP("WISE 1", &wise1); TIMER_START() for (size_t i = 0; i < bin_rules_count; i++) { LAGraph_rule_WCNF bin_rule = rules[bin_rules[i]]; + Matrix *A = &matrices[bin_rule.prod_B]; + Matrix *B = &delta_matrices[bin_rule.prod_A]; + Matrix *C = &temp_matrices[bin_rule.nonterm]; - mxm(&temp_matrices[bin_rule.nonterm], &matrices[bin_rule.prod_B], - &delta_matrices[bin_rule.prod_A], true, true); + mxm(C, A, B, true, true); } TIMER_STOP("MXM 2", &mxm2); @@ -866,7 +873,10 @@ GrB_Info LAGraph_CFL_reachability_adv( TIMER_START(); for (int32_t i = 0; i < nonterms_count; i++) { - rsub(&delta_matrices[i], &matrices[i]); + Matrix *A = &matrices[i]; + Matrix *C = &delta_matrices[i]; + + rsub(C, A); } TIMER_STOP("WISE 3 (MASK)", &rsubt); From 66d55a89d1d1726f37be14128e392c3593477a72 Mon Sep 17 00:00:00 2001 From: Homka122 Date: Thu, 15 May 2025 12:37:55 +0300 Subject: [PATCH 043/122] Feat: lazy optimizations now works --- .../LAGraph_CFL_reachability_advanced.c | 47 +++++++++++++++++-- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/experimental/algorithm/LAGraph_CFL_reachability_advanced.c b/experimental/algorithm/LAGraph_CFL_reachability_advanced.c index b0ded1343c..202c9a8d4c 100644 --- a/experimental/algorithm/LAGraph_CFL_reachability_advanced.c +++ b/experimental/algorithm/LAGraph_CFL_reachability_advanced.c @@ -156,7 +156,16 @@ typedef struct Matrix { } Matrix; void matrix_update(Matrix *matrix) { - GrB_Matrix_nvals(&matrix->nvals, matrix->base); + if (matrix->base_matrices_count == 0) { + GrB_Matrix_nvals(&matrix->nvals, matrix->base); + } else { + size_t new_nnz = 0; + for (size_t i = 0; i < matrix->base_matrices_count; i++) { + new_nnz += matrix->base_matrices[i].nvals; + } + + matrix->nvals = new_nnz; + } GrB_Matrix_nrows(&matrix->size, matrix->base); // GrB_get(matrix->base, &matrix->format, GrB_STORAGE_ORIENTATION_HINT); } @@ -166,7 +175,7 @@ Matrix matrix_from_base(GrB_Matrix matrix) { result.base = matrix; result.base_row = matrix; result.base_col = NULL; - result.base_matrices = malloc(sizeof(Matrix) * 10); + result.base_matrices = malloc(sizeof(Matrix) * 40); result.base_matrices_count = 0; result.nvals = 0; result.size = 0; @@ -346,6 +355,10 @@ GrB_Info matrix_mxm_lazy(Matrix *output, Matrix *first, Matrix *second, bool acc matrix_wise_empty(&acc_matrix, &acc_matrix, &acc_matrices[i], false); } + if (accum) { + return matrix_wise_empty(output, output, &acc_matrix, false); + } + return matrix_dup_empty(output, &acc_matrix); } @@ -520,7 +533,8 @@ void matrix_print_lazy(Matrix *A) { matrix_wise_empty(&temp, &temp, &A->base_matrices[i], false); } - GxB_print(temp.base, 1); + A = &temp; + GxB_print(A->base, 1); } // LAGraph_CFL_reachability: Context-Free Language Reachability Matrix-Based Algorithm @@ -842,6 +856,9 @@ GrB_Info LAGraph_CFL_reachability_adv( Matrix *C = &temp_matrices[bin_rule.nonterm]; mxm(C, A, B, false, false); + // matrix_print_lazy(A); + // matrix_print_lazy(B); + // matrix_print_lazy(C); } TIMER_STOP("MXM 1", &mxm1); @@ -851,6 +868,8 @@ GrB_Info LAGraph_CFL_reachability_adv( Matrix *C = &matrices[i]; wise(C, C, A, false); + // matrix_print_lazy(A); + // matrix_print_lazy(C); } TIMER_STOP("WISE 1", &wise1); @@ -860,8 +879,11 @@ GrB_Info LAGraph_CFL_reachability_adv( Matrix *A = &matrices[bin_rule.prod_B]; Matrix *B = &delta_matrices[bin_rule.prod_A]; Matrix *C = &temp_matrices[bin_rule.nonterm]; - + // printf("ITER: %ld\n", i); mxm(C, A, B, true, true); + // matrix_print_lazy(A); + // matrix_print_lazy(B); + // matrix_print_lazy(C); } TIMER_STOP("MXM 2", &mxm2); @@ -877,6 +899,8 @@ GrB_Info LAGraph_CFL_reachability_adv( Matrix *C = &delta_matrices[i]; rsub(C, A); + // matrix_print_lazy(A); + // matrix_print_lazy(C); } TIMER_STOP("WISE 3 (MASK)", &rsubt); @@ -915,7 +939,20 @@ GrB_Info LAGraph_CFL_reachability_adv( #endif for (int32_t i = 0; i < nonterms_count; i++) { - outputs[i] = matrices[i].base; + if (matrices[i].base_matrices_count == 0) { + outputs[i] = matrices[i].base; + } else { + GrB_Matrix _acc; + GrB_Matrix_new(&_acc, GrB_BOOL, matrices[i].size, matrices[i].size); + Matrix acc = matrix_from_base(_acc); + + for (size_t j = 0; j < matrices[i].base_matrices_count; j++) { + matrix_wise_empty(&acc, &acc, &matrices[i].base_matrices[j], false); + } + + outputs[i] = acc.base; + } + // outputs[i] = matrices[i].base; } LG_FREE_WORK; From 6d97d8279747cd80da2097b9d5cf11b44c04b1da Mon Sep 17 00:00:00 2001 From: Homka122 Date: Thu, 15 May 2025 13:53:58 +0300 Subject: [PATCH 044/122] Fix: erase matrix when accum true in mxm --- .../algorithm/LAGraph_CFL_reachability_advanced.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/experimental/algorithm/LAGraph_CFL_reachability_advanced.c b/experimental/algorithm/LAGraph_CFL_reachability_advanced.c index 202c9a8d4c..999263d426 100644 --- a/experimental/algorithm/LAGraph_CFL_reachability_advanced.c +++ b/experimental/algorithm/LAGraph_CFL_reachability_advanced.c @@ -324,8 +324,13 @@ GrB_Info matrix_mxm_format(Matrix *output, Matrix *first, Matrix *second, bool a GrB_Info matrix_mxm_empty(Matrix *output, Matrix *first, Matrix *second, bool accum, bool swap) { - if (first->nvals == 0 || second->nvals == 0) - return GrB_SUCCESS; + if (first->nvals == 0 || second->nvals == 0) { + if (accum) { + return GrB_SUCCESS; + } + + matrix_clear_empty(output); + } return matrix_mxm_format(output, first, second, accum, swap); } From 146d58ce02acc47120dbb5f663f8995b6a52174b Mon Sep 17 00:00:00 2001 From: Homka122 Date: Fri, 16 May 2025 19:09:46 +0300 Subject: [PATCH 045/122] Feat: add sort and combine function to lazy optimization --- .../LAGraph_CFL_reachability_advanced.c | 58 ++++++++++++++++++- 1 file changed, 56 insertions(+), 2 deletions(-) diff --git a/experimental/algorithm/LAGraph_CFL_reachability_advanced.c b/experimental/algorithm/LAGraph_CFL_reachability_advanced.c index 999263d426..c540a2f96e 100644 --- a/experimental/algorithm/LAGraph_CFL_reachability_advanced.c +++ b/experimental/algorithm/LAGraph_CFL_reachability_advanced.c @@ -290,6 +290,41 @@ GrB_Info matrix_dup_empty(Matrix *output, Matrix *input) { GrB_Info matrix_wise_empty(Matrix *output, Matrix *first, Matrix *second, bool accum); +GrB_Info matrix_sort_lazy(Matrix *A, bool reverse) { + for (size_t i = 0; i < A->base_matrices_count; i++) { + for (size_t j = i + 1; j < A->base_matrices_count; j++) { + Matrix first = reverse ? A->base_matrices[i] : A->base_matrices[j]; + Matrix second = reverse ? A->base_matrices[j] : A->base_matrices[i]; + if (first.nvals < second.nvals) { + Matrix temp = A->base_matrices[i]; + A->base_matrices[i] = A->base_matrices[j]; + A->base_matrices[j] = temp; + } + } + } +} + +GrB_Info matrix_combine_lazy(Matrix *A, size_t threshold) { + Matrix *new_matrices = malloc(sizeof(Matrix) * 50); + size_t new_size = 0; + + matrix_sort_lazy(A, false); + + for (size_t i = 0; i < A->base_matrices_count; i++) { + if (A->base_matrices[i].nvals <= threshold && new_size > 0) { + matrix_wise_empty(&new_matrices[new_size - 1], &new_matrices[new_size - 1], + &A->base_matrices[i], false); + } else { + new_matrices[new_size++] = A->base_matrices[i]; + } + } + + A->base_matrices = new_matrices; + A->base_matrices_count = new_size; + + return GrB_SUCCESS; +} + GrB_Info matrix_mxm(Matrix *output, Matrix *first, Matrix *second, bool accum, bool swap) { Matrix *left = swap ? second : first; @@ -341,6 +376,9 @@ GrB_Info matrix_mxm_lazy(Matrix *output, Matrix *first, Matrix *second, bool acc return matrix_mxm_empty(output, first, second, accum, swap); } + matrix_sort_lazy(first, true); + matrix_combine_lazy(first, second->nvals); + GrB_Matrix *accs = malloc(sizeof(GrB_Matrix) * first->base_matrices_count); Matrix *acc_matrices = malloc(sizeof(Matrix) * first->base_matrices_count); for (size_t i = 0; i < first->base_matrices_count; i++) { @@ -352,6 +390,16 @@ GrB_Info matrix_mxm_lazy(Matrix *output, Matrix *first, Matrix *second, bool acc matrix_mxm_empty(&acc_matrices[i], &first->base_matrices[i], second, accum, swap); } + for (size_t i = 0; i < first->base_matrices_count; i++) { + for (size_t j = i + 1; j < first->base_matrices_count; j++) { + if (acc_matrices[i].nvals < acc_matrices[j].nvals) { + Matrix temp = acc_matrices[i]; + acc_matrices[i] = acc_matrices[j]; + acc_matrices[j] = temp; + } + } + } + GrB_Matrix acc; GrB_Matrix_new(&acc, GrB_BOOL, first->size, first->size); Matrix acc_matrix = matrix_from_base(acc); @@ -443,12 +491,15 @@ GrB_Info matrix_wise_lazy(Matrix *output, Matrix *first, Matrix *second, bool ac Matrix other = matrix_from_base(_other); matrix_dup_empty(&other, second); + size_t other_nvals = other.nvals >= 10 ? other.nvals : 10; + while (true) { bool found = false; for (size_t i = 0; i < first->base_matrices_count; i++) { - if (other.nvals / 10 < first->base_matrices[i].nvals && - first->base_matrices[i].nvals < other.nvals * 10) { + size_t self_nvals = first->base_matrices[i].nvals >= 10 ? first->nvals : 10; + + if (other.nvals / 10 <= self_nvals && self_nvals <= other.nvals * 10) { matrix_wise_empty(&other, &other, &first->base_matrices[i], false); for (size_t j = i + 1; j < first->base_matrices_count; j++) { first->base_matrices[j - 1] = first->base_matrices[j]; @@ -513,6 +564,9 @@ GrB_Info matrix_rsub_lazy(Matrix *output, Matrix *mask) { return matrix_rsub_empty(output, mask); } + matrix_sort_lazy(mask, true); + matrix_combine_lazy(mask, output->nvals); + for (size_t i = 0; i < mask->base_matrices_count; i++) { matrix_rsub_empty(output, &mask->base_matrices[i]); } From bd2c142d98b51b83912c7ddfd7adc045c088c2e8 Mon Sep 17 00:00:00 2001 From: Homka122 Date: Sat, 17 May 2025 12:37:43 +0300 Subject: [PATCH 046/122] Fix: some memory leaks --- .../algorithm/LAGraph_CFL_reachability_advanced.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/experimental/algorithm/LAGraph_CFL_reachability_advanced.c b/experimental/algorithm/LAGraph_CFL_reachability_advanced.c index c540a2f96e..bdb97ea892 100644 --- a/experimental/algorithm/LAGraph_CFL_reachability_advanced.c +++ b/experimental/algorithm/LAGraph_CFL_reachability_advanced.c @@ -314,6 +314,7 @@ GrB_Info matrix_combine_lazy(Matrix *A, size_t threshold) { if (A->base_matrices[i].nvals <= threshold && new_size > 0) { matrix_wise_empty(&new_matrices[new_size - 1], &new_matrices[new_size - 1], &A->base_matrices[i], false); + GrB_free(&A->base_matrices[i].base); } else { new_matrices[new_size++] = A->base_matrices[i]; } @@ -406,13 +407,17 @@ GrB_Info matrix_mxm_lazy(Matrix *output, Matrix *first, Matrix *second, bool acc for (size_t i = 0; i < first->base_matrices_count; i++) { matrix_wise_empty(&acc_matrix, &acc_matrix, &acc_matrices[i], false); + GrB_free(&acc_matrices[i].base); } if (accum) { return matrix_wise_empty(output, output, &acc_matrix, false); } - return matrix_dup_empty(output, &acc_matrix); + GrB_Info result = matrix_dup_empty(output, &acc_matrix); + GrB_free(&acc_matrix.base); + + return result; } GrB_Info matrix_wise(Matrix *output, Matrix *first, Matrix *second, bool accum) { @@ -501,6 +506,7 @@ GrB_Info matrix_wise_lazy(Matrix *output, Matrix *first, Matrix *second, bool ac if (other.nvals / 10 <= self_nvals && self_nvals <= other.nvals * 10) { matrix_wise_empty(&other, &other, &first->base_matrices[i], false); + GrB_free(&first->base_matrices[i].base); for (size_t j = i + 1; j < first->base_matrices_count; j++) { first->base_matrices[j - 1] = first->base_matrices[j]; } @@ -594,6 +600,7 @@ void matrix_print_lazy(Matrix *A) { A = &temp; GxB_print(A->base, 1); + GrB_free(&_temp); } // LAGraph_CFL_reachability: Context-Free Language Reachability Matrix-Based Algorithm @@ -1007,6 +1014,7 @@ GrB_Info LAGraph_CFL_reachability_adv( for (size_t j = 0; j < matrices[i].base_matrices_count; j++) { matrix_wise_empty(&acc, &acc, &matrices[i].base_matrices[j], false); + GrB_free(&matrices[i].base_matrices[j].base); } outputs[i] = acc.base; From c0eae50757ee8a4e42781493782cb743c2b020d4 Mon Sep 17 00:00:00 2001 From: Homka122 Date: Sat, 17 May 2025 13:26:11 +0300 Subject: [PATCH 047/122] Feat: now matrix has not just mxm size --- .../LAGraph_CFL_reachability_advanced.c | 25 +++++++++++-------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/experimental/algorithm/LAGraph_CFL_reachability_advanced.c b/experimental/algorithm/LAGraph_CFL_reachability_advanced.c index bdb97ea892..98a43961e4 100644 --- a/experimental/algorithm/LAGraph_CFL_reachability_advanced.c +++ b/experimental/algorithm/LAGraph_CFL_reachability_advanced.c @@ -149,7 +149,8 @@ typedef struct Matrix { struct Matrix *base_matrices; size_t base_matrices_count; GrB_Index nvals; - GrB_Index size; + GrB_Index nrows; + GrB_Index ncols; int32_t format; bool is_both; bool is_lazy; @@ -166,7 +167,8 @@ void matrix_update(Matrix *matrix) { matrix->nvals = new_nnz; } - GrB_Matrix_nrows(&matrix->size, matrix->base); + GrB_Matrix_nrows(&matrix->nrows, matrix->base); + GrB_Matrix_ncols(&matrix->ncols, matrix->base); // GrB_get(matrix->base, &matrix->format, GrB_STORAGE_ORIENTATION_HINT); } @@ -178,7 +180,8 @@ Matrix matrix_from_base(GrB_Matrix matrix) { result.base_matrices = malloc(sizeof(Matrix) * 40); result.base_matrices_count = 0; result.nvals = 0; - result.size = 0; + result.nrows = 0; + result.ncols = 0; result.format = GrB_ROWMAJOR; result.is_both = false; matrix_update(&result); @@ -205,9 +208,9 @@ void matrix_to_format(Matrix *matrix, int32_t format, bool is_both) { matrix->format == GrB_ROWMAJOR ? &matrix->base_row : &matrix->base_col; if (is_both) { - GrB_Matrix_new(new_matrix, GrB_BOOL, matrix->size, matrix->size); + GrB_Matrix_new(new_matrix, GrB_BOOL, matrix->nrows, matrix->ncols); GrB_Matrix_assign(*new_matrix, GrB_NULL, GrB_NULL, *old_matrix, GrB_ALL, - matrix->size, GrB_ALL, matrix->size, GrB_NULL); + matrix->nrows, GrB_ALL, matrix->ncols, GrB_NULL); matrix->is_both = true; } else { *new_matrix = *old_matrix; @@ -253,7 +256,7 @@ GrB_Info matrix_clear_empty(Matrix *A) { GrB_Info matrix_dup(Matrix *output, Matrix *input) { GrB_Info result = GrB_Matrix_assign(output->base, GrB_NULL, GrB_NULL, input->base, GrB_ALL, - input->size, GrB_ALL, input->size, GrB_NULL); + input->nrows, GrB_ALL, input->ncols, GrB_NULL); matrix_update(output); return result; @@ -383,7 +386,7 @@ GrB_Info matrix_mxm_lazy(Matrix *output, Matrix *first, Matrix *second, bool acc GrB_Matrix *accs = malloc(sizeof(GrB_Matrix) * first->base_matrices_count); Matrix *acc_matrices = malloc(sizeof(Matrix) * first->base_matrices_count); for (size_t i = 0; i < first->base_matrices_count; i++) { - GrB_Matrix_new(&accs[i], GrB_BOOL, output->size, output->size); + GrB_Matrix_new(&accs[i], GrB_BOOL, output->nrows, output->ncols); acc_matrices[i] = matrix_from_base(accs[i]); } @@ -402,7 +405,7 @@ GrB_Info matrix_mxm_lazy(Matrix *output, Matrix *first, Matrix *second, bool acc } GrB_Matrix acc; - GrB_Matrix_new(&acc, GrB_BOOL, first->size, first->size); + GrB_Matrix_new(&acc, GrB_BOOL, first->nrows, first->ncols); Matrix acc_matrix = matrix_from_base(acc); for (size_t i = 0; i < first->base_matrices_count; i++) { @@ -492,7 +495,7 @@ GrB_Info matrix_wise_lazy(Matrix *output, Matrix *first, Matrix *second, bool ac } GrB_Matrix _other; - GrB_Matrix_new(&_other, GrB_BOOL, output->size, output->size); + GrB_Matrix_new(&_other, GrB_BOOL, output->nrows, output->ncols); Matrix other = matrix_from_base(_other); matrix_dup_empty(&other, second); @@ -592,7 +595,7 @@ void matrix_print_lazy(Matrix *A) { } GrB_Matrix _temp; - GrB_Matrix_new(&_temp, GrB_BOOL, A->size, A->size); + GrB_Matrix_new(&_temp, GrB_BOOL, A->nrows, A->ncols); Matrix temp = matrix_from_base(_temp); for (size_t i = 0; i < A->base_matrices_count; i++) { matrix_wise_empty(&temp, &temp, &A->base_matrices[i], false); @@ -1009,7 +1012,7 @@ GrB_Info LAGraph_CFL_reachability_adv( outputs[i] = matrices[i].base; } else { GrB_Matrix _acc; - GrB_Matrix_new(&_acc, GrB_BOOL, matrices[i].size, matrices[i].size); + GrB_Matrix_new(&_acc, GrB_BOOL, matrices[i].nrows, matrices[i].ncols); Matrix acc = matrix_from_base(_acc); for (size_t j = 0; j < matrices[i].base_matrices_count; j++) { From bc0af0dbec1efc0f6d424f77da7ea461ad0e9f8f Mon Sep 17 00:00:00 2001 From: Homka122 Date: Wed, 21 May 2025 16:32:16 +0300 Subject: [PATCH 048/122] Feat: Add fields to Matrix object for block matrices --- .../algorithm/LAGraph_CFL_reachability_advanced.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/experimental/algorithm/LAGraph_CFL_reachability_advanced.c b/experimental/algorithm/LAGraph_CFL_reachability_advanced.c index 98a43961e4..bffff285dc 100644 --- a/experimental/algorithm/LAGraph_CFL_reachability_advanced.c +++ b/experimental/algorithm/LAGraph_CFL_reachability_advanced.c @@ -142,6 +142,8 @@ } \ } +enum Matrix_block { CELL, VEC_HORIZ, VEC_VERT }; + typedef struct Matrix { GrB_Matrix base; GrB_Matrix base_row; @@ -152,6 +154,7 @@ typedef struct Matrix { GrB_Index nrows; GrB_Index ncols; int32_t format; + enum Matrix_block block_type; bool is_both; bool is_lazy; } Matrix; @@ -169,6 +172,14 @@ void matrix_update(Matrix *matrix) { } GrB_Matrix_nrows(&matrix->nrows, matrix->base); GrB_Matrix_ncols(&matrix->ncols, matrix->base); + + if (matrix->nrows > matrix->ncols) { + matrix->block_type = VEC_VERT; + } + + if (matrix->ncols > matrix->nrows) { + matrix->block_type = VEC_HORIZ; + } // GrB_get(matrix->base, &matrix->format, GrB_STORAGE_ORIENTATION_HINT); } @@ -182,6 +193,7 @@ Matrix matrix_from_base(GrB_Matrix matrix) { result.nvals = 0; result.nrows = 0; result.ncols = 0; + result.block_type = CELL; result.format = GrB_ROWMAJOR; result.is_both = false; matrix_update(&result); From eb313afe8789b7cece293b31eb6970f977fc5efe Mon Sep 17 00:00:00 2001 From: Homka122 Date: Wed, 21 May 2025 16:33:55 +0300 Subject: [PATCH 049/122] Feat: change rule parsing --- .../LAGraph_CFL_reachability_advanced.c | 58 ++++++++++++++----- 1 file changed, 42 insertions(+), 16 deletions(-) diff --git a/experimental/algorithm/LAGraph_CFL_reachability_advanced.c b/experimental/algorithm/LAGraph_CFL_reachability_advanced.c index bffff285dc..9e5cba82cd 100644 --- a/experimental/algorithm/LAGraph_CFL_reachability_advanced.c +++ b/experimental/algorithm/LAGraph_CFL_reachability_advanced.c @@ -618,6 +618,26 @@ void matrix_print_lazy(Matrix *A) { GrB_free(&_temp); } +#define IS_NONTERM(index) \ + { \ + for (size_t m = 0; m < rules_count; m++) { \ + if (rules[m].nonterm == index) \ + return true; \ + } \ + \ + return false; \ + } + +bool is_nonterm(int index, const LAGraph_rule_WCNF *rules, size_t rules_count) { + for (size_t i = 0; i < rules_count; i++) { + if (rules[i].nonterm == index) { + return true; + } + } + + return false; +} + // LAGraph_CFL_reachability: Context-Free Language Reachability Matrix-Based Algorithm // // This function determines the set of vertex pairs (u, v) in a graph (represented by @@ -677,8 +697,7 @@ GrB_Info LAGraph_CFL_reachability_adv( // is an edge between nodes i and j with the label of // the terminal corresponding to index 't' (where t is // in the range [0, terms_count - 1]). - int32_t terms_count, // The total number of terminal symbols in the CFG. - int32_t nonterms_count, // The total number of non-terminal symbols in the CFG. + int32_t nonterms_count, const LAGraph_rule_WCNF *rules, // The rules of the CFG. size_t rules_count, // The total number of rules in the CFG. char *msg, // Message string for error reporting. @@ -695,17 +714,25 @@ GrB_Info LAGraph_CFL_reachability_adv( size_t msg_len = 0; // For error formatting GrB_Index *indexes = NULL; + int32_t symbols_amount = 0; + for (size_t i = 0; i < rules_count; i++) { + symbols_amount = + rules[i].nonterm + 1 > symbols_amount ? rules[i].nonterm + 1 : symbols_amount; + symbols_amount = + rules[i].prod_A + 1 > symbols_amount ? rules[i].prod_A + 1 : symbols_amount; + symbols_amount = + rules[i].prod_B + 1 > symbols_amount ? rules[i].prod_B + 1 : symbols_amount; + } + GrB_Scalar true_scalar; GrB_Scalar_new(&true_scalar, GrB_BOOL); GrB_Scalar_setElement_BOOL(true_scalar, true); - LG_TRY(LAGraph_Calloc((void **)&T, nonterms_count, sizeof(GrB_Matrix), msg)); - LG_TRY(LAGraph_Calloc((void **)&delta_matrices, nonterms_count, sizeof(Matrix), msg)); - LG_TRY(LAGraph_Calloc((void **)&matrices, nonterms_count, sizeof(Matrix), msg)); - LG_TRY(LAGraph_Calloc((void **)&temp_matrices, nonterms_count, sizeof(Matrix), msg)); + LG_TRY(LAGraph_Calloc((void **)&T, symbols_amount, sizeof(GrB_Matrix), msg)); + LG_TRY(LAGraph_Calloc((void **)&delta_matrices, symbols_amount, sizeof(Matrix), msg)); + LG_TRY(LAGraph_Calloc((void **)&matrices, symbols_amount, sizeof(Matrix), msg)); + LG_TRY(LAGraph_Calloc((void **)&temp_matrices, symbols_amount, sizeof(Matrix), msg)); - LG_ASSERT_MSG(terms_count > 0, GrB_INVALID_VALUE, - "The number of terminals must be greater than zero."); LG_ASSERT_MSG(nonterms_count > 0, GrB_INVALID_VALUE, "The number of non-terminals must be greater than zero."); LG_ASSERT_MSG(rules_count > 0, GrB_INVALID_VALUE, @@ -717,7 +744,7 @@ GrB_Info LAGraph_CFL_reachability_adv( // Find null adjacency matrices bool found_null = false; - for (int32_t i = 0; i < terms_count; i++) { + for (int32_t i = 0; i < symbols_amount; i++) { if (adj_matrices[i] != NULL) continue; @@ -740,7 +767,7 @@ GrB_Info LAGraph_CFL_reachability_adv( GRB_TRY(GrB_Matrix_ncols(&n, adj_matrices[0])); // Create nonterms matrices - for (int32_t i = 0; i < nonterms_count; i++) { + for (int32_t i = 0; i < symbols_amount; i++) { GrB_Matrix matrix; GRB_TRY(GrB_Matrix_new(&T[i], GrB_BOOL, n, n)); @@ -748,8 +775,7 @@ GrB_Info LAGraph_CFL_reachability_adv( GRB_TRY(GrB_Matrix_new(&matrix, GrB_BOOL, n, n)); delta_matrices[i] = matrix_from_base(matrix); - GRB_TRY(GrB_Matrix_new(&matrix, GrB_BOOL, n, n)); - matrices[i] = matrix_from_base(matrix); + GrB_Matrix_dup(&matrices[i], adj_matrices[i]); GRB_TRY(GrB_Matrix_new(&matrix, GrB_BOOL, n, n)); temp_matrices[i] = matrix_from_base(matrix); @@ -777,7 +803,7 @@ GrB_Info LAGraph_CFL_reachability_adv( bool is_rule_bin = rule.prod_A != -1 && rule.prod_B != -1; // Check that all rules are well-formed - if (rule.nonterm < 0 || rule.nonterm >= nonterms_count) { + if (rule.nonterm < 0 || rule.nonterm >= symbols_amount) { ADD_INDEX_TO_ERROR_RULE(nonterm_err, i); } @@ -792,7 +818,7 @@ GrB_Info LAGraph_CFL_reachability_adv( if (is_rule_term) { term_rules[term_rules_count++] = i; - if (rule.prod_A < -1 || rule.prod_A >= terms_count) { + if (rule.prod_A < -1 || rule.prod_A >= symbols_amount) { ADD_INDEX_TO_ERROR_RULE(term_err, i); } @@ -803,8 +829,8 @@ GrB_Info LAGraph_CFL_reachability_adv( if (is_rule_bin) { bin_rules[bin_rules_count++] = i; - if (rule.prod_A < -1 || rule.prod_A >= nonterms_count || rule.prod_B < -1 || - rule.prod_B >= nonterms_count) { + if (rule.prod_A < -1 || rule.prod_A >= symbols_amount || rule.prod_B < -1 || + rule.prod_B >= symbols_amount) { ADD_INDEX_TO_ERROR_RULE(nonterm_err, i); } From 9be8a1536354ae3114c0e8390d5eca23472efa6d Mon Sep 17 00:00:00 2001 From: Homka122 Date: Thu, 22 May 2025 20:07:37 +0300 Subject: [PATCH 050/122] Feat: implement block mxm operation --- .../LAGraph_CFL_reachability_advanced.c | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/experimental/algorithm/LAGraph_CFL_reachability_advanced.c b/experimental/algorithm/LAGraph_CFL_reachability_advanced.c index 9e5cba82cd..8e80efc115 100644 --- a/experimental/algorithm/LAGraph_CFL_reachability_advanced.c +++ b/experimental/algorithm/LAGraph_CFL_reachability_advanced.c @@ -435,6 +435,42 @@ GrB_Info matrix_mxm_lazy(Matrix *output, Matrix *first, Matrix *second, bool acc return result; } +GrB_Info matrix_mxm_block(Matrix *output, Matrix *first, Matrix *second, bool accum, + bool swap) { + if (first->block_type == CELL && second->block_type == CELL) { + matrix_mxm_lazy(output, first, second, accum, swap); + } + + if (first->block_type == CELL) { + block_matrix_hyper_rotate_i(second, swap ? VEC_VERT : VEC_HORIZ); + block_matrix_hyper_rotate_i(output, swap ? VEC_VERT : VEC_HORIZ); + + matrix_mxm_lazy(output, first, second, accum, swap); + + return GrB_SUCCESS; + } + + if (second->block_type == CELL) { + block_matrix_hyper_rotate_i(first, swap ? VEC_HORIZ : VEC_VERT); + block_matrix_hyper_rotate_i(output, swap ? VEC_HORIZ : VEC_VERT); + + matrix_mxm_lazy(output, first, second, accum, swap); + + return GrB_SUCCESS; + } + + GrB_Index size = first->nrows > first->ncols ? first->nrows : first->ncols; + GrB_Matrix _diag; + GrB_Matrix_new(_diag, GrB_BOOL, size, size); + Matrix diag = matrix_from_base(_diag); + block_matrix_to_diag(&diag, second); + + block_matrix_hyper_rotate_i(first, swap ? VEC_VERT : VEC_HORIZ); + block_matrix_hyper_rotate_i(output, swap ? VEC_VERT : VEC_HORIZ); + + matrix_mxm_lazy(output, first, &diag, accum, swap); +} + GrB_Info matrix_wise(Matrix *output, Matrix *first, Matrix *second, bool accum) { GrB_BinaryOp accum_op = accum ? GxB_ANY_BOOL : GrB_NULL; From cc23b24ef895b9e14b7d5d0cceb3c9c495c52cf6 Mon Sep 17 00:00:00 2001 From: Homka122 Date: Thu, 22 May 2025 20:08:05 +0300 Subject: [PATCH 051/122] Fix: first mxm need accum operator for correct result --- experimental/algorithm/LAGraph_CFL_reachability_advanced.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/experimental/algorithm/LAGraph_CFL_reachability_advanced.c b/experimental/algorithm/LAGraph_CFL_reachability_advanced.c index 8e80efc115..1dcccc82c1 100644 --- a/experimental/algorithm/LAGraph_CFL_reachability_advanced.c +++ b/experimental/algorithm/LAGraph_CFL_reachability_advanced.c @@ -998,7 +998,7 @@ GrB_Info LAGraph_CFL_reachability_adv( Matrix *B = &delta_matrices[bin_rule.prod_B]; Matrix *C = &temp_matrices[bin_rule.nonterm]; - mxm(C, A, B, false, false); + mxm(C, A, B, true, false); // matrix_print_lazy(A); // matrix_print_lazy(B); // matrix_print_lazy(C); From e6a77bf8fdd1145f9aed1b8739937f954d0d33fd Mon Sep 17 00:00:00 2001 From: Homka122 Date: Fri, 23 May 2025 13:44:43 +0300 Subject: [PATCH 052/122] Feat: implement wise block operation --- .../LAGraph_CFL_reachability_advanced.c | 40 +++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/experimental/algorithm/LAGraph_CFL_reachability_advanced.c b/experimental/algorithm/LAGraph_CFL_reachability_advanced.c index 1dcccc82c1..e14139bae0 100644 --- a/experimental/algorithm/LAGraph_CFL_reachability_advanced.c +++ b/experimental/algorithm/LAGraph_CFL_reachability_advanced.c @@ -578,6 +578,46 @@ GrB_Info matrix_wise_lazy(Matrix *output, Matrix *first, Matrix *second, bool ac return GrB_SUCCESS; } +// - Any operation on two hyper vectors is performed block-wise +// - When hyper vector is added in-place to a cell, then sum of hyper vector's blocks is +// added to a cell +// - When cell is added in-place to a hyper vector, then cell is added to each of +// hyper vector's blocks +GrB_Info matrix_wise_block(Matrix *output, Matrix *first, Matrix *second, bool accum) { + if (output != first) { + fprintf(stderr, "Matrix wise currently support only iadd operation"); + exit(-122); + } + + if (first->block_type == CELL && second->block_type == CELL) { + matrix_wise_lazy(output, first, second, accum); + } + + // second is vector + if (first->block_type == CELL) { + Matrix temp_reduced = matrix_create(first->nrows, first->ncols); + block_matrix_reduce(&temp_reduced, second); + + GrB_Info info = matrix_wise_lazy(output, first, &temp_reduced, accum); + matrix_free(&temp_reduced); + return info; + } + + // first is vector + if (second->block_type == CELL) { + Matrix temp_vector = matrix_create(first->nrows, first->ncols); + block_matrix_repeat_into_vector(&temp_vector, second); + + GrB_Info info = matrix_wise_lazy(output, first, &temp_vector, accum); + matrix_free(&temp_vector); + return info; + } + + // both are vector + block_matrix_hyper_rotate_i(second, first->block_type); + return matrix_wise_block(output, first, second, accum); +} + GrB_Info matrix_rsub(Matrix *output, Matrix *mask) { GrB_Info result = GrB_eWiseAdd(output->base, mask->base, GrB_NULL, GxB_ANY_BOOL, output->base, output->base, GrB_DESC_RSC); From 8249fc176eb8f31992319cf40853a7721da0c806 Mon Sep 17 00:00:00 2001 From: Homka122 Date: Fri, 23 May 2025 13:45:00 +0300 Subject: [PATCH 053/122] Feat: add create and free methods for Matrix structure --- .../algorithm/LAGraph_CFL_reachability_advanced.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/experimental/algorithm/LAGraph_CFL_reachability_advanced.c b/experimental/algorithm/LAGraph_CFL_reachability_advanced.c index e14139bae0..213de73e32 100644 --- a/experimental/algorithm/LAGraph_CFL_reachability_advanced.c +++ b/experimental/algorithm/LAGraph_CFL_reachability_advanced.c @@ -200,6 +200,19 @@ Matrix matrix_from_base(GrB_Matrix matrix) { return result; } +Matrix matrix_create(GrB_Index nrows, GrB_Index ncols) { + GrB_Matrix _result; + GrB_Matrix_new(&_result, GrB_BOOL, nrows, ncols); + Matrix result = matrix_from_base(_result); + + return result; +}; + +void matrix_free(Matrix *matrix) { + free(matrix->base_matrices); + GrB_free(&matrix->base); +} + void matrix_to_format(Matrix *matrix, int32_t format, bool is_both) { // Matrix contain both formats so just switch base matrix if (matrix->is_both) { From 6225f49cbfee539c4657ebd15be48ace84871eb1 Mon Sep 17 00:00:00 2001 From: Homka122 Date: Fri, 23 May 2025 13:50:30 +0300 Subject: [PATCH 054/122] Feat: implement rsub block operation --- .../algorithm/LAGraph_CFL_reachability_advanced.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/experimental/algorithm/LAGraph_CFL_reachability_advanced.c b/experimental/algorithm/LAGraph_CFL_reachability_advanced.c index 213de73e32..3ea639daed 100644 --- a/experimental/algorithm/LAGraph_CFL_reachability_advanced.c +++ b/experimental/algorithm/LAGraph_CFL_reachability_advanced.c @@ -684,6 +684,21 @@ GrB_Info matrix_rsub_lazy(Matrix *output, Matrix *mask) { return GrB_SUCCESS; } +GrB_Info matrix_rsub_block(Matrix *output, Matrix *mask) { + if (output->block_type == CELL && output->block_type != CELL || + output->block_type != CELL && mask->block_type == CELL) { + fprintf(stderr, "Don't support rsub operation between cell and vector"); + exit(-1); + } + + if (output->block_type == CELL) { + return matrix_rsub_lazy(output, mask); + } + + block_matrix_hyper_rotate_i(output, mask->block_type); + return matrix_rsub_lazy(output, mask); +} + void matrix_print_lazy(Matrix *A) { if (A->base_matrices_count == 0) { GxB_print(A->base, 1); From 3595a8f0cd3ebd37176d5504ab21553e6e0a8dac Mon Sep 17 00:00:00 2001 From: Homka122 Date: Fri, 23 May 2025 14:23:53 +0300 Subject: [PATCH 055/122] Feat: add block hyper rotate method --- .../LAGraph_CFL_reachability_advanced.c | 50 +++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/experimental/algorithm/LAGraph_CFL_reachability_advanced.c b/experimental/algorithm/LAGraph_CFL_reachability_advanced.c index 3ea639daed..5cf4572caf 100644 --- a/experimental/algorithm/LAGraph_CFL_reachability_advanced.c +++ b/experimental/algorithm/LAGraph_CFL_reachability_advanced.c @@ -278,6 +278,56 @@ GrB_Info matrix_clear_empty(Matrix *A) { return matrix_clear_format(A); } +void block_matrix_hyper_rotate_i(Matrix *matrix, enum Matrix_block format) { + if (matrix->block_type == CELL) { + return; + } + + if (matrix->block_type == format) { + return; + } + + GrB_Scalar scalar_true; + GrB_Scalar_new(&scalar_true, GrB_BOOL); + GrB_Scalar_setElement_BOOL(scalar_true, true); + + if (matrix->format == VEC_VERT) { + GrB_Index *nrows = malloc(matrix->nvals * sizeof(GrB_Index)); + GrB_Index *ncols = malloc(matrix->nvals * sizeof(GrB_Index)); + + GrB_Matrix_extractTuples_BOOL(nrows, ncols, NULL, &matrix->nvals, matrix->base); + + for (size_t i = 0; i < matrix->nvals; i++) { + ncols[i] = ncols[i] + ncols[i] / matrix->ncols * matrix->ncols; + nrows[i] = nrows[i] % matrix->ncols; + } + + GxB_Matrix_build_Scalar(matrix->base, nrows, ncols, scalar_true, matrix->nvals); + free(nrows); + free(ncols); + GrB_free(&scalar_true); + return; + } + + if (matrix->format == VEC_HORIZ) { + GrB_Index *nrows = malloc(matrix->nvals * sizeof(GrB_Index)); + GrB_Index *ncols = malloc(matrix->nvals * sizeof(GrB_Index)); + + GrB_Matrix_extractTuples_BOOL(nrows, ncols, NULL, &matrix->nvals, matrix->base); + + for (size_t i = 0; i < matrix->nvals; i++) { + nrows[i] = nrows[i] + nrows[i] / matrix->nrows * matrix->nrows; + ncols[i] = ncols[i] % matrix->ncols; + } + + GxB_Matrix_build_Scalar(matrix->base, nrows, ncols, scalar_true, matrix->nvals); + free(nrows); + free(ncols); + GrB_free(&scalar_true); + return; + } +} + GrB_Info matrix_dup(Matrix *output, Matrix *input) { GrB_Info result = GrB_Matrix_assign(output->base, GrB_NULL, GrB_NULL, input->base, GrB_ALL, From c0adbab15334da82037d5096257951e458fdcac1 Mon Sep 17 00:00:00 2001 From: Homka122 Date: Fri, 23 May 2025 14:31:22 +0300 Subject: [PATCH 056/122] Feat: add block matrix to diag method --- .../LAGraph_CFL_reachability_advanced.c | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/experimental/algorithm/LAGraph_CFL_reachability_advanced.c b/experimental/algorithm/LAGraph_CFL_reachability_advanced.c index 5cf4572caf..72c3872b2c 100644 --- a/experimental/algorithm/LAGraph_CFL_reachability_advanced.c +++ b/experimental/algorithm/LAGraph_CFL_reachability_advanced.c @@ -328,6 +328,38 @@ void block_matrix_hyper_rotate_i(Matrix *matrix, enum Matrix_block format) { } } +void block_matrix_to_diag(Matrix *diag, Matrix *input) { + if (input->block_type == CELL) { + exit(-1); + } + + GrB_Scalar scalar_true; + GrB_Scalar_new(&scalar_true, GrB_BOOL); + GrB_Scalar_setElement_BOOL(scalar_true, true); + + GrB_Index *rows = malloc(input->nvals * sizeof(GrB_Index)); + GrB_Index *cols = malloc(input->nvals * sizeof(GrB_Index)); + GrB_Matrix_extractTuples_BOOL(rows, cols, NULL, &input->nvals, input->base); + + if (input->block_type == VEC_HORIZ) { + for (size_t i = 0; i < input->nvals; i++) { + rows[i] = rows[i] + cols[i] / input->nrows * input->nrows; + } + } + + if (input->block_type == VEC_VERT) { + for (size_t i = 0; i < input->nvals; i++) { + cols[i] = cols[i] + rows[i] / input->ncols * input->ncols; + } + } + + GxB_Matrix_build_Scalar(diag->base, rows, cols, scalar_true, input->nvals); + + free(rows); + free(cols); + GrB_free(&scalar_true); +} + GrB_Info matrix_dup(Matrix *output, Matrix *input) { GrB_Info result = GrB_Matrix_assign(output->base, GrB_NULL, GrB_NULL, input->base, GrB_ALL, From caddbf18e8894cec89268a8509dc7a22035d87ee Mon Sep 17 00:00:00 2001 From: Homka122 Date: Fri, 23 May 2025 14:35:16 +0300 Subject: [PATCH 057/122] Feat: add block matrix reduce method --- .../LAGraph_CFL_reachability_advanced.c | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/experimental/algorithm/LAGraph_CFL_reachability_advanced.c b/experimental/algorithm/LAGraph_CFL_reachability_advanced.c index 72c3872b2c..bff336dcb3 100644 --- a/experimental/algorithm/LAGraph_CFL_reachability_advanced.c +++ b/experimental/algorithm/LAGraph_CFL_reachability_advanced.c @@ -360,6 +360,38 @@ void block_matrix_to_diag(Matrix *diag, Matrix *input) { GrB_free(&scalar_true); } +void block_matrix_reduce(Matrix *matrix, Matrix *input) { + if (input->block_type == CELL) { + matrix_dup_empty(matrix, input); + } + + GrB_Scalar scalar_true; + GrB_Scalar_new(&scalar_true, GrB_BOOL); + GrB_Scalar_setElement_BOOL(scalar_true, true); + + GrB_Index *rows = malloc(input->nvals * sizeof(GrB_Index)); + GrB_Index *cols = malloc(input->nvals * sizeof(GrB_Index)); + GrB_Matrix_extractTuples_BOOL(rows, cols, NULL, &input->nvals, input->base); + + if (input->format == VEC_VERT) { + for (size_t i = 0; i < input->nvals; i++) { + rows[i] = rows[i] % input->ncols; + } + } + + if (input->format == VEC_HORIZ) { + for (size_t i = 0; i < input->nvals; i++) { + cols[i] = cols[i] % input->nrows; + } + } + + GxB_Matrix_build_Scalar(matrix->base, rows, cols, scalar_true, input->nvals); + + free(rows); + free(cols); + GrB_free(&scalar_true); +} + GrB_Info matrix_dup(Matrix *output, Matrix *input) { GrB_Info result = GrB_Matrix_assign(output->base, GrB_NULL, GrB_NULL, input->base, GrB_ALL, From b7e68b8a71efa094079670fda4a0fff533e5e0c8 Mon Sep 17 00:00:00 2001 From: Homka122 Date: Fri, 23 May 2025 14:36:44 +0300 Subject: [PATCH 058/122] Fix: wrong type input --- experimental/algorithm/LAGraph_CFL_reachability_advanced.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/experimental/algorithm/LAGraph_CFL_reachability_advanced.c b/experimental/algorithm/LAGraph_CFL_reachability_advanced.c index bff336dcb3..d5d6e19eeb 100644 --- a/experimental/algorithm/LAGraph_CFL_reachability_advanced.c +++ b/experimental/algorithm/LAGraph_CFL_reachability_advanced.c @@ -360,6 +360,8 @@ void block_matrix_to_diag(Matrix *diag, Matrix *input) { GrB_free(&scalar_true); } +GrB_Info matrix_dup_empty(Matrix *output, Matrix *input); + void block_matrix_reduce(Matrix *matrix, Matrix *input) { if (input->block_type == CELL) { matrix_dup_empty(matrix, input); @@ -588,7 +590,7 @@ GrB_Info matrix_mxm_block(Matrix *output, Matrix *first, Matrix *second, bool ac GrB_Index size = first->nrows > first->ncols ? first->nrows : first->ncols; GrB_Matrix _diag; - GrB_Matrix_new(_diag, GrB_BOOL, size, size); + GrB_Matrix_new(&_diag, GrB_BOOL, size, size); Matrix diag = matrix_from_base(_diag); block_matrix_to_diag(&diag, second); From 3359d61bf56d385c40f0ec7680f27c61a35fbeaf Mon Sep 17 00:00:00 2001 From: Homka122 Date: Fri, 23 May 2025 14:43:46 +0300 Subject: [PATCH 059/122] Feat: add method matrix -> block vector --- .../algorithm/LAGraph_CFL_reachability_advanced.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/experimental/algorithm/LAGraph_CFL_reachability_advanced.c b/experimental/algorithm/LAGraph_CFL_reachability_advanced.c index d5d6e19eeb..45395705ae 100644 --- a/experimental/algorithm/LAGraph_CFL_reachability_advanced.c +++ b/experimental/algorithm/LAGraph_CFL_reachability_advanced.c @@ -394,6 +394,16 @@ void block_matrix_reduce(Matrix *matrix, Matrix *input) { GrB_free(&scalar_true); } +void block_matrix_repeat_into_vector(Matrix *matrix, Matrix *input, + GrB_Index block_count) { + GrB_Matrix *tiles = malloc(block_count * sizeof(GrB_Matrix)); + for (size_t i = 0; i < block_count; i++) { + tiles[i] = input->base; + } + + GxB_Matrix_concat(matrix->base, tiles, block_count, 1, GrB_NULL); +} + GrB_Info matrix_dup(Matrix *output, Matrix *input) { GrB_Info result = GrB_Matrix_assign(output->base, GrB_NULL, GrB_NULL, input->base, GrB_ALL, @@ -735,7 +745,8 @@ GrB_Info matrix_wise_block(Matrix *output, Matrix *first, Matrix *second, bool a // first is vector if (second->block_type == CELL) { Matrix temp_vector = matrix_create(first->nrows, first->ncols); - block_matrix_repeat_into_vector(&temp_vector, second); + GrB_Index block_count = first->nrows > first->ncols ? first->nrows : first->ncols; + block_matrix_repeat_into_vector(&temp_vector, second, block_count); GrB_Info info = matrix_wise_lazy(output, first, &temp_vector, accum); matrix_free(&temp_vector); From c79861ff7ab33e6f5ac148e6d0d255d30be084f7 Mon Sep 17 00:00:00 2001 From: Homka122 Date: Fri, 23 May 2025 14:44:45 +0300 Subject: [PATCH 060/122] Fix: fix bug when dublicate adj matrices --- experimental/algorithm/LAGraph_CFL_reachability_advanced.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/experimental/algorithm/LAGraph_CFL_reachability_advanced.c b/experimental/algorithm/LAGraph_CFL_reachability_advanced.c index 45395705ae..dd1fc4e640 100644 --- a/experimental/algorithm/LAGraph_CFL_reachability_advanced.c +++ b/experimental/algorithm/LAGraph_CFL_reachability_advanced.c @@ -1006,7 +1006,7 @@ GrB_Info LAGraph_CFL_reachability_adv( GRB_TRY(GrB_Matrix_new(&matrix, GrB_BOOL, n, n)); delta_matrices[i] = matrix_from_base(matrix); - GrB_Matrix_dup(&matrices[i], adj_matrices[i]); + GrB_Matrix_dup(&matrices[i].base, adj_matrices[i]); GRB_TRY(GrB_Matrix_new(&matrix, GrB_BOOL, n, n)); temp_matrices[i] = matrix_from_base(matrix); From 5f96e316a6a239a29fd677f64f339dd2e0a24545 Mon Sep 17 00:00:00 2001 From: Homka122 Date: Fri, 23 May 2025 14:50:44 +0300 Subject: [PATCH 061/122] Fix: compiler warnings --- .../algorithm/LAGraph_CFL_reachability_advanced.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/experimental/algorithm/LAGraph_CFL_reachability_advanced.c b/experimental/algorithm/LAGraph_CFL_reachability_advanced.c index dd1fc4e640..bd50cd0a2b 100644 --- a/experimental/algorithm/LAGraph_CFL_reachability_advanced.c +++ b/experimental/algorithm/LAGraph_CFL_reachability_advanced.c @@ -206,7 +206,7 @@ Matrix matrix_create(GrB_Index nrows, GrB_Index ncols) { Matrix result = matrix_from_base(_result); return result; -}; +} void matrix_free(Matrix *matrix) { free(matrix->base_matrices); @@ -456,6 +456,8 @@ GrB_Info matrix_sort_lazy(Matrix *A, bool reverse) { } } } + + return GrB_SUCCESS; } GrB_Info matrix_combine_lazy(Matrix *A, size_t threshold) { @@ -607,7 +609,7 @@ GrB_Info matrix_mxm_block(Matrix *output, Matrix *first, Matrix *second, bool ac block_matrix_hyper_rotate_i(first, swap ? VEC_VERT : VEC_HORIZ); block_matrix_hyper_rotate_i(output, swap ? VEC_VERT : VEC_HORIZ); - matrix_mxm_lazy(output, first, &diag, accum, swap); + return matrix_mxm_lazy(output, first, &diag, accum, swap); } GrB_Info matrix_wise(Matrix *output, Matrix *first, Matrix *second, bool accum) { @@ -694,8 +696,8 @@ GrB_Info matrix_wise_lazy(Matrix *output, Matrix *first, Matrix *second, bool ac for (size_t i = 0; i < first->base_matrices_count; i++) { size_t self_nvals = first->base_matrices[i].nvals >= 10 ? first->nvals : 10; - if (other.nvals / 10 <= self_nvals && self_nvals <= other.nvals * 10) { - matrix_wise_empty(&other, &other, &first->base_matrices[i], false); + if (other_nvals / 10 <= self_nvals && self_nvals <= other_nvals * 10) { + matrix_wise_empty(&other, &other, &first->base_matrices[i], accum); GrB_free(&first->base_matrices[i].base); for (size_t j = i + 1; j < first->base_matrices_count; j++) { first->base_matrices[j - 1] = first->base_matrices[j]; @@ -812,8 +814,8 @@ GrB_Info matrix_rsub_lazy(Matrix *output, Matrix *mask) { } GrB_Info matrix_rsub_block(Matrix *output, Matrix *mask) { - if (output->block_type == CELL && output->block_type != CELL || - output->block_type != CELL && mask->block_type == CELL) { + if ((output->block_type == CELL && output->block_type != CELL) || + (output->block_type != CELL && mask->block_type == CELL)) { fprintf(stderr, "Don't support rsub operation between cell and vector"); exit(-1); } From 6b25fa44f5583c52599945a8a1694c1c1900613e Mon Sep 17 00:00:00 2001 From: Homka122 Date: Fri, 23 May 2025 20:02:27 +0300 Subject: [PATCH 062/122] Fix: copy graph matrix from ajd --- experimental/algorithm/LAGraph_CFL_reachability_advanced.c | 1 + 1 file changed, 1 insertion(+) diff --git a/experimental/algorithm/LAGraph_CFL_reachability_advanced.c b/experimental/algorithm/LAGraph_CFL_reachability_advanced.c index bd50cd0a2b..8e696eb723 100644 --- a/experimental/algorithm/LAGraph_CFL_reachability_advanced.c +++ b/experimental/algorithm/LAGraph_CFL_reachability_advanced.c @@ -1009,6 +1009,7 @@ GrB_Info LAGraph_CFL_reachability_adv( delta_matrices[i] = matrix_from_base(matrix); GrB_Matrix_dup(&matrices[i].base, adj_matrices[i]); + matrices[i] = matrix_from_base(matrices[i].base); GRB_TRY(GrB_Matrix_new(&matrix, GrB_BOOL, n, n)); temp_matrices[i] = matrix_from_base(matrix); From c030cca0107a740d926837fba8edc89447ac672a Mon Sep 17 00:00:00 2001 From: Homka122 Date: Fri, 23 May 2025 20:11:40 +0300 Subject: [PATCH 063/122] Feat: add block optimization choice --- experimental/algorithm/LAGraph_CFL_reachability_advanced.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/experimental/algorithm/LAGraph_CFL_reachability_advanced.c b/experimental/algorithm/LAGraph_CFL_reachability_advanced.c index 8e696eb723..1054655f12 100644 --- a/experimental/algorithm/LAGraph_CFL_reachability_advanced.c +++ b/experimental/algorithm/LAGraph_CFL_reachability_advanced.c @@ -124,6 +124,7 @@ #define OPT_EMPTY (1 << 0) #define OPT_FORMAT (1 << 1) #define OPT_LAZY (1 << 2) +#define OPT_BLOCK (1 << 3) #define SKIP_IF_NULL(matrix) \ GrB_Matrix_nvals(&new_nnz, matrix); \ @@ -1163,6 +1164,10 @@ GrB_Info LAGraph_CFL_reachability_adv( mxm = matrix_mxm_format; wise = matrix_wise_format; rsub = matrix_rsub_format; + } else if (optimizations & OPT_BLOCK) { + mxm = matrix_mxm_block; + wise = matrix_wise_block; + rsub = matrix_rsub_block; } else { mxm = matrix_mxm; wise = matrix_wise; From 3aea853d585a8f02b9420e11794284fe89ca1a35 Mon Sep 17 00:00:00 2001 From: Homka122 Date: Fri, 23 May 2025 21:09:40 +0300 Subject: [PATCH 064/122] Feat: now implicitly declare that graph matrices are lazy --- .../LAGraph_CFL_reachability_advanced.c | 29 +++++++++++++++---- 1 file changed, 24 insertions(+), 5 deletions(-) diff --git a/experimental/algorithm/LAGraph_CFL_reachability_advanced.c b/experimental/algorithm/LAGraph_CFL_reachability_advanced.c index 1054655f12..43099a631d 100644 --- a/experimental/algorithm/LAGraph_CFL_reachability_advanced.c +++ b/experimental/algorithm/LAGraph_CFL_reachability_advanced.c @@ -197,10 +197,21 @@ Matrix matrix_from_base(GrB_Matrix matrix) { result.block_type = CELL; result.format = GrB_ROWMAJOR; result.is_both = false; + result.is_lazy = false; matrix_update(&result); return result; } +Matrix matrix_from_base_lazy(GrB_Matrix matrix) { + Matrix result = matrix_from_base(matrix); + result.is_lazy = true; + + result.base_matrices_count = 1; + result.base_matrices[0] = matrix_from_base(result.base); + + return result; +} + Matrix matrix_create(GrB_Index nrows, GrB_Index ncols) { GrB_Matrix _result; GrB_Matrix_new(&_result, GrB_BOOL, nrows, ncols); @@ -679,9 +690,16 @@ GrB_Info matrix_wise_empty(Matrix *output, Matrix *first, Matrix *second, bool a } GrB_Info matrix_wise_lazy(Matrix *output, Matrix *first, Matrix *second, bool accum) { - if (first->base_matrices_count == 0) { - first->base_matrices_count = 1; - first->base_matrices[0] = matrix_from_base(first->base); + if (!first->is_lazy && !second->is_lazy) { + return matrix_wise_empty(output, first, second, accum); + } + + if (!first->is_lazy && second->is_lazy) { + for (size_t i = 0; i < second->base_matrices_count; i++) { + matrix_wise_empty(output, first, &second->base_matrices[i], false); + } + + return GrB_SUCCESS; } GrB_Matrix _other; @@ -695,7 +713,8 @@ GrB_Info matrix_wise_lazy(Matrix *output, Matrix *first, Matrix *second, bool ac bool found = false; for (size_t i = 0; i < first->base_matrices_count; i++) { - size_t self_nvals = first->base_matrices[i].nvals >= 10 ? first->nvals : 10; + size_t self_nvals = + first->base_matrices[i].nvals >= 10 ? first->base_matrices[i].nvals : 10; if (other_nvals / 10 <= self_nvals && self_nvals <= other_nvals * 10) { matrix_wise_empty(&other, &other, &first->base_matrices[i], accum); @@ -1010,7 +1029,7 @@ GrB_Info LAGraph_CFL_reachability_adv( delta_matrices[i] = matrix_from_base(matrix); GrB_Matrix_dup(&matrices[i].base, adj_matrices[i]); - matrices[i] = matrix_from_base(matrices[i].base); + matrices[i] = matrix_from_base_lazy(matrices[i].base); GRB_TRY(GrB_Matrix_new(&matrix, GrB_BOOL, n, n)); temp_matrices[i] = matrix_from_base(matrix); From 68301f984de80f5c3d1cb4ae6e2b46629b31bc60 Mon Sep 17 00:00:00 2001 From: Homka122 Date: Fri, 23 May 2025 21:30:51 +0300 Subject: [PATCH 065/122] Fix: is lazy check in rsub function --- experimental/algorithm/LAGraph_CFL_reachability_advanced.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/experimental/algorithm/LAGraph_CFL_reachability_advanced.c b/experimental/algorithm/LAGraph_CFL_reachability_advanced.c index 43099a631d..beb5e00612 100644 --- a/experimental/algorithm/LAGraph_CFL_reachability_advanced.c +++ b/experimental/algorithm/LAGraph_CFL_reachability_advanced.c @@ -819,12 +819,12 @@ GrB_Info matrix_rsub_empty(Matrix *output, Matrix *mask) { } GrB_Info matrix_rsub_lazy(Matrix *output, Matrix *mask) { - if (mask->base_matrices_count == 0) { + if (!mask->is_lazy) { return matrix_rsub_empty(output, mask); } - matrix_sort_lazy(mask, true); matrix_combine_lazy(mask, output->nvals); + matrix_sort_lazy(mask, true); for (size_t i = 0; i < mask->base_matrices_count; i++) { matrix_rsub_empty(output, &mask->base_matrices[i]); From d734683d7c00ac815c452bc3e2347c9c633328b4 Mon Sep 17 00:00:00 2001 From: Homka122 Date: Sun, 25 May 2025 18:42:08 +0300 Subject: [PATCH 066/122] Fix: update base matrix nnz before calc in lazy matrix --- experimental/algorithm/LAGraph_CFL_reachability_advanced.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/experimental/algorithm/LAGraph_CFL_reachability_advanced.c b/experimental/algorithm/LAGraph_CFL_reachability_advanced.c index beb5e00612..6e2f11be9f 100644 --- a/experimental/algorithm/LAGraph_CFL_reachability_advanced.c +++ b/experimental/algorithm/LAGraph_CFL_reachability_advanced.c @@ -161,11 +161,13 @@ typedef struct Matrix { } Matrix; void matrix_update(Matrix *matrix) { - if (matrix->base_matrices_count == 0) { + if (!matrix->is_lazy) { GrB_Matrix_nvals(&matrix->nvals, matrix->base); } else { size_t new_nnz = 0; for (size_t i = 0; i < matrix->base_matrices_count; i++) { + GrB_Matrix_nvals(&matrix->base_matrices[i].nvals, + matrix->base_matrices[i].base); new_nnz += matrix->base_matrices[i].nvals; } From 7c17e47e485378739576e9b8225c7209e31f04eb Mon Sep 17 00:00:00 2001 From: Homka122 Date: Sun, 25 May 2025 19:35:46 +0300 Subject: [PATCH 067/122] Refactor: algorithm now accepth symbol count --- .../LAGraph_CFL_reachability_advanced.c | 44 +++++++------------ 1 file changed, 17 insertions(+), 27 deletions(-) diff --git a/experimental/algorithm/LAGraph_CFL_reachability_advanced.c b/experimental/algorithm/LAGraph_CFL_reachability_advanced.c index 6e2f11be9f..6133319c29 100644 --- a/experimental/algorithm/LAGraph_CFL_reachability_advanced.c +++ b/experimental/algorithm/LAGraph_CFL_reachability_advanced.c @@ -26,7 +26,7 @@ #define LG_FREE_ALL \ { \ - for (int32_t i = 0; i < nonterms_count; i++) { \ + for (size_t i = 0; i < symbols_amount; i++) { \ GrB_free(&T[i]); \ } \ \ @@ -952,7 +952,7 @@ GrB_Info LAGraph_CFL_reachability_adv( // is an edge between nodes i and j with the label of // the terminal corresponding to index 't' (where t is // in the range [0, terms_count - 1]). - int32_t nonterms_count, + size_t symbols_amount, const LAGraph_rule_WCNF *rules, // The rules of the CFG. size_t rules_count, // The total number of rules in the CFG. char *msg, // Message string for error reporting. @@ -969,16 +969,6 @@ GrB_Info LAGraph_CFL_reachability_adv( size_t msg_len = 0; // For error formatting GrB_Index *indexes = NULL; - int32_t symbols_amount = 0; - for (size_t i = 0; i < rules_count; i++) { - symbols_amount = - rules[i].nonterm + 1 > symbols_amount ? rules[i].nonterm + 1 : symbols_amount; - symbols_amount = - rules[i].prod_A + 1 > symbols_amount ? rules[i].prod_A + 1 : symbols_amount; - symbols_amount = - rules[i].prod_B + 1 > symbols_amount ? rules[i].prod_B + 1 : symbols_amount; - } - GrB_Scalar true_scalar; GrB_Scalar_new(&true_scalar, GrB_BOOL); GrB_Scalar_setElement_BOOL(true_scalar, true); @@ -988,8 +978,8 @@ GrB_Info LAGraph_CFL_reachability_adv( LG_TRY(LAGraph_Calloc((void **)&matrices, symbols_amount, sizeof(Matrix), msg)); LG_TRY(LAGraph_Calloc((void **)&temp_matrices, symbols_amount, sizeof(Matrix), msg)); - LG_ASSERT_MSG(nonterms_count > 0, GrB_INVALID_VALUE, - "The number of non-terminals must be greater than zero."); + LG_ASSERT_MSG(symbols_amount > 0, GrB_INVALID_VALUE, + "The number of symbols must be greater than zero."); LG_ASSERT_MSG(rules_count > 0, GrB_INVALID_VALUE, "The number of rules must be greater than zero."); LG_ASSERT_MSG(outputs != NULL, GrB_NULL_POINTER, "The outputs array cannot be null."); @@ -999,15 +989,15 @@ GrB_Info LAGraph_CFL_reachability_adv( // Find null adjacency matrices bool found_null = false; - for (int32_t i = 0; i < symbols_amount; i++) { + for (size_t i = 0; i < symbols_amount; i++) { if (adj_matrices[i] != NULL) continue; if (!found_null) { ADD_TO_MSG("Adjacency matrices with these indexes are null: "); - ADD_TO_MSG("%d", i); + ADD_TO_MSG("%ld", i); } else { - ADD_TO_MSG(", %d", i); + ADD_TO_MSG(", %ld", i); } found_null = true; @@ -1022,7 +1012,7 @@ GrB_Info LAGraph_CFL_reachability_adv( GRB_TRY(GrB_Matrix_ncols(&n, adj_matrices[0])); // Create nonterms matrices - for (int32_t i = 0; i < symbols_amount; i++) { + for (size_t i = 0; i < symbols_amount; i++) { GrB_Matrix matrix; GRB_TRY(GrB_Matrix_new(&T[i], GrB_BOOL, n, n)); @@ -1059,7 +1049,7 @@ GrB_Info LAGraph_CFL_reachability_adv( bool is_rule_bin = rule.prod_A != -1 && rule.prod_B != -1; // Check that all rules are well-formed - if (rule.nonterm < 0 || rule.nonterm >= symbols_amount) { + if (rule.nonterm < 0 || (size_t)rule.nonterm >= symbols_amount) { ADD_INDEX_TO_ERROR_RULE(nonterm_err, i); } @@ -1074,7 +1064,7 @@ GrB_Info LAGraph_CFL_reachability_adv( if (is_rule_term) { term_rules[term_rules_count++] = i; - if (rule.prod_A < -1 || rule.prod_A >= symbols_amount) { + if (rule.prod_A < -1 || (size_t)rule.prod_A >= symbols_amount) { ADD_INDEX_TO_ERROR_RULE(term_err, i); } @@ -1085,8 +1075,8 @@ GrB_Info LAGraph_CFL_reachability_adv( if (is_rule_bin) { bin_rules[bin_rules_count++] = i; - if (rule.prod_A < -1 || rule.prod_A >= symbols_amount || rule.prod_B < -1 || - rule.prod_B >= symbols_amount) { + if (rule.prod_A < -1 || (size_t)rule.prod_A >= symbols_amount || + rule.prod_B < -1 || (size_t)rule.prod_B >= symbols_amount) { ADD_INDEX_TO_ERROR_RULE(nonterm_err, i); } @@ -1211,7 +1201,7 @@ GrB_Info LAGraph_CFL_reachability_adv( printf("\n--- ITERATARION %ld ---\n", iteration); #endif - for (int32_t i = 0; i < nonterms_count; i++) { + for (size_t i = 0; i < symbols_amount; i++) { GRB_TRY(matrix_clear_empty(&temp_matrices[i])); } @@ -1230,7 +1220,7 @@ GrB_Info LAGraph_CFL_reachability_adv( TIMER_STOP("MXM 1", &mxm1); TIMER_START() - for (int32_t i = 0; i < nonterms_count; i++) { + for (size_t i = 0; i < symbols_amount; i++) { Matrix *A = &delta_matrices[i]; Matrix *C = &matrices[i]; @@ -1255,13 +1245,13 @@ GrB_Info LAGraph_CFL_reachability_adv( TIMER_STOP("MXM 2", &mxm2); TIMER_START(); - for (int32_t i = 0; i < nonterms_count; i++) { + for (size_t i = 0; i < symbols_amount; i++) { matrix_dup_empty(&delta_matrices[i], &temp_matrices[i]); } TIMER_STOP("WISE 2 (copy)", &wise2); TIMER_START(); - for (int32_t i = 0; i < nonterms_count; i++) { + for (size_t i = 0; i < symbols_amount; i++) { Matrix *A = &matrices[i]; Matrix *C = &delta_matrices[i]; @@ -1305,7 +1295,7 @@ GrB_Info LAGraph_CFL_reachability_adv( } #endif - for (int32_t i = 0; i < nonterms_count; i++) { + for (size_t i = 0; i < symbols_amount; i++) { if (matrices[i].base_matrices_count == 0) { outputs[i] = matrices[i].base; } else { From 8440287a3537dbf63e085f70f50a71f93b585dc0 Mon Sep 17 00:00:00 2001 From: Homka122 Date: Sun, 25 May 2025 19:36:27 +0300 Subject: [PATCH 068/122] Feat: sort matrices before find acc --- experimental/algorithm/LAGraph_CFL_reachability_advanced.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/experimental/algorithm/LAGraph_CFL_reachability_advanced.c b/experimental/algorithm/LAGraph_CFL_reachability_advanced.c index 6133319c29..f100e780fe 100644 --- a/experimental/algorithm/LAGraph_CFL_reachability_advanced.c +++ b/experimental/algorithm/LAGraph_CFL_reachability_advanced.c @@ -1299,10 +1299,12 @@ GrB_Info LAGraph_CFL_reachability_adv( if (matrices[i].base_matrices_count == 0) { outputs[i] = matrices[i].base; } else { + // TODO: new method for getting acc from lazy matrix GrB_Matrix _acc; GrB_Matrix_new(&_acc, GrB_BOOL, matrices[i].nrows, matrices[i].ncols); Matrix acc = matrix_from_base(_acc); + matrix_sort_lazy(&matrices[i], false); for (size_t j = 0; j < matrices[i].base_matrices_count; j++) { matrix_wise_empty(&acc, &acc, &matrices[i].base_matrices[j], false); GrB_free(&matrices[i].base_matrices[j].base); From 9cf80c2eeea6a12279ca5ca300a063dde8b9e4a6 Mon Sep 17 00:00:00 2001 From: Homka122 Date: Sun, 25 May 2025 19:39:33 +0300 Subject: [PATCH 069/122] Feat: new way checking changing graph --- .../LAGraph_CFL_reachability_advanced.c | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/experimental/algorithm/LAGraph_CFL_reachability_advanced.c b/experimental/algorithm/LAGraph_CFL_reachability_advanced.c index f100e780fe..85348b37a8 100644 --- a/experimental/algorithm/LAGraph_CFL_reachability_advanced.c +++ b/experimental/algorithm/LAGraph_CFL_reachability_advanced.c @@ -1261,18 +1261,14 @@ GrB_Info LAGraph_CFL_reachability_adv( } TIMER_STOP("WISE 3 (MASK)", &rsubt); - for (int32_t i = 0; i < nonterms_count; i++) { - size_t new_nnz = 0; - if (matrices[i].base_matrices_count == 0) { - new_nnz = matrices[i].nvals; - } else { - for (size_t j = 0; j < matrices[i].base_matrices_count; j++) { - new_nnz += matrices[i].base_matrices[j].nvals; - } - } + size_t new_nnz = 0; + for (size_t i = 0; i < symbols_amount; i++) { + matrix_update(&delta_matrices[i]); + new_nnz += delta_matrices[i].nvals; + } - changed = changed || (nnzs[i] != new_nnz); - nnzs[i] = new_nnz; + if (new_nnz != 0) { + changed = true; } #ifdef DEBUG_CFL_REACHBILITY From b99cc1b385ef4cd49bfb587cd7dacf3dc83889b4 Mon Sep 17 00:00:00 2001 From: Homka122 Date: Sun, 25 May 2025 19:40:27 +0300 Subject: [PATCH 070/122] Refactor: make more useful matrix printing --- .../LAGraph_CFL_reachability_advanced.c | 25 +++++++++++++++---- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/experimental/algorithm/LAGraph_CFL_reachability_advanced.c b/experimental/algorithm/LAGraph_CFL_reachability_advanced.c index 85348b37a8..4fa22b0aa6 100644 --- a/experimental/algorithm/LAGraph_CFL_reachability_advanced.c +++ b/experimental/algorithm/LAGraph_CFL_reachability_advanced.c @@ -1212,10 +1212,12 @@ GrB_Info LAGraph_CFL_reachability_adv( Matrix *B = &delta_matrices[bin_rule.prod_B]; Matrix *C = &temp_matrices[bin_rule.nonterm]; - mxm(C, A, B, true, false); + // printf("MXM 1 iteration: %ld i: %ld\n", iteration, i); // matrix_print_lazy(A); // matrix_print_lazy(B); // matrix_print_lazy(C); + mxm(C, A, B, true, false); + // matrix_print_lazy(C); } TIMER_STOP("MXM 1", &mxm1); @@ -1224,9 +1226,11 @@ GrB_Info LAGraph_CFL_reachability_adv( Matrix *A = &delta_matrices[i]; Matrix *C = &matrices[i]; - wise(C, C, A, false); + // printf("WISE 1 iteration: %ld i: %ld\n", iteration, i); // matrix_print_lazy(A); // matrix_print_lazy(C); + wise(C, C, A, false); + // matrix_print_lazy(C); } TIMER_STOP("WISE 1", &wise1); @@ -1236,14 +1240,23 @@ GrB_Info LAGraph_CFL_reachability_adv( Matrix *A = &matrices[bin_rule.prod_B]; Matrix *B = &delta_matrices[bin_rule.prod_A]; Matrix *C = &temp_matrices[bin_rule.nonterm]; - // printf("ITER: %ld\n", i); - mxm(C, A, B, true, true); + + // printf("MXM 2 iteration: %ld i: %ld\n", iteration, i); // matrix_print_lazy(A); // matrix_print_lazy(B); // matrix_print_lazy(C); + mxm(C, A, B, true, true); + // matrix_print_lazy(C); } TIMER_STOP("MXM 2", &mxm2); + // printf("Simple rules iteration: %ld i: %ld\n", iteration, i); + // matrix_print_lazy(A); + // matrix_print_lazy(B); + wise(A, A, B, true); + // matrix_print_lazy(A); + } + TIMER_START(); for (size_t i = 0; i < symbols_amount; i++) { matrix_dup_empty(&delta_matrices[i], &temp_matrices[i]); @@ -1255,9 +1268,11 @@ GrB_Info LAGraph_CFL_reachability_adv( Matrix *A = &matrices[i]; Matrix *C = &delta_matrices[i]; - rsub(C, A); + // printf("RSUB iteration: %ld i: %ld\n", iteration, i); // matrix_print_lazy(A); // matrix_print_lazy(C); + rsub(C, A); + // matrix_print_lazy(C); } TIMER_STOP("WISE 3 (MASK)", &rsubt); From ee4ffa4c670c7973b96598f9f565179ab5777f48 Mon Sep 17 00:00:00 2001 From: Homka122 Date: Sun, 25 May 2025 19:40:56 +0300 Subject: [PATCH 071/122] Feat: add simple rules adding to matrices If rule Nonterm -> nonterm appear --- experimental/algorithm/LAGraph_CFL_reachability_advanced.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/experimental/algorithm/LAGraph_CFL_reachability_advanced.c b/experimental/algorithm/LAGraph_CFL_reachability_advanced.c index 4fa22b0aa6..c3b77b3d2c 100644 --- a/experimental/algorithm/LAGraph_CFL_reachability_advanced.c +++ b/experimental/algorithm/LAGraph_CFL_reachability_advanced.c @@ -1250,6 +1250,12 @@ GrB_Info LAGraph_CFL_reachability_adv( } TIMER_STOP("MXM 2", &mxm2); + // Rule [Variable -> term] + for (size_t i = 0; i < term_rules_count; i++) { + LAGraph_rule_WCNF term_rule = rules[term_rules[i]]; + Matrix *A = &temp_matrices[term_rule.nonterm]; + Matrix *B = &delta_matrices[term_rule.prod_A]; + // printf("Simple rules iteration: %ld i: %ld\n", iteration, i); // matrix_print_lazy(A); // matrix_print_lazy(B); From e166fc12ad48facf3396b07201dfe130eeb8c994 Mon Sep 17 00:00:00 2001 From: Homka122 Date: Sun, 25 May 2025 19:41:37 +0300 Subject: [PATCH 072/122] Refactor: move custom methods definition --- .../LAGraph_CFL_reachability_advanced.c | 83 +++++++++---------- 1 file changed, 38 insertions(+), 45 deletions(-) diff --git a/experimental/algorithm/LAGraph_CFL_reachability_advanced.c b/experimental/algorithm/LAGraph_CFL_reachability_advanced.c index c3b77b3d2c..fb0c256f7e 100644 --- a/experimental/algorithm/LAGraph_CFL_reachability_advanced.c +++ b/experimental/algorithm/LAGraph_CFL_reachability_advanced.c @@ -1108,51 +1108,6 @@ GrB_Info LAGraph_CFL_reachability_adv( return GrB_INVALID_VALUE; } - // Rule [Variable -> term] - for (size_t i = 0; i < term_rules_count; i++) { - LAGraph_rule_WCNF term_rule = rules[term_rules[i]]; - GrB_Index adj_matrix_nnz = 0; - GRB_TRY(GrB_Matrix_nvals(&adj_matrix_nnz, adj_matrices[term_rule.prod_A])); - - if (adj_matrix_nnz == 0) { - continue; - } - - GxB_eWiseUnion(delta_matrices[term_rule.nonterm].base, GrB_NULL, GrB_NULL, - GxB_PAIR_BOOL, delta_matrices[term_rule.nonterm].base, true_scalar, - adj_matrices[term_rule.prod_A], true_scalar, GrB_NULL); - matrix_update(&delta_matrices[term_rule.nonterm]); - -#ifdef DEBUG_CFL_REACHBILITY - GxB_Matrix_iso(&iso_flag, T[term_rule.nonterm]); - printf("[TERM] eWiseUnion: NONTERM: %d (ISO: %d)\n", term_rule.nonterm, iso_flag); -#endif - } - - GrB_Vector v_diag; - GRB_TRY(GrB_Vector_new(&v_diag, GrB_BOOL, n)); - GRB_TRY(GrB_Vector_assign_BOOL(v_diag, GrB_NULL, GrB_NULL, true, GrB_ALL, n, NULL)); - GRB_TRY(GrB_Matrix_diag(&identity_matrix, v_diag, 0)); - GRB_TRY(GrB_free(&v_diag)); - - // Rule [Variable -> eps] - for (size_t i = 0; i < eps_rules_count; i++) { - LAGraph_rule_WCNF eps_rule = rules[eps_rules[i]]; - - GxB_eWiseUnion(delta_matrices[eps_rule.nonterm].base, GrB_NULL, GxB_PAIR_BOOL, - GxB_PAIR_BOOL, delta_matrices[eps_rule.nonterm].base, true_scalar, - identity_matrix, true_scalar, GrB_NULL); - matrix_update(&delta_matrices[eps_rule.nonterm]); - -#ifdef DEBUG_CFL_REACHBILITY - GxB_Matrix_iso(&iso_flag, T[eps_rule.nonterm]); - printf("[EPS] eWiseUnion: NONTERM: %d (ISO: %d)\n", eps_rule.nonterm, iso_flag); -#endif - } - - // Rule [Variable -> Variable1 Variable2] - LG_TRY(LAGraph_Calloc((void **)&nnzs, nonterms_count, sizeof(uint64_t), msg)); - typedef GrB_Info (*matrix_mxm_fn)(Matrix *output, Matrix *first, Matrix *second, bool accum, bool swap); typedef GrB_Info (*matrix_wise_fn)(Matrix *output, Matrix *first, Matrix *second, @@ -1185,6 +1140,44 @@ GrB_Info LAGraph_CFL_reachability_adv( rsub = matrix_rsub; } + // Rule [Variable -> term] + for (size_t i = 0; i < term_rules_count; i++) { + LAGraph_rule_WCNF term_rule = rules[term_rules[i]]; + Matrix *nonterm_matrix = &delta_matrices[term_rule.nonterm]; + Matrix *term_matrix = &delta_matrices[term_rule.prod_A]; + + GRB_TRY(wise(nonterm_matrix, nonterm_matrix, term_matrix, true)); + +#ifdef DEBUG_CFL_REACHBILITY + GxB_Matrix_iso(&iso_flag, T[term_rule.nonterm]); + printf("[TERM] eWiseUnion: NONTERM: %d (ISO: %d)\n", term_rule.nonterm, iso_flag); +#endif + } + + GrB_Vector v_diag; + GRB_TRY(GrB_Vector_new(&v_diag, GrB_BOOL, n)); + GRB_TRY(GrB_Vector_assign_BOOL(v_diag, GrB_NULL, GrB_NULL, true, GrB_ALL, n, NULL)); + GRB_TRY(GrB_Matrix_diag(&identity_matrix, v_diag, 0)); + GRB_TRY(GrB_free(&v_diag)); + Matrix iden = matrix_from_base(identity_matrix); + + // Rule [Variable -> eps] + for (size_t i = 0; i < eps_rules_count; i++) { + LAGraph_rule_WCNF eps_rule = rules[eps_rules[i]]; + + Matrix *nonterm_matrix = &delta_matrices[eps_rule.nonterm]; + + wise(nonterm_matrix, nonterm_matrix, &iden, true); + +#ifdef DEBUG_CFL_REACHBILITY + GxB_Matrix_iso(&iso_flag, T[eps_rule.nonterm]); + printf("[EPS] eWiseUnion: NONTERM: %d (ISO: %d)\n", eps_rule.nonterm, iso_flag); +#endif + } + + // Rule [Variable -> Variable1 Variable2] + LG_TRY(LAGraph_Calloc((void **)&nnzs, symbols_amount, sizeof(uint64_t), msg)); + double start_time, end_time; bool changed = true; size_t iteration = 0; From 5b7370843a828d86bad2885d794176b9c09c59a5 Mon Sep 17 00:00:00 2001 From: Homka122 Date: Sun, 25 May 2025 19:42:06 +0300 Subject: [PATCH 073/122] Feat: now delta matrices dublicates from adj matrices --- .../algorithm/LAGraph_CFL_reachability_advanced.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/experimental/algorithm/LAGraph_CFL_reachability_advanced.c b/experimental/algorithm/LAGraph_CFL_reachability_advanced.c index fb0c256f7e..eae12bd336 100644 --- a/experimental/algorithm/LAGraph_CFL_reachability_advanced.c +++ b/experimental/algorithm/LAGraph_CFL_reachability_advanced.c @@ -1017,11 +1017,13 @@ GrB_Info LAGraph_CFL_reachability_adv( GRB_TRY(GrB_Matrix_new(&T[i], GrB_BOOL, n, n)); - GRB_TRY(GrB_Matrix_new(&matrix, GrB_BOOL, n, n)); - delta_matrices[i] = matrix_from_base(matrix); + GrB_Matrix_dup(&delta_matrices[i].base, adj_matrices[i]); + delta_matrices[i] = matrix_from_base(delta_matrices[i].base); - GrB_Matrix_dup(&matrices[i].base, adj_matrices[i]); - matrices[i] = matrix_from_base_lazy(matrices[i].base); + GRB_TRY(GrB_Matrix_new(&matrix, GrB_BOOL, n, n)); + matrices[i] = optimizations & OPT_LAZY ? matrix_from_base_lazy(matrix) + : matrix_from_base(matrix); + // matrix_print_lazy(&matrices[i]); GRB_TRY(GrB_Matrix_new(&matrix, GrB_BOOL, n, n)); temp_matrices[i] = matrix_from_base(matrix); From 5502c89b6af815e1ebc15198ab5ce6efe7bb6a39 Mon Sep 17 00:00:00 2001 From: Homka122 Date: Sun, 25 May 2025 19:42:44 +0300 Subject: [PATCH 074/122] Refactor: rework print lazy method --- .../LAGraph_CFL_reachability_advanced.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/experimental/algorithm/LAGraph_CFL_reachability_advanced.c b/experimental/algorithm/LAGraph_CFL_reachability_advanced.c index eae12bd336..a4a6969645 100644 --- a/experimental/algorithm/LAGraph_CFL_reachability_advanced.c +++ b/experimental/algorithm/LAGraph_CFL_reachability_advanced.c @@ -851,13 +851,20 @@ GrB_Info matrix_rsub_block(Matrix *output, Matrix *mask) { } void matrix_print_lazy(Matrix *A) { - if (A->base_matrices_count == 0) { - GxB_print(A->base, 1); + return; + GxB_Print_Level pr = 1; + + if (!A->is_lazy) { + matrix_update(A); + GxB_print(A->base, pr); + // printf("nnz: %ld\n", A->nvals); return; } if (A->base_matrices_count == 1) { - GxB_print(A->base_matrices[0].base, 1); + matrix_update(A); + // printf("nnz: %ld\n", A->nvals); + GxB_print(A->base_matrices[0].base, pr); return; } @@ -869,7 +876,8 @@ void matrix_print_lazy(Matrix *A) { } A = &temp; - GxB_print(A->base, 1); + GxB_print(A->base, pr); + // printf("nnz: %ld\n", A->nvals); GrB_free(&_temp); } From 6ce43b01f8cea54887c0eb4e045fda3821196c2f Mon Sep 17 00:00:00 2001 From: Homka122 Date: Sun, 25 May 2025 19:46:48 +0300 Subject: [PATCH 075/122] Fix: check is lazy status in mxm lazy method --- experimental/algorithm/LAGraph_CFL_reachability_advanced.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/experimental/algorithm/LAGraph_CFL_reachability_advanced.c b/experimental/algorithm/LAGraph_CFL_reachability_advanced.c index a4a6969645..a4be6d755a 100644 --- a/experimental/algorithm/LAGraph_CFL_reachability_advanced.c +++ b/experimental/algorithm/LAGraph_CFL_reachability_advanced.c @@ -543,11 +543,10 @@ GrB_Info matrix_mxm_empty(Matrix *output, Matrix *first, Matrix *second, bool ac GrB_Info matrix_mxm_lazy(Matrix *output, Matrix *first, Matrix *second, bool accum, bool swap) { - if (first->base_matrices_count == 0) { + if (!first->is_lazy) { return matrix_mxm_empty(output, first, second, accum, swap); } - matrix_sort_lazy(first, true); matrix_combine_lazy(first, second->nvals); GrB_Matrix *accs = malloc(sizeof(GrB_Matrix) * first->base_matrices_count); From b0d3f53d921dbc6e395047ecb0e19a92c6c8204d Mon Sep 17 00:00:00 2001 From: Homka122 Date: Sun, 25 May 2025 20:21:29 +0300 Subject: [PATCH 076/122] Feat: add iadd interpration to wise methods --- .../LAGraph_CFL_reachability_advanced.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/experimental/algorithm/LAGraph_CFL_reachability_advanced.c b/experimental/algorithm/LAGraph_CFL_reachability_advanced.c index a4be6d755a..ef89893ffb 100644 --- a/experimental/algorithm/LAGraph_CFL_reachability_advanced.c +++ b/experimental/algorithm/LAGraph_CFL_reachability_advanced.c @@ -627,6 +627,8 @@ GrB_Info matrix_mxm_block(Matrix *output, Matrix *first, Matrix *second, bool ac GrB_Info matrix_wise(Matrix *output, Matrix *first, Matrix *second, bool accum) { GrB_BinaryOp accum_op = accum ? GxB_ANY_BOOL : GrB_NULL; + if (output == first) + accum_op = GrB_NULL; GrB_Info result = GrB_eWiseAdd(output->base, GrB_NULL, accum_op, GxB_ANY_BOOL, first->base, second->base, GrB_NULL); @@ -663,8 +665,20 @@ GrB_Info matrix_wise_format(Matrix *output, Matrix *first, Matrix *second, bool } GrB_Info matrix_wise_empty(Matrix *output, Matrix *first, Matrix *second, bool accum) { + if (output == first) { + if (first->nvals == 0) { + return matrix_dup_empty(first, second); + } + + if (second->nvals == 0) { + return GrB_SUCCESS; + } + + return matrix_wise_format(output, first, second, accum); + } + if (first->nvals == 0 && second->nvals == 0) { - if (accum) { + if (accum || output->nvals == 0) { return GrB_SUCCESS; } From 5100773661d9ef0d441c0005a19c0ad2d754aec1 Mon Sep 17 00:00:00 2001 From: Homka122 Date: Sun, 25 May 2025 20:39:00 +0300 Subject: [PATCH 077/122] Fix: problems with sorting in mxm lazy --- .../algorithm/LAGraph_CFL_reachability_advanced.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/experimental/algorithm/LAGraph_CFL_reachability_advanced.c b/experimental/algorithm/LAGraph_CFL_reachability_advanced.c index ef89893ffb..ff18a069d7 100644 --- a/experimental/algorithm/LAGraph_CFL_reachability_advanced.c +++ b/experimental/algorithm/LAGraph_CFL_reachability_advanced.c @@ -535,6 +535,10 @@ GrB_Info matrix_mxm_empty(Matrix *output, Matrix *first, Matrix *second, bool ac return GrB_SUCCESS; } + if (output->nvals == 0) { + return GrB_SUCCESS; + } + matrix_clear_empty(output); } @@ -548,6 +552,7 @@ GrB_Info matrix_mxm_lazy(Matrix *output, Matrix *first, Matrix *second, bool acc } matrix_combine_lazy(first, second->nvals); + matrix_sort_lazy(first, false); GrB_Matrix *accs = malloc(sizeof(GrB_Matrix) * first->base_matrices_count); Matrix *acc_matrices = malloc(sizeof(Matrix) * first->base_matrices_count); @@ -557,12 +562,12 @@ GrB_Info matrix_mxm_lazy(Matrix *output, Matrix *first, Matrix *second, bool acc } for (size_t i = 0; i < first->base_matrices_count; i++) { - matrix_mxm_empty(&acc_matrices[i], &first->base_matrices[i], second, accum, swap); + matrix_mxm_empty(&acc_matrices[i], &first->base_matrices[i], second, false, swap); } for (size_t i = 0; i < first->base_matrices_count; i++) { for (size_t j = i + 1; j < first->base_matrices_count; j++) { - if (acc_matrices[i].nvals < acc_matrices[j].nvals) { + if (acc_matrices[i].nvals > acc_matrices[j].nvals) { Matrix temp = acc_matrices[i]; acc_matrices[i] = acc_matrices[j]; acc_matrices[j] = temp; From 2e63e5fe5cc014938b8e250901f90c3715b058b9 Mon Sep 17 00:00:00 2001 From: Homka122 Date: Sun, 25 May 2025 20:39:59 +0300 Subject: [PATCH 078/122] Fix: update matrix after combine base matrices --- experimental/algorithm/LAGraph_CFL_reachability_advanced.c | 1 + 1 file changed, 1 insertion(+) diff --git a/experimental/algorithm/LAGraph_CFL_reachability_advanced.c b/experimental/algorithm/LAGraph_CFL_reachability_advanced.c index ff18a069d7..ee99527f8a 100644 --- a/experimental/algorithm/LAGraph_CFL_reachability_advanced.c +++ b/experimental/algorithm/LAGraph_CFL_reachability_advanced.c @@ -492,6 +492,7 @@ GrB_Info matrix_combine_lazy(Matrix *A, size_t threshold) { A->base_matrices = new_matrices; A->base_matrices_count = new_size; + matrix_update(A); return GrB_SUCCESS; } From 08a19c9c974aeef1c930e27401e8dd0599bf71ac Mon Sep 17 00:00:00 2001 From: Homka122 Date: Sun, 25 May 2025 20:40:26 +0300 Subject: [PATCH 079/122] Refactor: now use TRY macro --- .../LAGraph_CFL_reachability_advanced.c | 29 ++++++++++++------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/experimental/algorithm/LAGraph_CFL_reachability_advanced.c b/experimental/algorithm/LAGraph_CFL_reachability_advanced.c index ee99527f8a..f4be606b5f 100644 --- a/experimental/algorithm/LAGraph_CFL_reachability_advanced.c +++ b/experimental/algorithm/LAGraph_CFL_reachability_advanced.c @@ -139,7 +139,8 @@ { \ GrB_Info LG_GrB_Info = GrB_method; \ if (LG_GrB_Info < GrB_SUCCESS) { \ - return LG_GrB_Info; \ + fprintf(stderr, "LAGraph failure (file %s, line %d): ", __FILE__, __LINE__); \ + exit(LG_GrB_Info); \ } \ } @@ -162,19 +163,24 @@ typedef struct Matrix { void matrix_update(Matrix *matrix) { if (!matrix->is_lazy) { - GrB_Matrix_nvals(&matrix->nvals, matrix->base); + TRY(GrB_Matrix_nvals(&matrix->nvals, matrix->base)); } else { size_t new_nnz = 0; for (size_t i = 0; i < matrix->base_matrices_count; i++) { - GrB_Matrix_nvals(&matrix->base_matrices[i].nvals, - matrix->base_matrices[i].base); + TRY(GrB_Matrix_nvals(&matrix->base_matrices[i].nvals, + matrix->base_matrices[i].base)); new_nnz += matrix->base_matrices[i].nvals; } matrix->nvals = new_nnz; } - GrB_Matrix_nrows(&matrix->nrows, matrix->base); - GrB_Matrix_ncols(&matrix->ncols, matrix->base); + if (!matrix->is_lazy) { + TRY(GrB_Matrix_nrows(&matrix->nrows, matrix->base)); + TRY(GrB_Matrix_ncols(&matrix->ncols, matrix->base)); + } else { + TRY(GrB_Matrix_nrows(&matrix->nrows, matrix->base_matrices[0].base)); + TRY(GrB_Matrix_ncols(&matrix->ncols, matrix->base_matrices[0].base)); + } if (matrix->nrows > matrix->ncols) { matrix->block_type = VEC_VERT; @@ -216,7 +222,7 @@ Matrix matrix_from_base_lazy(GrB_Matrix matrix) { Matrix matrix_create(GrB_Index nrows, GrB_Index ncols) { GrB_Matrix _result; - GrB_Matrix_new(&_result, GrB_BOOL, nrows, ncols); + TRY(GrB_Matrix_new(&_result, GrB_BOOL, nrows, ncols)); Matrix result = matrix_from_base(_result); return result; @@ -224,7 +230,7 @@ Matrix matrix_create(GrB_Index nrows, GrB_Index ncols) { void matrix_free(Matrix *matrix) { free(matrix->base_matrices); - GrB_free(&matrix->base); + TRY(GrB_free(&matrix->base)); } void matrix_to_format(Matrix *matrix, int32_t format, bool is_both) { @@ -247,9 +253,9 @@ void matrix_to_format(Matrix *matrix, int32_t format, bool is_both) { matrix->format == GrB_ROWMAJOR ? &matrix->base_row : &matrix->base_col; if (is_both) { - GrB_Matrix_new(new_matrix, GrB_BOOL, matrix->nrows, matrix->ncols); - GrB_Matrix_assign(*new_matrix, GrB_NULL, GrB_NULL, *old_matrix, GrB_ALL, - matrix->nrows, GrB_ALL, matrix->ncols, GrB_NULL); + TRY(GrB_Matrix_new(new_matrix, GrB_BOOL, matrix->nrows, matrix->ncols)); + TRY(GrB_Matrix_assign(*new_matrix, GrB_NULL, GrB_NULL, *old_matrix, GrB_ALL, + matrix->nrows, GrB_ALL, matrix->ncols, GrB_NULL)); matrix->is_both = true; } else { *new_matrix = *old_matrix; @@ -264,6 +270,7 @@ void matrix_to_format(Matrix *matrix, int32_t format, bool is_both) { GrB_Info matrix_clear(Matrix *A) { GrB_Info result = GrB_Matrix_clear(A->base); + TRY(result); matrix_update(A); return result; } From df5cdea066145be4c6946777d4d14e7ba7fdb7aa Mon Sep 17 00:00:00 2001 From: Homka122 Date: Sun, 25 May 2025 20:51:14 +0300 Subject: [PATCH 080/122] Fix: return from block mxm is both matrices are cell --- experimental/algorithm/LAGraph_CFL_reachability_advanced.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/experimental/algorithm/LAGraph_CFL_reachability_advanced.c b/experimental/algorithm/LAGraph_CFL_reachability_advanced.c index f4be606b5f..e54f749f40 100644 --- a/experimental/algorithm/LAGraph_CFL_reachability_advanced.c +++ b/experimental/algorithm/LAGraph_CFL_reachability_advanced.c @@ -605,7 +605,7 @@ GrB_Info matrix_mxm_lazy(Matrix *output, Matrix *first, Matrix *second, bool acc GrB_Info matrix_mxm_block(Matrix *output, Matrix *first, Matrix *second, bool accum, bool swap) { if (first->block_type == CELL && second->block_type == CELL) { - matrix_mxm_lazy(output, first, second, accum, swap); + return matrix_mxm_lazy(output, first, second, accum, swap); } if (first->block_type == CELL) { From 8a1b404bfca4eae327018e44b9ff9e8e28780fd7 Mon Sep 17 00:00:00 2001 From: Homka122 Date: Sun, 25 May 2025 21:00:15 +0300 Subject: [PATCH 081/122] Fix: use lazy matrices with lazy optimization and higher --- experimental/algorithm/LAGraph_CFL_reachability_advanced.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/experimental/algorithm/LAGraph_CFL_reachability_advanced.c b/experimental/algorithm/LAGraph_CFL_reachability_advanced.c index e54f749f40..5533dc662a 100644 --- a/experimental/algorithm/LAGraph_CFL_reachability_advanced.c +++ b/experimental/algorithm/LAGraph_CFL_reachability_advanced.c @@ -1055,8 +1055,9 @@ GrB_Info LAGraph_CFL_reachability_adv( delta_matrices[i] = matrix_from_base(delta_matrices[i].base); GRB_TRY(GrB_Matrix_new(&matrix, GrB_BOOL, n, n)); - matrices[i] = optimizations & OPT_LAZY ? matrix_from_base_lazy(matrix) - : matrix_from_base(matrix); + matrices[i] = ((optimizations & OPT_LAZY) || (optimizations & OPT_BLOCK)) + ? matrix_from_base_lazy(matrix) + : matrix_from_base(matrix); // matrix_print_lazy(&matrices[i]); GRB_TRY(GrB_Matrix_new(&matrix, GrB_BOOL, n, n)); From 88f25bd2dc466eff1fac493acff7e3f144fb0045 Mon Sep 17 00:00:00 2001 From: Homka122 Date: Sun, 25 May 2025 21:01:00 +0300 Subject: [PATCH 082/122] Fix: wise_block --- .../algorithm/LAGraph_CFL_reachability_advanced.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/experimental/algorithm/LAGraph_CFL_reachability_advanced.c b/experimental/algorithm/LAGraph_CFL_reachability_advanced.c index 5533dc662a..7d4da337a8 100644 --- a/experimental/algorithm/LAGraph_CFL_reachability_advanced.c +++ b/experimental/algorithm/LAGraph_CFL_reachability_advanced.c @@ -312,7 +312,7 @@ void block_matrix_hyper_rotate_i(Matrix *matrix, enum Matrix_block format) { GrB_Scalar_new(&scalar_true, GrB_BOOL); GrB_Scalar_setElement_BOOL(scalar_true, true); - if (matrix->format == VEC_VERT) { + if (matrix->block_type == VEC_VERT) { GrB_Index *nrows = malloc(matrix->nvals * sizeof(GrB_Index)); GrB_Index *ncols = malloc(matrix->nvals * sizeof(GrB_Index)); @@ -330,7 +330,7 @@ void block_matrix_hyper_rotate_i(Matrix *matrix, enum Matrix_block format) { return; } - if (matrix->format == VEC_HORIZ) { + if (matrix->block_type == VEC_HORIZ) { GrB_Index *nrows = malloc(matrix->nvals * sizeof(GrB_Index)); GrB_Index *ncols = malloc(matrix->nvals * sizeof(GrB_Index)); @@ -396,13 +396,13 @@ void block_matrix_reduce(Matrix *matrix, Matrix *input) { GrB_Index *cols = malloc(input->nvals * sizeof(GrB_Index)); GrB_Matrix_extractTuples_BOOL(rows, cols, NULL, &input->nvals, input->base); - if (input->format == VEC_VERT) { + if (input->block_type == VEC_VERT) { for (size_t i = 0; i < input->nvals; i++) { rows[i] = rows[i] % input->ncols; } } - if (input->format == VEC_HORIZ) { + if (input->block_type == VEC_HORIZ) { for (size_t i = 0; i < input->nvals; i++) { cols[i] = cols[i] % input->nrows; } @@ -779,7 +779,7 @@ GrB_Info matrix_wise_block(Matrix *output, Matrix *first, Matrix *second, bool a } if (first->block_type == CELL && second->block_type == CELL) { - matrix_wise_lazy(output, first, second, accum); + return matrix_wise_lazy(output, first, second, accum); } // second is vector @@ -794,10 +794,12 @@ GrB_Info matrix_wise_block(Matrix *output, Matrix *first, Matrix *second, bool a // first is vector if (second->block_type == CELL) { + // LG_SET_BURBLE(true); Matrix temp_vector = matrix_create(first->nrows, first->ncols); GrB_Index block_count = first->nrows > first->ncols ? first->nrows : first->ncols; block_matrix_repeat_into_vector(&temp_vector, second, block_count); + block_matrix_hyper_rotate_i(&temp_vector, first->block_type); GrB_Info info = matrix_wise_lazy(output, first, &temp_vector, accum); matrix_free(&temp_vector); return info; @@ -805,7 +807,7 @@ GrB_Info matrix_wise_block(Matrix *output, Matrix *first, Matrix *second, bool a // both are vector block_matrix_hyper_rotate_i(second, first->block_type); - return matrix_wise_block(output, first, second, accum); + return matrix_wise_lazy(output, first, second, accum); } GrB_Info matrix_rsub(Matrix *output, Matrix *mask) { From c05d6c086a4cde2ff712305a24275e6b7580e33d Mon Sep 17 00:00:00 2001 From: Homka122 Date: Sun, 25 May 2025 22:01:33 +0300 Subject: [PATCH 083/122] Fix: forget update matrix after changing --- experimental/algorithm/LAGraph_CFL_reachability_advanced.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/experimental/algorithm/LAGraph_CFL_reachability_advanced.c b/experimental/algorithm/LAGraph_CFL_reachability_advanced.c index 7d4da337a8..3b639134b6 100644 --- a/experimental/algorithm/LAGraph_CFL_reachability_advanced.c +++ b/experimental/algorithm/LAGraph_CFL_reachability_advanced.c @@ -409,6 +409,7 @@ void block_matrix_reduce(Matrix *matrix, Matrix *input) { } GxB_Matrix_build_Scalar(matrix->base, rows, cols, scalar_true, input->nvals); + matrix_update(matrix); free(rows); free(cols); @@ -423,6 +424,7 @@ void block_matrix_repeat_into_vector(Matrix *matrix, Matrix *input, } GxB_Matrix_concat(matrix->base, tiles, block_count, 1, GrB_NULL); + matrix_update(matrix); } GrB_Info matrix_dup(Matrix *output, Matrix *input) { From e0841c0a4193e6043d68a84c4e2c01320a0eb4f6 Mon Sep 17 00:00:00 2001 From: Homka122 Date: Sun, 25 May 2025 22:04:49 +0300 Subject: [PATCH 084/122] Fix: now if symbol is indexed matrix is block --- .../algorithm/LAGraph_CFL_reachability_advanced.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/experimental/algorithm/LAGraph_CFL_reachability_advanced.c b/experimental/algorithm/LAGraph_CFL_reachability_advanced.c index 3b639134b6..0859970796 100644 --- a/experimental/algorithm/LAGraph_CFL_reachability_advanced.c +++ b/experimental/algorithm/LAGraph_CFL_reachability_advanced.c @@ -1055,16 +1055,20 @@ GrB_Info LAGraph_CFL_reachability_adv( GRB_TRY(GrB_Matrix_new(&T[i], GrB_BOOL, n, n)); + GrB_Index nrows; + GrB_Matrix_nrows(&nrows, adj_matrices[i]); + GrB_Index ncols; + GrB_Matrix_ncols(&ncols, adj_matrices[i]); + GrB_Matrix_dup(&delta_matrices[i].base, adj_matrices[i]); delta_matrices[i] = matrix_from_base(delta_matrices[i].base); - GRB_TRY(GrB_Matrix_new(&matrix, GrB_BOOL, n, n)); + GRB_TRY(GrB_Matrix_new(&matrix, GrB_BOOL, nrows, ncols)); matrices[i] = ((optimizations & OPT_LAZY) || (optimizations & OPT_BLOCK)) ? matrix_from_base_lazy(matrix) : matrix_from_base(matrix); - // matrix_print_lazy(&matrices[i]); - GRB_TRY(GrB_Matrix_new(&matrix, GrB_BOOL, n, n)); + GRB_TRY(GrB_Matrix_new(&matrix, GrB_BOOL, nrows, ncols)); temp_matrices[i] = matrix_from_base(matrix); } From 61ada9392e7a686037a9dbc5d72fb371c157946d Mon Sep 17 00:00:00 2001 From: Homka122 Date: Fri, 30 May 2025 20:00:10 +0300 Subject: [PATCH 085/122] Feat: add print_graph_info function --- .../LAGraph_CFL_reachability_advanced.c | 34 +++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/experimental/algorithm/LAGraph_CFL_reachability_advanced.c b/experimental/algorithm/LAGraph_CFL_reachability_advanced.c index 0859970796..65dc4b4d69 100644 --- a/experimental/algorithm/LAGraph_CFL_reachability_advanced.c +++ b/experimental/algorithm/LAGraph_CFL_reachability_advanced.c @@ -911,6 +911,18 @@ void matrix_print_lazy(Matrix *A) { GrB_free(&_temp); } +void print_graph_info(Matrix *matrices, size_t count) { + GrB_Index nnz = 0; + + for (size_t i = 0; i < count; i++) { + Matrix *A = &matrices[i]; + matrix_update(A); + nnz += A->nvals; + } + + printf("NNZ: %ld\n", nnz); +} + #define IS_NONTERM(index) \ { \ for (size_t m = 0; m < rules_count; m++) { \ @@ -1231,6 +1243,9 @@ GrB_Info LAGraph_CFL_reachability_adv( double mxm2 = 0.0; double wise2 = 0.0; double rsubt = 0.0; + // print_graph_info(matrices, symbols_amount); + // print_graph_info(delta_matrices, symbols_amount); + // print_graph_info(temp_matrices, symbols_amount); while (changed) { iteration++; changed = false; @@ -1258,6 +1273,9 @@ GrB_Info LAGraph_CFL_reachability_adv( // matrix_print_lazy(C); } TIMER_STOP("MXM 1", &mxm1); + // print_graph_info(matrices, symbols_amount); + // print_graph_info(delta_matrices, symbols_amount); + // print_graph_info(temp_matrices, symbols_amount); TIMER_START() for (size_t i = 0; i < symbols_amount; i++) { @@ -1271,6 +1289,9 @@ GrB_Info LAGraph_CFL_reachability_adv( // matrix_print_lazy(C); } TIMER_STOP("WISE 1", &wise1); + // print_graph_info(matrices, symbols_amount); + // print_graph_info(delta_matrices, symbols_amount); + // print_graph_info(temp_matrices, symbols_amount); TIMER_START() for (size_t i = 0; i < bin_rules_count; i++) { @@ -1287,6 +1308,9 @@ GrB_Info LAGraph_CFL_reachability_adv( // matrix_print_lazy(C); } TIMER_STOP("MXM 2", &mxm2); + // print_graph_info(matrices, symbols_amount); + // print_graph_info(delta_matrices, symbols_amount); + // print_graph_info(temp_matrices, symbols_amount); // Rule [Variable -> term] for (size_t i = 0; i < term_rules_count; i++) { @@ -1300,12 +1324,19 @@ GrB_Info LAGraph_CFL_reachability_adv( wise(A, A, B, true); // matrix_print_lazy(A); } + // printf("Simple rules\n"); + // print_graph_info(matrices, symbols_amount); + // print_graph_info(delta_matrices, symbols_amount); + // print_graph_info(temp_matrices, symbols_amount); TIMER_START(); for (size_t i = 0; i < symbols_amount; i++) { matrix_dup_empty(&delta_matrices[i], &temp_matrices[i]); } TIMER_STOP("WISE 2 (copy)", &wise2); + // print_graph_info(matrices, symbols_amount); + // print_graph_info(delta_matrices, symbols_amount); + // print_graph_info(temp_matrices, symbols_amount); TIMER_START(); for (size_t i = 0; i < symbols_amount; i++) { @@ -1319,6 +1350,9 @@ GrB_Info LAGraph_CFL_reachability_adv( // matrix_print_lazy(C); } TIMER_STOP("WISE 3 (MASK)", &rsubt); + // print_graph_info(matrices, symbols_amount); + // print_graph_info(delta_matrices, symbols_amount); + // print_graph_info(temp_matrices, symbols_amount); size_t new_nnz = 0; for (size_t i = 0; i < symbols_amount; i++) { From 22e4c4c6ebebfda42edf274dbdc66bfa20a5a56e Mon Sep 17 00:00:00 2001 From: Homka122 Date: Fri, 30 May 2025 20:01:13 +0300 Subject: [PATCH 086/122] Fix: add method for dup block matrices --- .../LAGraph_CFL_reachability_advanced.c | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/experimental/algorithm/LAGraph_CFL_reachability_advanced.c b/experimental/algorithm/LAGraph_CFL_reachability_advanced.c index 65dc4b4d69..27f9bf97e7 100644 --- a/experimental/algorithm/LAGraph_CFL_reachability_advanced.c +++ b/experimental/algorithm/LAGraph_CFL_reachability_advanced.c @@ -382,10 +382,11 @@ void block_matrix_to_diag(Matrix *diag, Matrix *input) { } GrB_Info matrix_dup_empty(Matrix *output, Matrix *input); +GrB_Info matrix_dup_block(Matrix *output, Matrix *input); void block_matrix_reduce(Matrix *matrix, Matrix *input) { if (input->block_type == CELL) { - matrix_dup_empty(matrix, input); + matrix_dup_block(matrix, input); } GrB_Scalar scalar_true; @@ -465,6 +466,15 @@ GrB_Info matrix_dup_empty(Matrix *output, Matrix *input) { return matrix_dup_format(output, input); } +GrB_Info matrix_dup_block(Matrix *output, Matrix *input) { + if (output->block_type == CELL && input->block_type == CELL) { + return matrix_dup_empty(output, input); + } + + block_matrix_hyper_rotate_i(input, output->block_type); + return matrix_dup_empty(output, input); +} + GrB_Info matrix_wise_empty(Matrix *output, Matrix *first, Matrix *second, bool accum); GrB_Info matrix_sort_lazy(Matrix *A, bool reverse) { @@ -598,7 +608,7 @@ GrB_Info matrix_mxm_lazy(Matrix *output, Matrix *first, Matrix *second, bool acc return matrix_wise_empty(output, output, &acc_matrix, false); } - GrB_Info result = matrix_dup_empty(output, &acc_matrix); + GrB_Info result = matrix_dup_block(output, &acc_matrix); GrB_free(&acc_matrix.base); return result; @@ -1331,7 +1341,7 @@ GrB_Info LAGraph_CFL_reachability_adv( TIMER_START(); for (size_t i = 0; i < symbols_amount; i++) { - matrix_dup_empty(&delta_matrices[i], &temp_matrices[i]); + matrix_dup_block(&delta_matrices[i], &temp_matrices[i]); } TIMER_STOP("WISE 2 (copy)", &wise2); // print_graph_info(matrices, symbols_amount); From 8c85e4eef4116b9f8712ba2aecdf82298e830828 Mon Sep 17 00:00:00 2001 From: Homka122 Date: Fri, 30 May 2025 20:08:58 +0300 Subject: [PATCH 087/122] Fix: bug that lazy matrix didn't create --- .../algorithm/LAGraph_CFL_reachability_advanced.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/experimental/algorithm/LAGraph_CFL_reachability_advanced.c b/experimental/algorithm/LAGraph_CFL_reachability_advanced.c index 27f9bf97e7..7f1d3bfe94 100644 --- a/experimental/algorithm/LAGraph_CFL_reachability_advanced.c +++ b/experimental/algorithm/LAGraph_CFL_reachability_advanced.c @@ -212,12 +212,14 @@ Matrix matrix_from_base(GrB_Matrix matrix) { Matrix matrix_from_base_lazy(GrB_Matrix matrix) { Matrix result = matrix_from_base(matrix); - result.is_lazy = true; - result.base_matrices_count = 1; - result.base_matrices[0] = matrix_from_base(result.base); + Matrix lazy_result = matrix_from_base(matrix); + lazy_result.is_lazy = true; + lazy_result.base_matrices[0] = result; + lazy_result.base_matrices_count = 1; + matrix_update(&lazy_result); - return result; + return lazy_result; } Matrix matrix_create(GrB_Index nrows, GrB_Index ncols) { From 6b59c0fb0be1b57eb4e2ae0347fbf3ff6ffd7e5b Mon Sep 17 00:00:00 2001 From: Homka122 Date: Fri, 30 May 2025 20:09:43 +0300 Subject: [PATCH 088/122] Fix: matrix mxm now can multiply not only square matrices --- experimental/algorithm/LAGraph_CFL_reachability_advanced.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/experimental/algorithm/LAGraph_CFL_reachability_advanced.c b/experimental/algorithm/LAGraph_CFL_reachability_advanced.c index 7f1d3bfe94..8aa9045ace 100644 --- a/experimental/algorithm/LAGraph_CFL_reachability_advanced.c +++ b/experimental/algorithm/LAGraph_CFL_reachability_advanced.c @@ -579,7 +579,8 @@ GrB_Info matrix_mxm_lazy(Matrix *output, Matrix *first, Matrix *second, bool acc GrB_Matrix *accs = malloc(sizeof(GrB_Matrix) * first->base_matrices_count); Matrix *acc_matrices = malloc(sizeof(Matrix) * first->base_matrices_count); for (size_t i = 0; i < first->base_matrices_count; i++) { - GrB_Matrix_new(&accs[i], GrB_BOOL, output->nrows, output->ncols); + GrB_Matrix_new(&accs[i], GrB_BOOL, swap ? second->nrows : first->nrows, + swap ? first->ncols : second->ncols); acc_matrices[i] = matrix_from_base(accs[i]); } @@ -598,7 +599,8 @@ GrB_Info matrix_mxm_lazy(Matrix *output, Matrix *first, Matrix *second, bool acc } GrB_Matrix acc; - GrB_Matrix_new(&acc, GrB_BOOL, first->nrows, first->ncols); + GrB_Matrix_new(&acc, GrB_BOOL, swap ? second->nrows : first->nrows, + swap ? first->ncols : second->ncols); Matrix acc_matrix = matrix_from_base(acc); for (size_t i = 0; i < first->base_matrices_count; i++) { From 46608e1ba57f682608ba656e68b679eed718ec2f Mon Sep 17 00:00:00 2001 From: Homka122 Date: Fri, 30 May 2025 20:10:51 +0300 Subject: [PATCH 089/122] Feat: create temp matrix in mxm block --- .../LAGraph_CFL_reachability_advanced.c | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/experimental/algorithm/LAGraph_CFL_reachability_advanced.c b/experimental/algorithm/LAGraph_CFL_reachability_advanced.c index 8aa9045ace..7a4ad17486 100644 --- a/experimental/algorithm/LAGraph_CFL_reachability_advanced.c +++ b/experimental/algorithm/LAGraph_CFL_reachability_advanced.c @@ -618,6 +618,8 @@ GrB_Info matrix_mxm_lazy(Matrix *output, Matrix *first, Matrix *second, bool acc return result; } +GrB_Info matrix_wise_block(Matrix *output, Matrix *first, Matrix *second, bool accum); + GrB_Info matrix_mxm_block(Matrix *output, Matrix *first, Matrix *second, bool accum, bool swap) { if (first->block_type == CELL && second->block_type == CELL) { @@ -628,7 +630,11 @@ GrB_Info matrix_mxm_block(Matrix *output, Matrix *first, Matrix *second, bool ac block_matrix_hyper_rotate_i(second, swap ? VEC_VERT : VEC_HORIZ); block_matrix_hyper_rotate_i(output, swap ? VEC_VERT : VEC_HORIZ); - matrix_mxm_lazy(output, first, second, accum, swap); + Matrix temp = matrix_create(swap ? second->nrows : first->nrows, + swap ? first->ncols : second->ncols); + matrix_mxm_lazy(&temp, first, second, accum, swap); + matrix_wise_block(output, output, &temp, false); + matrix_free(&temp); return GrB_SUCCESS; } @@ -637,7 +643,11 @@ GrB_Info matrix_mxm_block(Matrix *output, Matrix *first, Matrix *second, bool ac block_matrix_hyper_rotate_i(first, swap ? VEC_HORIZ : VEC_VERT); block_matrix_hyper_rotate_i(output, swap ? VEC_HORIZ : VEC_VERT); - matrix_mxm_lazy(output, first, second, accum, swap); + Matrix temp = matrix_create(swap ? second->nrows : first->nrows, + swap ? first->ncols : first->ncols); + matrix_mxm_lazy(&temp, first, second, accum, swap); + matrix_wise_block(output, output, &temp, false); + matrix_free(&temp); return GrB_SUCCESS; } @@ -647,11 +657,14 @@ GrB_Info matrix_mxm_block(Matrix *output, Matrix *first, Matrix *second, bool ac GrB_Matrix_new(&_diag, GrB_BOOL, size, size); Matrix diag = matrix_from_base(_diag); block_matrix_to_diag(&diag, second); + matrix_update(&diag); block_matrix_hyper_rotate_i(first, swap ? VEC_VERT : VEC_HORIZ); block_matrix_hyper_rotate_i(output, swap ? VEC_VERT : VEC_HORIZ); - return matrix_mxm_lazy(output, first, &diag, accum, swap); + Matrix temp = matrix_create(first->nrows, diag.ncols); + matrix_mxm_lazy(&temp, first, &diag, false, swap); + return matrix_wise_block(output, output, &temp, false); } GrB_Info matrix_wise(Matrix *output, Matrix *first, Matrix *second, bool accum) { From 513aecace64c71801cc323c02ce8eb9168d9327d Mon Sep 17 00:00:00 2001 From: Homka122 Date: Fri, 30 May 2025 20:17:59 +0300 Subject: [PATCH 090/122] Refactor: matrix dup now uses a different method --- .../algorithm/LAGraph_CFL_reachability_advanced.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/experimental/algorithm/LAGraph_CFL_reachability_advanced.c b/experimental/algorithm/LAGraph_CFL_reachability_advanced.c index 7a4ad17486..606de0c422 100644 --- a/experimental/algorithm/LAGraph_CFL_reachability_advanced.c +++ b/experimental/algorithm/LAGraph_CFL_reachability_advanced.c @@ -431,11 +431,15 @@ void block_matrix_repeat_into_vector(Matrix *matrix, Matrix *input, } GrB_Info matrix_dup(Matrix *output, Matrix *input) { - GrB_Info result = - GrB_Matrix_assign(output->base, GrB_NULL, GrB_NULL, input->base, GrB_ALL, - input->nrows, GrB_ALL, input->ncols, GrB_NULL); + if (output == input) { + return GrB_SUCCESS; + } + GrB_Info result = GrB_Matrix_apply(output->base, GrB_NULL, GrB_NULL, + GrB_IDENTITY_BOOL, input->base, GrB_NULL); + TRY(result); matrix_update(output); + return result; } From f49a6b2a2680f39ac28cf8dfb71b09590ee4d841 Mon Sep 17 00:00:00 2001 From: Homka122 Date: Fri, 30 May 2025 20:20:11 +0300 Subject: [PATCH 091/122] Fix: hyper rotate method --- .../LAGraph_CFL_reachability_advanced.c | 27 +++++++++++++++---- 1 file changed, 22 insertions(+), 5 deletions(-) diff --git a/experimental/algorithm/LAGraph_CFL_reachability_advanced.c b/experimental/algorithm/LAGraph_CFL_reachability_advanced.c index 606de0c422..b5a921209f 100644 --- a/experimental/algorithm/LAGraph_CFL_reachability_advanced.c +++ b/experimental/algorithm/LAGraph_CFL_reachability_advanced.c @@ -302,6 +302,15 @@ GrB_Info matrix_clear_empty(Matrix *A) { } void block_matrix_hyper_rotate_i(Matrix *matrix, enum Matrix_block format) { + if (matrix->is_lazy) { + for (size_t i = 0; i < matrix->base_matrices_count; i++) { + block_matrix_hyper_rotate_i(&matrix->base_matrices[i], format); + } + + matrix_update(matrix); + return; + } + if (matrix->block_type == CELL) { return; } @@ -321,11 +330,15 @@ void block_matrix_hyper_rotate_i(Matrix *matrix, enum Matrix_block format) { GrB_Matrix_extractTuples_BOOL(nrows, ncols, NULL, &matrix->nvals, matrix->base); for (size_t i = 0; i < matrix->nvals; i++) { - ncols[i] = ncols[i] + ncols[i] / matrix->ncols * matrix->ncols; + ncols[i] = ncols[i] + nrows[i] / matrix->ncols * matrix->ncols; nrows[i] = nrows[i] % matrix->ncols; } - GxB_Matrix_build_Scalar(matrix->base, nrows, ncols, scalar_true, matrix->nvals); + GrB_Matrix new; + TRY(GrB_Matrix_new(&new, GrB_BOOL, matrix->ncols, matrix->nrows)); + TRY(GxB_Matrix_build_Scalar(new, nrows, ncols, scalar_true, matrix->nvals)); + matrix_free(matrix); + *matrix = matrix->is_lazy ? matrix_from_base_lazy(new) : matrix_from_base(new); free(nrows); free(ncols); GrB_free(&scalar_true); @@ -339,11 +352,15 @@ void block_matrix_hyper_rotate_i(Matrix *matrix, enum Matrix_block format) { GrB_Matrix_extractTuples_BOOL(nrows, ncols, NULL, &matrix->nvals, matrix->base); for (size_t i = 0; i < matrix->nvals; i++) { - nrows[i] = nrows[i] + nrows[i] / matrix->nrows * matrix->nrows; - ncols[i] = ncols[i] % matrix->ncols; + nrows[i] = nrows[i] + ncols[i] / matrix->nrows * matrix->nrows; + ncols[i] = ncols[i] % matrix->nrows; } - GxB_Matrix_build_Scalar(matrix->base, nrows, ncols, scalar_true, matrix->nvals); + GrB_Matrix new; + TRY(GrB_Matrix_new(&new, GrB_BOOL, matrix->ncols, matrix->nrows)); + TRY(GxB_Matrix_build_Scalar(new, nrows, ncols, scalar_true, matrix->nvals)); + matrix_free(matrix); + *matrix = matrix->is_lazy ? matrix_from_base_lazy(new) : matrix_from_base(new); free(nrows); free(ncols); GrB_free(&scalar_true); From 697d23c44bc353e273073ea6ee2b1d9771277137 Mon Sep 17 00:00:00 2001 From: Homka122 Date: Fri, 30 May 2025 20:32:13 +0300 Subject: [PATCH 092/122] Feat: add aditional check in matrix update --- .../algorithm/LAGraph_CFL_reachability_advanced.c | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/experimental/algorithm/LAGraph_CFL_reachability_advanced.c b/experimental/algorithm/LAGraph_CFL_reachability_advanced.c index b5a921209f..d2caf0936c 100644 --- a/experimental/algorithm/LAGraph_CFL_reachability_advanced.c +++ b/experimental/algorithm/LAGraph_CFL_reachability_advanced.c @@ -174,6 +174,7 @@ void matrix_update(Matrix *matrix) { matrix->nvals = new_nnz; } + if (!matrix->is_lazy) { TRY(GrB_Matrix_nrows(&matrix->nrows, matrix->base)); TRY(GrB_Matrix_ncols(&matrix->ncols, matrix->base)); @@ -182,14 +183,10 @@ void matrix_update(Matrix *matrix) { TRY(GrB_Matrix_ncols(&matrix->ncols, matrix->base_matrices[0].base)); } - if (matrix->nrows > matrix->ncols) { - matrix->block_type = VEC_VERT; - } - - if (matrix->ncols > matrix->nrows) { - matrix->block_type = VEC_HORIZ; - } - // GrB_get(matrix->base, &matrix->format, GrB_STORAGE_ORIENTATION_HINT); + if (matrix->nrows == matrix->ncols) + matrix->block_type = CELL; + else + matrix->block_type = matrix->nrows > matrix->ncols ? VEC_VERT : VEC_HORIZ; } Matrix matrix_from_base(GrB_Matrix matrix) { From 68658939999e6eb1b25801e1b47627fb85f11aad Mon Sep 17 00:00:00 2001 From: Homka122 Date: Sat, 7 Jun 2025 10:03:02 +0300 Subject: [PATCH 093/122] Fix: assert condition in rsub block --- experimental/algorithm/LAGraph_CFL_reachability_advanced.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/experimental/algorithm/LAGraph_CFL_reachability_advanced.c b/experimental/algorithm/LAGraph_CFL_reachability_advanced.c index d2caf0936c..d0c43cb82b 100644 --- a/experimental/algorithm/LAGraph_CFL_reachability_advanced.c +++ b/experimental/algorithm/LAGraph_CFL_reachability_advanced.c @@ -911,7 +911,7 @@ GrB_Info matrix_rsub_lazy(Matrix *output, Matrix *mask) { } GrB_Info matrix_rsub_block(Matrix *output, Matrix *mask) { - if ((output->block_type == CELL && output->block_type != CELL) || + if ((output->block_type == CELL && mask->block_type != CELL) || (output->block_type != CELL && mask->block_type == CELL)) { fprintf(stderr, "Don't support rsub operation between cell and vector"); exit(-1); From 3bf3ba409345f264427a256bef32ef76be9f33ae Mon Sep 17 00:00:00 2001 From: Homka122 Date: Sat, 7 Jun 2025 10:23:43 +0300 Subject: [PATCH 094/122] Feat: check result of rsub methods --- .../LAGraph_CFL_reachability_advanced.c | 60 ++++++++++--------- 1 file changed, 32 insertions(+), 28 deletions(-) diff --git a/experimental/algorithm/LAGraph_CFL_reachability_advanced.c b/experimental/algorithm/LAGraph_CFL_reachability_advanced.c index d0c43cb82b..2d03472d1b 100644 --- a/experimental/algorithm/LAGraph_CFL_reachability_advanced.c +++ b/experimental/algorithm/LAGraph_CFL_reachability_advanced.c @@ -232,17 +232,17 @@ void matrix_free(Matrix *matrix) { TRY(GrB_free(&matrix->base)); } -void matrix_to_format(Matrix *matrix, int32_t format, bool is_both) { +GrB_Info matrix_to_format(Matrix *matrix, int32_t format, bool is_both) { // Matrix contain both formats so just switch base matrix if (matrix->is_both) { matrix->base = format == GrB_ROWMAJOR ? matrix->base_row : matrix->base_col; matrix->format = format; - return; + return GrB_SUCCESS; } // No changes required if (matrix->format == format) { - return; + return GrB_SUCCESS; } // Matrix contain just one matrix and format is not same @@ -264,7 +264,7 @@ void matrix_to_format(Matrix *matrix, int32_t format, bool is_both) { matrix->base = format == GrB_ROWMAJOR ? matrix->base_row : matrix->base_col; format == GrB_ROWMAJOR ? TO_ROW(matrix->base) : TO_COL(matrix->base); matrix->format = format; - return; + return GrB_SUCCESS; } GrB_Info matrix_clear(Matrix *A) { @@ -298,33 +298,35 @@ GrB_Info matrix_clear_empty(Matrix *A) { return matrix_clear_format(A); } -void block_matrix_hyper_rotate_i(Matrix *matrix, enum Matrix_block format) { +GrB_Info block_matrix_hyper_rotate_i(Matrix *matrix, enum Matrix_block format) { if (matrix->is_lazy) { for (size_t i = 0; i < matrix->base_matrices_count; i++) { - block_matrix_hyper_rotate_i(&matrix->base_matrices[i], format); + TRY(block_matrix_hyper_rotate_i(&matrix->base_matrices[i], format)); } matrix_update(matrix); - return; + return GrB_SUCCESS; } if (matrix->block_type == CELL) { - return; + return GrB_SUCCESS; } if (matrix->block_type == format) { - return; + return GrB_SUCCESS; } GrB_Scalar scalar_true; - GrB_Scalar_new(&scalar_true, GrB_BOOL); - GrB_Scalar_setElement_BOOL(scalar_true, true); + TRY(GrB_Scalar_new(&scalar_true, GrB_BOOL)); + TRY(GrB_Scalar_setElement_BOOL(scalar_true, true)); if (matrix->block_type == VEC_VERT) { + // fix: change to lagraph malloc GrB_Index *nrows = malloc(matrix->nvals * sizeof(GrB_Index)); GrB_Index *ncols = malloc(matrix->nvals * sizeof(GrB_Index)); - GrB_Matrix_extractTuples_BOOL(nrows, ncols, NULL, &matrix->nvals, matrix->base); + TRY(GrB_Matrix_extractTuples_BOOL(nrows, ncols, NULL, &matrix->nvals, + matrix->base)); for (size_t i = 0; i < matrix->nvals; i++) { ncols[i] = ncols[i] + nrows[i] / matrix->ncols * matrix->ncols; @@ -339,14 +341,15 @@ void block_matrix_hyper_rotate_i(Matrix *matrix, enum Matrix_block format) { free(nrows); free(ncols); GrB_free(&scalar_true); - return; + return GrB_SUCCESS; } if (matrix->block_type == VEC_HORIZ) { GrB_Index *nrows = malloc(matrix->nvals * sizeof(GrB_Index)); GrB_Index *ncols = malloc(matrix->nvals * sizeof(GrB_Index)); - GrB_Matrix_extractTuples_BOOL(nrows, ncols, NULL, &matrix->nvals, matrix->base); + TRY(GrB_Matrix_extractTuples_BOOL(nrows, ncols, NULL, &matrix->nvals, + matrix->base)); for (size_t i = 0; i < matrix->nvals; i++) { nrows[i] = nrows[i] + ncols[i] / matrix->nrows * matrix->nrows; @@ -361,7 +364,7 @@ void block_matrix_hyper_rotate_i(Matrix *matrix, enum Matrix_block format) { free(nrows); free(ncols); GrB_free(&scalar_true); - return; + return GrB_SUCCESS; } } @@ -517,16 +520,17 @@ GrB_Info matrix_combine_lazy(Matrix *A, size_t threshold) { Matrix *new_matrices = malloc(sizeof(Matrix) * 50); size_t new_size = 0; - matrix_sort_lazy(A, false); + TRY(matrix_sort_lazy(A, false)); for (size_t i = 0; i < A->base_matrices_count; i++) { - if (A->base_matrices[i].nvals <= threshold && new_size > 0) { - matrix_wise_empty(&new_matrices[new_size - 1], &new_matrices[new_size - 1], - &A->base_matrices[i], false); - GrB_free(&A->base_matrices[i].base); - } else { + if (new_size == 0 || A->base_matrices[i].nvals > threshold) { new_matrices[new_size++] = A->base_matrices[i]; + continue; } + + TRY(matrix_wise_empty(&new_matrices[new_size - 1], &new_matrices[new_size - 1], + &A->base_matrices[i], false)); + GrB_free(&A->base_matrices[i].base); } A->base_matrices = new_matrices; @@ -867,8 +871,8 @@ GrB_Info matrix_rsub(Matrix *output, Matrix *mask) { GrB_Info matrix_rsub_format(Matrix *output, Matrix *mask) { Matrix *larger_matrix = output->nvals > mask->nvals ? output : mask; - matrix_to_format(output, larger_matrix->format, false); - matrix_to_format(mask, larger_matrix->format, false); + TRY(matrix_to_format(output, larger_matrix->format, false)); + TRY(matrix_to_format(mask, larger_matrix->format, false)); if (!output->is_both) { return matrix_rsub(output, mask); @@ -900,11 +904,11 @@ GrB_Info matrix_rsub_lazy(Matrix *output, Matrix *mask) { return matrix_rsub_empty(output, mask); } - matrix_combine_lazy(mask, output->nvals); - matrix_sort_lazy(mask, true); + TRY(matrix_combine_lazy(mask, output->nvals)); + TRY(matrix_sort_lazy(mask, true)); for (size_t i = 0; i < mask->base_matrices_count; i++) { - matrix_rsub_empty(output, &mask->base_matrices[i]); + TRY(matrix_rsub_empty(output, &mask->base_matrices[i])); } return GrB_SUCCESS; @@ -921,7 +925,7 @@ GrB_Info matrix_rsub_block(Matrix *output, Matrix *mask) { return matrix_rsub_lazy(output, mask); } - block_matrix_hyper_rotate_i(output, mask->block_type); + TRY(block_matrix_hyper_rotate_i(output, mask->block_type)); return matrix_rsub_lazy(output, mask); } @@ -1391,7 +1395,7 @@ GrB_Info LAGraph_CFL_reachability_adv( // printf("RSUB iteration: %ld i: %ld\n", iteration, i); // matrix_print_lazy(A); // matrix_print_lazy(C); - rsub(C, A); + TRY(rsub(C, A)); // matrix_print_lazy(C); } TIMER_STOP("WISE 3 (MASK)", &rsubt); From 595a2cb34ecb3b844164b3103d1bc641f26229cd Mon Sep 17 00:00:00 2001 From: Homka122 Date: Mon, 13 Oct 2025 20:47:23 +0300 Subject: [PATCH 095/122] Fix: fix order of flags --- .../algorithm/LAGraph_CFL_reachability_advanced.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/experimental/algorithm/LAGraph_CFL_reachability_advanced.c b/experimental/algorithm/LAGraph_CFL_reachability_advanced.c index 2d03472d1b..cc17f89a67 100644 --- a/experimental/algorithm/LAGraph_CFL_reachability_advanced.c +++ b/experimental/algorithm/LAGraph_CFL_reachability_advanced.c @@ -1228,19 +1228,23 @@ GrB_Info LAGraph_CFL_reachability_adv( mxm = matrix_mxm_lazy; wise = matrix_wise_lazy; rsub = matrix_rsub_lazy; - } else if (optimizations & OPT_EMPTY) { + } + if (optimizations & OPT_EMPTY) { mxm = matrix_mxm_empty; wise = matrix_wise_empty; rsub = matrix_rsub_empty; - } else if (optimizations & OPT_FORMAT) { + } + if (optimizations & OPT_FORMAT) { mxm = matrix_mxm_format; wise = matrix_wise_format; rsub = matrix_rsub_format; - } else if (optimizations & OPT_BLOCK) { + } + if (optimizations & OPT_BLOCK) { mxm = matrix_mxm_block; wise = matrix_wise_block; rsub = matrix_rsub_block; - } else { + } + if (optimizations == 0x0) { mxm = matrix_mxm; wise = matrix_wise; rsub = matrix_rsub; From af498f81940ce2253af4e815e60dc3281555a8c6 Mon Sep 17 00:00:00 2001 From: Homka122 Date: Mon, 13 Oct 2025 20:58:52 +0300 Subject: [PATCH 096/122] Refactor: delete unused T matrix from prev algo --- .../algorithm/LAGraph_CFL_reachability_advanced.c | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/experimental/algorithm/LAGraph_CFL_reachability_advanced.c b/experimental/algorithm/LAGraph_CFL_reachability_advanced.c index cc17f89a67..3b5868fe60 100644 --- a/experimental/algorithm/LAGraph_CFL_reachability_advanced.c +++ b/experimental/algorithm/LAGraph_CFL_reachability_advanced.c @@ -20,14 +20,14 @@ LAGraph_Free((void **)&nnzs, msg); \ GrB_free(&true_scalar); \ GrB_free(&identity_matrix); \ - LAGraph_Free((void **)&T, msg); \ LAGraph_Free((void **)&indexes, msg); \ } #define LG_FREE_ALL \ { \ for (size_t i = 0; i < symbols_amount; i++) { \ - GrB_free(&T[i]); \ + /* TODO: delete it and free actual matrices */ \ + /* GrB_free(&T[i]); */ \ } \ \ LG_FREE_WORK; \ @@ -1072,7 +1072,6 @@ GrB_Info LAGraph_CFL_reachability_adv( GrB_Scalar_new(&true_scalar, GrB_BOOL); GrB_Scalar_setElement_BOOL(true_scalar, true); - LG_TRY(LAGraph_Calloc((void **)&T, symbols_amount, sizeof(GrB_Matrix), msg)); LG_TRY(LAGraph_Calloc((void **)&delta_matrices, symbols_amount, sizeof(Matrix), msg)); LG_TRY(LAGraph_Calloc((void **)&matrices, symbols_amount, sizeof(Matrix), msg)); LG_TRY(LAGraph_Calloc((void **)&temp_matrices, symbols_amount, sizeof(Matrix), msg)); @@ -1114,8 +1113,6 @@ GrB_Info LAGraph_CFL_reachability_adv( for (size_t i = 0; i < symbols_amount; i++) { GrB_Matrix matrix; - GRB_TRY(GrB_Matrix_new(&T[i], GrB_BOOL, n, n)); - GrB_Index nrows; GrB_Matrix_nrows(&nrows, adj_matrices[i]); GrB_Index ncols; @@ -1259,7 +1256,7 @@ GrB_Info LAGraph_CFL_reachability_adv( GRB_TRY(wise(nonterm_matrix, nonterm_matrix, term_matrix, true)); #ifdef DEBUG_CFL_REACHBILITY - GxB_Matrix_iso(&iso_flag, T[term_rule.nonterm]); + // GxB_Matrix_iso(&iso_flag, T[term_rule.nonterm]); printf("[TERM] eWiseUnion: NONTERM: %d (ISO: %d)\n", term_rule.nonterm, iso_flag); #endif } @@ -1280,7 +1277,7 @@ GrB_Info LAGraph_CFL_reachability_adv( wise(nonterm_matrix, nonterm_matrix, &iden, true); #ifdef DEBUG_CFL_REACHBILITY - GxB_Matrix_iso(&iso_flag, T[eps_rule.nonterm]); + // GxB_Matrix_iso(&iso_flag, T[eps_rule.nonterm]); printf("[EPS] eWiseUnion: NONTERM: %d (ISO: %d)\n", eps_rule.nonterm, iso_flag); #endif } @@ -1418,7 +1415,7 @@ GrB_Info LAGraph_CFL_reachability_adv( } #ifdef DEBUG_CFL_REACHBILITY - GxB_Matrix_iso(&iso_flag, T[bin_rule.nonterm]); + // GxB_Matrix_iso(&iso_flag, T[bin_rule.nonterm]); printf("[TERM1 TERM2] MULTIPLY, S: %d, A: %d, B: %d, " "I: %ld (ISO: %d)\n", bin_rule.nonterm, bin_rule.prod_A, bin_rule.prod_B, i, iso_flag); @@ -1433,7 +1430,7 @@ GrB_Info LAGraph_CFL_reachability_adv( #ifdef DEBUG_CFL_REACHBILITY for (int32_t i = 0; i < nonterms_count; i++) { printf("MATRIX WITH INDEX %d:\n", i); - GxB_print(T[i], GxB_SUMMARY); + // GxB_print(T[i], GxB_SUMMARY); } #endif From 2b8337bf53b8a68ae207c76e5e63caa86b62af25 Mon Sep 17 00:00:00 2001 From: Homka122 Date: Wed, 15 Oct 2025 04:27:10 +0300 Subject: [PATCH 097/122] Refactor: delete whitespaces after if statement --- .../algorithm/LAGraph_CFL_reachability_advanced.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/experimental/algorithm/LAGraph_CFL_reachability_advanced.c b/experimental/algorithm/LAGraph_CFL_reachability_advanced.c index 3b5868fe60..679492392e 100644 --- a/experimental/algorithm/LAGraph_CFL_reachability_advanced.c +++ b/experimental/algorithm/LAGraph_CFL_reachability_advanced.c @@ -1225,22 +1225,22 @@ GrB_Info LAGraph_CFL_reachability_adv( mxm = matrix_mxm_lazy; wise = matrix_wise_lazy; rsub = matrix_rsub_lazy; - } + } if (optimizations & OPT_EMPTY) { mxm = matrix_mxm_empty; wise = matrix_wise_empty; rsub = matrix_rsub_empty; - } + } if (optimizations & OPT_FORMAT) { mxm = matrix_mxm_format; wise = matrix_wise_format; rsub = matrix_rsub_format; - } + } if (optimizations & OPT_BLOCK) { mxm = matrix_mxm_block; wise = matrix_wise_block; rsub = matrix_rsub_block; - } + } if (optimizations == 0x0) { mxm = matrix_mxm; wise = matrix_wise; From 8f5759180461f876ed8776af77bde079eed262ec Mon Sep 17 00:00:00 2001 From: Homka122 Date: Wed, 15 Oct 2025 04:32:22 +0300 Subject: [PATCH 098/122] Feat: move functions with optimized matrices in seperate file --- .../LAGraph_CFL_optimized_matrix_opt.c | 110 +++++++++++ .../LAGraph_CFL_reachability_advanced.c | 174 +++++------------- include/LAGraphX.h | 38 +++- 3 files changed, 188 insertions(+), 134 deletions(-) create mode 100644 experimental/algorithm/LAGraph_CFL_optimized_matrix_opt.c diff --git a/experimental/algorithm/LAGraph_CFL_optimized_matrix_opt.c b/experimental/algorithm/LAGraph_CFL_optimized_matrix_opt.c new file mode 100644 index 0000000000..6d93b1779a --- /dev/null +++ b/experimental/algorithm/LAGraph_CFL_optimized_matrix_opt.c @@ -0,0 +1,110 @@ +//------------------------------------------------------------------------------ +// LAGraph_CFL_optimized_matrix_opt.c: Implementation of operations for +// Optimized Context-Free Language Reachability Matrix-Based Algorithm +//------------------------------------------------------------------------------ +// +// LAGraph, (c) 2019-2025 by The LAGraph Contributors, All Rights Reserved. +// SPDX-License-Identifier: BSD-2-Clause + +// Contributed by Vlasenco Daniel, Ilhom Kombaev, Semyon Grigoriev, St. Petersburg State +// University. + +//------------------------------------------------------------------------------ + +// Code is an implementation of optimized matrix operations for CFL_reachability +// algorithms, described in the following paper: +// * Ilia Muravev, "Optimization of the Context-Free Language Reachability Matrix-Based +// Algorithm" and based on the python implementation from: +// https://github.com/FormalLanguageConstrainedPathQuerying/CFPQ_PyAlgo/tree/murav/optimize-matrix + +#include "LG_internal.h" +#include + +#define OPT_EMPTY (1 << 0) +#define OPT_FORMAT (1 << 1) +#define OPT_LAZY (1 << 2) +#define OPT_BLOCK (1 << 3) + +typedef CFL_Matrix Matrix; +typedef enum CFL_Matrix_block Matrix_block; + +void CFL_matrix_update(Matrix *matrix) { + if (!matrix->is_lazy) { + GrB_Matrix_nvals(&matrix->nvals, matrix->base); + } else { + size_t new_nnz = 0; + for (size_t i = 0; i < matrix->base_matrices_count; i++) { + GrB_Matrix_nvals(&matrix->base_matrices[i].nvals, + matrix->base_matrices[i].base); + new_nnz += matrix->base_matrices[i].nvals; + } + + matrix->nvals = new_nnz; + } + + if (!matrix->is_lazy) { + GrB_Matrix_nrows(&matrix->nrows, matrix->base); + GrB_Matrix_ncols(&matrix->ncols, matrix->base); + } else { + GrB_Matrix_nrows(&matrix->nrows, matrix->base_matrices[0].base); + GrB_Matrix_ncols(&matrix->ncols, matrix->base_matrices[0].base); + } + + if (matrix->nrows == matrix->ncols) + matrix->block_type = CELL; + else + matrix->block_type = matrix->nrows > matrix->ncols ? VEC_VERT : VEC_HORIZ; +} + +// Create optimizied matrix from base GrB_Matrix +Matrix CFL_matrix_from_base(GrB_Matrix matrix) { + Matrix result; + + result.base = matrix; + result.nvals = 0; // We will get actual info in update functoin + result.nrows = 0; + result.ncols = 0; + + // Format optimization fields + result.base_row = matrix; + result.base_col = NULL; + result.format = GrB_ROWMAJOR; + result.is_both = false; + + // Lazy addition optimization fields + result.is_lazy = false; + result.base_matrices = malloc(sizeof(CFL_Matrix) * 40); // TODO: dynamic size + result.base_matrices_count = 0; + + // Block optimization fields + result.block_type = CELL; + + CFL_matrix_update(&result); + return result; +} + +Matrix CFL_matrix_from_base_lazy(GrB_Matrix matrix) { + Matrix result = CFL_matrix_from_base(matrix); + + Matrix lazy_result = CFL_matrix_from_base(matrix); + lazy_result.is_lazy = true; + lazy_result.base_matrices[0] = result; + lazy_result.base_matrices_count = 1; + CFL_matrix_update(&lazy_result); + + return lazy_result; +} + +Matrix CFL_matrix_create(GrB_Index nrows, GrB_Index ncols) { + GrB_Matrix _result; + GrB_Matrix_new(&_result, GrB_BOOL, nrows, ncols); + Matrix result = CFL_matrix_from_base(_result); + + return result; +} + +// TODO: free all base_matrices, free format matrices +void CFL_matrix_free(Matrix *matrix) { + free(matrix->base_matrices); + GrB_free(&matrix->base); +} \ No newline at end of file diff --git a/experimental/algorithm/LAGraph_CFL_reachability_advanced.c b/experimental/algorithm/LAGraph_CFL_reachability_advanced.c index 679492392e..2b28807629 100644 --- a/experimental/algorithm/LAGraph_CFL_reachability_advanced.c +++ b/experimental/algorithm/LAGraph_CFL_reachability_advanced.c @@ -144,93 +144,8 @@ } \ } -enum Matrix_block { CELL, VEC_HORIZ, VEC_VERT }; - -typedef struct Matrix { - GrB_Matrix base; - GrB_Matrix base_row; - GrB_Matrix base_col; - struct Matrix *base_matrices; - size_t base_matrices_count; - GrB_Index nvals; - GrB_Index nrows; - GrB_Index ncols; - int32_t format; - enum Matrix_block block_type; - bool is_both; - bool is_lazy; -} Matrix; - -void matrix_update(Matrix *matrix) { - if (!matrix->is_lazy) { - TRY(GrB_Matrix_nvals(&matrix->nvals, matrix->base)); - } else { - size_t new_nnz = 0; - for (size_t i = 0; i < matrix->base_matrices_count; i++) { - TRY(GrB_Matrix_nvals(&matrix->base_matrices[i].nvals, - matrix->base_matrices[i].base)); - new_nnz += matrix->base_matrices[i].nvals; - } - - matrix->nvals = new_nnz; - } - - if (!matrix->is_lazy) { - TRY(GrB_Matrix_nrows(&matrix->nrows, matrix->base)); - TRY(GrB_Matrix_ncols(&matrix->ncols, matrix->base)); - } else { - TRY(GrB_Matrix_nrows(&matrix->nrows, matrix->base_matrices[0].base)); - TRY(GrB_Matrix_ncols(&matrix->ncols, matrix->base_matrices[0].base)); - } - - if (matrix->nrows == matrix->ncols) - matrix->block_type = CELL; - else - matrix->block_type = matrix->nrows > matrix->ncols ? VEC_VERT : VEC_HORIZ; -} - -Matrix matrix_from_base(GrB_Matrix matrix) { - Matrix result; - result.base = matrix; - result.base_row = matrix; - result.base_col = NULL; - result.base_matrices = malloc(sizeof(Matrix) * 40); - result.base_matrices_count = 0; - result.nvals = 0; - result.nrows = 0; - result.ncols = 0; - result.block_type = CELL; - result.format = GrB_ROWMAJOR; - result.is_both = false; - result.is_lazy = false; - matrix_update(&result); - return result; -} - -Matrix matrix_from_base_lazy(GrB_Matrix matrix) { - Matrix result = matrix_from_base(matrix); - - Matrix lazy_result = matrix_from_base(matrix); - lazy_result.is_lazy = true; - lazy_result.base_matrices[0] = result; - lazy_result.base_matrices_count = 1; - matrix_update(&lazy_result); - - return lazy_result; -} - -Matrix matrix_create(GrB_Index nrows, GrB_Index ncols) { - GrB_Matrix _result; - TRY(GrB_Matrix_new(&_result, GrB_BOOL, nrows, ncols)); - Matrix result = matrix_from_base(_result); - - return result; -} - -void matrix_free(Matrix *matrix) { - free(matrix->base_matrices); - TRY(GrB_free(&matrix->base)); -} +typedef CFL_Matrix Matrix; +typedef enum CFL_Matrix_block Matrix_block; GrB_Info matrix_to_format(Matrix *matrix, int32_t format, bool is_both) { // Matrix contain both formats so just switch base matrix @@ -270,7 +185,7 @@ GrB_Info matrix_to_format(Matrix *matrix, int32_t format, bool is_both) { GrB_Info matrix_clear(Matrix *A) { GrB_Info result = GrB_Matrix_clear(A->base); TRY(result); - matrix_update(A); + CFL_matrix_update(A); return result; } @@ -298,13 +213,13 @@ GrB_Info matrix_clear_empty(Matrix *A) { return matrix_clear_format(A); } -GrB_Info block_matrix_hyper_rotate_i(Matrix *matrix, enum Matrix_block format) { +GrB_Info block_matrix_hyper_rotate_i(Matrix *matrix, enum CFL_Matrix_block format) { if (matrix->is_lazy) { for (size_t i = 0; i < matrix->base_matrices_count; i++) { TRY(block_matrix_hyper_rotate_i(&matrix->base_matrices[i], format)); } - matrix_update(matrix); + CFL_matrix_update(matrix); return GrB_SUCCESS; } @@ -336,8 +251,9 @@ GrB_Info block_matrix_hyper_rotate_i(Matrix *matrix, enum Matrix_block format) { GrB_Matrix new; TRY(GrB_Matrix_new(&new, GrB_BOOL, matrix->ncols, matrix->nrows)); TRY(GxB_Matrix_build_Scalar(new, nrows, ncols, scalar_true, matrix->nvals)); - matrix_free(matrix); - *matrix = matrix->is_lazy ? matrix_from_base_lazy(new) : matrix_from_base(new); + CFL_matrix_free(matrix); + *matrix = + matrix->is_lazy ? CFL_matrix_from_base_lazy(new) : CFL_matrix_from_base(new); free(nrows); free(ncols); GrB_free(&scalar_true); @@ -359,8 +275,9 @@ GrB_Info block_matrix_hyper_rotate_i(Matrix *matrix, enum Matrix_block format) { GrB_Matrix new; TRY(GrB_Matrix_new(&new, GrB_BOOL, matrix->ncols, matrix->nrows)); TRY(GxB_Matrix_build_Scalar(new, nrows, ncols, scalar_true, matrix->nvals)); - matrix_free(matrix); - *matrix = matrix->is_lazy ? matrix_from_base_lazy(new) : matrix_from_base(new); + CFL_matrix_free(matrix); + *matrix = + matrix->is_lazy ? CFL_matrix_from_base_lazy(new) : CFL_matrix_from_base(new); free(nrows); free(ncols); GrB_free(&scalar_true); @@ -429,7 +346,7 @@ void block_matrix_reduce(Matrix *matrix, Matrix *input) { } GxB_Matrix_build_Scalar(matrix->base, rows, cols, scalar_true, input->nvals); - matrix_update(matrix); + CFL_matrix_update(matrix); free(rows); free(cols); @@ -444,7 +361,7 @@ void block_matrix_repeat_into_vector(Matrix *matrix, Matrix *input, } GxB_Matrix_concat(matrix->base, tiles, block_count, 1, GrB_NULL); - matrix_update(matrix); + CFL_matrix_update(matrix); } GrB_Info matrix_dup(Matrix *output, Matrix *input) { @@ -455,7 +372,7 @@ GrB_Info matrix_dup(Matrix *output, Matrix *input) { GrB_Info result = GrB_Matrix_apply(output->base, GrB_NULL, GrB_NULL, GrB_IDENTITY_BOOL, input->base, GrB_NULL); TRY(result); - matrix_update(output); + CFL_matrix_update(output); return result; } @@ -535,7 +452,7 @@ GrB_Info matrix_combine_lazy(Matrix *A, size_t threshold) { A->base_matrices = new_matrices; A->base_matrices_count = new_size; - matrix_update(A); + CFL_matrix_update(A); return GrB_SUCCESS; } @@ -548,7 +465,7 @@ GrB_Info matrix_mxm(Matrix *output, Matrix *first, Matrix *second, bool accum, GrB_Info result = GrB_mxm(output->base, GrB_NULL, accum ? GxB_ANY_BOOL : GrB_NULL, GxB_ANY_PAIR_BOOL, left->base, right->base, GrB_NULL); IS_ISO(output->base, "MXM output"); - matrix_update(output); + CFL_matrix_update(output); return result; } @@ -603,7 +520,7 @@ GrB_Info matrix_mxm_lazy(Matrix *output, Matrix *first, Matrix *second, bool acc for (size_t i = 0; i < first->base_matrices_count; i++) { GrB_Matrix_new(&accs[i], GrB_BOOL, swap ? second->nrows : first->nrows, swap ? first->ncols : second->ncols); - acc_matrices[i] = matrix_from_base(accs[i]); + acc_matrices[i] = CFL_matrix_from_base(accs[i]); } for (size_t i = 0; i < first->base_matrices_count; i++) { @@ -623,7 +540,7 @@ GrB_Info matrix_mxm_lazy(Matrix *output, Matrix *first, Matrix *second, bool acc GrB_Matrix acc; GrB_Matrix_new(&acc, GrB_BOOL, swap ? second->nrows : first->nrows, swap ? first->ncols : second->ncols); - Matrix acc_matrix = matrix_from_base(acc); + Matrix acc_matrix = CFL_matrix_from_base(acc); for (size_t i = 0; i < first->base_matrices_count; i++) { matrix_wise_empty(&acc_matrix, &acc_matrix, &acc_matrices[i], false); @@ -652,11 +569,11 @@ GrB_Info matrix_mxm_block(Matrix *output, Matrix *first, Matrix *second, bool ac block_matrix_hyper_rotate_i(second, swap ? VEC_VERT : VEC_HORIZ); block_matrix_hyper_rotate_i(output, swap ? VEC_VERT : VEC_HORIZ); - Matrix temp = matrix_create(swap ? second->nrows : first->nrows, - swap ? first->ncols : second->ncols); + Matrix temp = CFL_matrix_create(swap ? second->nrows : first->nrows, + swap ? first->ncols : second->ncols); matrix_mxm_lazy(&temp, first, second, accum, swap); matrix_wise_block(output, output, &temp, false); - matrix_free(&temp); + CFL_matrix_free(&temp); return GrB_SUCCESS; } @@ -665,11 +582,11 @@ GrB_Info matrix_mxm_block(Matrix *output, Matrix *first, Matrix *second, bool ac block_matrix_hyper_rotate_i(first, swap ? VEC_HORIZ : VEC_VERT); block_matrix_hyper_rotate_i(output, swap ? VEC_HORIZ : VEC_VERT); - Matrix temp = matrix_create(swap ? second->nrows : first->nrows, - swap ? first->ncols : first->ncols); + Matrix temp = CFL_matrix_create(swap ? second->nrows : first->nrows, + swap ? first->ncols : first->ncols); matrix_mxm_lazy(&temp, first, second, accum, swap); matrix_wise_block(output, output, &temp, false); - matrix_free(&temp); + CFL_matrix_free(&temp); return GrB_SUCCESS; } @@ -677,14 +594,14 @@ GrB_Info matrix_mxm_block(Matrix *output, Matrix *first, Matrix *second, bool ac GrB_Index size = first->nrows > first->ncols ? first->nrows : first->ncols; GrB_Matrix _diag; GrB_Matrix_new(&_diag, GrB_BOOL, size, size); - Matrix diag = matrix_from_base(_diag); + Matrix diag = CFL_matrix_from_base(_diag); block_matrix_to_diag(&diag, second); - matrix_update(&diag); + CFL_matrix_update(&diag); block_matrix_hyper_rotate_i(first, swap ? VEC_VERT : VEC_HORIZ); block_matrix_hyper_rotate_i(output, swap ? VEC_VERT : VEC_HORIZ); - Matrix temp = matrix_create(first->nrows, diag.ncols); + Matrix temp = CFL_matrix_create(first->nrows, diag.ncols); matrix_mxm_lazy(&temp, first, &diag, false, swap); return matrix_wise_block(output, output, &temp, false); } @@ -697,7 +614,7 @@ GrB_Info matrix_wise(Matrix *output, Matrix *first, Matrix *second, bool accum) GrB_Info result = GrB_eWiseAdd(output->base, GrB_NULL, accum_op, GxB_ANY_BOOL, first->base, second->base, GrB_NULL); - matrix_update(output); + CFL_matrix_update(output); return result; } @@ -783,7 +700,7 @@ GrB_Info matrix_wise_lazy(Matrix *output, Matrix *first, Matrix *second, bool ac GrB_Matrix _other; GrB_Matrix_new(&_other, GrB_BOOL, output->nrows, output->ncols); - Matrix other = matrix_from_base(_other); + Matrix other = CFL_matrix_from_base(_other); matrix_dup_empty(&other, second); size_t other_nvals = other.nvals >= 10 ? other.nvals : 10; @@ -835,24 +752,24 @@ GrB_Info matrix_wise_block(Matrix *output, Matrix *first, Matrix *second, bool a // second is vector if (first->block_type == CELL) { - Matrix temp_reduced = matrix_create(first->nrows, first->ncols); + Matrix temp_reduced = CFL_matrix_create(first->nrows, first->ncols); block_matrix_reduce(&temp_reduced, second); GrB_Info info = matrix_wise_lazy(output, first, &temp_reduced, accum); - matrix_free(&temp_reduced); + CFL_matrix_free(&temp_reduced); return info; } // first is vector if (second->block_type == CELL) { // LG_SET_BURBLE(true); - Matrix temp_vector = matrix_create(first->nrows, first->ncols); + Matrix temp_vector = CFL_matrix_create(first->nrows, first->ncols); GrB_Index block_count = first->nrows > first->ncols ? first->nrows : first->ncols; block_matrix_repeat_into_vector(&temp_vector, second, block_count); block_matrix_hyper_rotate_i(&temp_vector, first->block_type); GrB_Info info = matrix_wise_lazy(output, first, &temp_vector, accum); - matrix_free(&temp_vector); + CFL_matrix_free(&temp_vector); return info; } @@ -865,7 +782,7 @@ GrB_Info matrix_rsub(Matrix *output, Matrix *mask) { GrB_Info result = GrB_eWiseAdd(output->base, mask->base, GrB_NULL, GxB_ANY_BOOL, output->base, output->base, GrB_DESC_RSC); - matrix_update(output); + CFL_matrix_update(output); return result; } @@ -934,14 +851,14 @@ void matrix_print_lazy(Matrix *A) { GxB_Print_Level pr = 1; if (!A->is_lazy) { - matrix_update(A); + CFL_matrix_update(A); GxB_print(A->base, pr); // printf("nnz: %ld\n", A->nvals); return; } if (A->base_matrices_count == 1) { - matrix_update(A); + CFL_matrix_update(A); // printf("nnz: %ld\n", A->nvals); GxB_print(A->base_matrices[0].base, pr); return; @@ -949,7 +866,7 @@ void matrix_print_lazy(Matrix *A) { GrB_Matrix _temp; GrB_Matrix_new(&_temp, GrB_BOOL, A->nrows, A->ncols); - Matrix temp = matrix_from_base(_temp); + Matrix temp = CFL_matrix_from_base(_temp); for (size_t i = 0; i < A->base_matrices_count; i++) { matrix_wise_empty(&temp, &temp, &A->base_matrices[i], false); } @@ -965,7 +882,7 @@ void print_graph_info(Matrix *matrices, size_t count) { for (size_t i = 0; i < count; i++) { Matrix *A = &matrices[i]; - matrix_update(A); + CFL_matrix_update(A); nnz += A->nvals; } @@ -1058,7 +975,6 @@ GrB_Info LAGraph_CFL_reachability_adv( int8_t optimizations // Optimizations flags ) { // Declare workspace and clear the msg string, if not NULL - GrB_Matrix *T; Matrix *delta_matrices; Matrix *matrices; Matrix *temp_matrices; @@ -1119,15 +1035,15 @@ GrB_Info LAGraph_CFL_reachability_adv( GrB_Matrix_ncols(&ncols, adj_matrices[i]); GrB_Matrix_dup(&delta_matrices[i].base, adj_matrices[i]); - delta_matrices[i] = matrix_from_base(delta_matrices[i].base); + delta_matrices[i] = CFL_matrix_from_base(delta_matrices[i].base); GRB_TRY(GrB_Matrix_new(&matrix, GrB_BOOL, nrows, ncols)); matrices[i] = ((optimizations & OPT_LAZY) || (optimizations & OPT_BLOCK)) - ? matrix_from_base_lazy(matrix) - : matrix_from_base(matrix); + ? CFL_matrix_from_base_lazy(matrix) + : CFL_matrix_from_base(matrix); GRB_TRY(GrB_Matrix_new(&matrix, GrB_BOOL, nrows, ncols)); - temp_matrices[i] = matrix_from_base(matrix); + temp_matrices[i] = CFL_matrix_from_base(matrix); } // Arrays for processing rules @@ -1266,7 +1182,7 @@ GrB_Info LAGraph_CFL_reachability_adv( GRB_TRY(GrB_Vector_assign_BOOL(v_diag, GrB_NULL, GrB_NULL, true, GrB_ALL, n, NULL)); GRB_TRY(GrB_Matrix_diag(&identity_matrix, v_diag, 0)); GRB_TRY(GrB_free(&v_diag)); - Matrix iden = matrix_from_base(identity_matrix); + Matrix iden = CFL_matrix_from_base(identity_matrix); // Rule [Variable -> eps] for (size_t i = 0; i < eps_rules_count; i++) { @@ -1406,7 +1322,7 @@ GrB_Info LAGraph_CFL_reachability_adv( size_t new_nnz = 0; for (size_t i = 0; i < symbols_amount; i++) { - matrix_update(&delta_matrices[i]); + CFL_matrix_update(&delta_matrices[i]); new_nnz += delta_matrices[i].nvals; } @@ -1441,7 +1357,7 @@ GrB_Info LAGraph_CFL_reachability_adv( // TODO: new method for getting acc from lazy matrix GrB_Matrix _acc; GrB_Matrix_new(&_acc, GrB_BOOL, matrices[i].nrows, matrices[i].ncols); - Matrix acc = matrix_from_base(_acc); + Matrix acc = CFL_matrix_from_base(_acc); matrix_sort_lazy(&matrices[i], false); for (size_t j = 0; j < matrices[i].base_matrices_count; j++) { diff --git a/include/LAGraphX.h b/include/LAGraphX.h index aaecb137c1..ca85338b68 100644 --- a/include/LAGraphX.h +++ b/include/LAGraphX.h @@ -1105,7 +1105,6 @@ GrB_Info LAGraph_CFL_reachability_adv // outputs[k]: (i, j) = true if and only if there is a path // from node i to node j whose edge labels form a word // derivable from the non-terminal 'k' of the specified CFG. - // Input const GrB_Matrix *adj_matrices, // Array of adjacency matrices representing the graph. // The length of this array is equal to the count of @@ -1115,14 +1114,43 @@ GrB_Info LAGraph_CFL_reachability_adv // is an edge between nodes i and j with the label of // the terminal corresponding to index 't' (where t is // in the range [0, terms_count - 1]). - - int32_t terms_count, // The total number of terminal symbols in the CFG. - int32_t nonterms_count, // The total number of non-terminal symbols in the CFG. + size_t symbols_amount, const LAGraph_rule_WCNF *rules, // The rules of the CFG. size_t rules_count, // The total number of rules in the CFG. - char *msg // Message string for error reporting. + char *msg, // Message string for error reporting. + int8_t optimizations // Optimizations flags ); + +enum CFL_Matrix_block { CELL, VEC_HORIZ, VEC_VERT }; + +// Struct for matrix for CFL algorithms with optimizations +typedef struct CFL_Matrix { + GrB_Matrix base; // Base GrB_Matrix from we create CFL_Matrix + int8_t optimizations; // Optimizations flags + // Fields of base matrix + GrB_Index nvals; + GrB_Index nrows; + GrB_Index ncols; + // Fields of format optimization + GrB_Matrix base_row; + GrB_Matrix base_col; + int32_t format; + bool is_both; + // Fields of lazy addition optimization + struct CFL_Matrix *base_matrices; + size_t base_matrices_count; + bool is_lazy; + // Fields of block optimization + enum CFL_Matrix_block block_type; +} CFL_Matrix; + +void CFL_matrix_update(CFL_Matrix *matrix); +CFL_Matrix CFL_matrix_from_base(GrB_Matrix matrix); +CFL_Matrix CFL_matrix_from_base_lazy(GrB_Matrix matrix); +CFL_Matrix CFL_matrix_create(GrB_Index nrows, GrB_Index ncols); +void CFL_matrix_free(CFL_Matrix *matrix); + //------------------------------------------------------------------------------ // a simple example of an algorithm //------------------------------------------------------------------------------ From b87ceadd1054aabf56cb1eedc7db677806c353b6 Mon Sep 17 00:00:00 2001 From: Homka122 Date: Wed, 15 Oct 2025 06:16:50 +0300 Subject: [PATCH 099/122] Refactor: move optimizations methods to seperate file --- .../LAGraph_CFL_optimized_matrix_opt.c | 877 ++++++++++++++++++ .../LAGraph_CFL_reachability_advanced.c | 813 +--------------- include/LAGraphX.h | 9 + 3 files changed, 897 insertions(+), 802 deletions(-) diff --git a/experimental/algorithm/LAGraph_CFL_optimized_matrix_opt.c b/experimental/algorithm/LAGraph_CFL_optimized_matrix_opt.c index 6d93b1779a..2dda2ba681 100644 --- a/experimental/algorithm/LAGraph_CFL_optimized_matrix_opt.c +++ b/experimental/algorithm/LAGraph_CFL_optimized_matrix_opt.c @@ -28,6 +28,360 @@ typedef CFL_Matrix Matrix; typedef enum CFL_Matrix_block Matrix_block; +#define TO_COL(matrix) GrB_set(matrix, GrB_COLMAJOR, GrB_STORAGE_ORIENTATION_HINT) +#define TO_ROW(matrix) GrB_set(matrix, GrB_ROWMAJOR, GrB_STORAGE_ORIENTATION_HINT) + +GrB_Info matrix_to_format(Matrix *matrix, int32_t format, bool is_both) { + // Matrix contain both formats so just switch base matrix + if (matrix->is_both) { + matrix->base = format == GrB_ROWMAJOR ? matrix->base_row : matrix->base_col; + matrix->format = format; + return GrB_SUCCESS; + } + + // No changes required + if (matrix->format == format) { + return GrB_SUCCESS; + } + + // Matrix contain just one matrix and format is not same + GrB_Matrix *new_matrix = + matrix->format == GrB_ROWMAJOR ? &matrix->base_col : &matrix->base_row; + GrB_Matrix *old_matrix = + matrix->format == GrB_ROWMAJOR ? &matrix->base_row : &matrix->base_col; + + if (is_both) { + GrB_Matrix_new(new_matrix, GrB_BOOL, matrix->nrows, matrix->ncols); + GrB_Matrix_assign(*new_matrix, GrB_NULL, GrB_NULL, *old_matrix, GrB_ALL, + matrix->nrows, GrB_ALL, matrix->ncols, GrB_NULL); + matrix->is_both = true; + } else { + *new_matrix = *old_matrix; + *old_matrix = NULL; + } + + matrix->base = format == GrB_ROWMAJOR ? matrix->base_row : matrix->base_col; + format == GrB_ROWMAJOR ? TO_ROW(matrix->base) : TO_COL(matrix->base); + matrix->format = format; + return GrB_SUCCESS; +} + +// clear methods + +GrB_Info matrix_clear(Matrix *A) { + GrB_Info result = GrB_Matrix_clear(A->base); + result; + CFL_matrix_update(A); + return result; +} + +GrB_Info matrix_clear_format(Matrix *A, int8_t optimizations) { + if (!(optimizations & OPT_FORMAT)) { + return matrix_clear(A); + } + + if (!A->is_both) { + return matrix_clear(A); + } + + matrix_to_format(A, GrB_ROWMAJOR, false); + GrB_Info result = matrix_clear(A); + + if (result < GrB_SUCCESS) { + return result; + } + + matrix_to_format(A, GrB_COLMAJOR, false); + return matrix_clear(A); +} + +GrB_Info matrix_clear_empty(Matrix *A, int8_t optimizations) { + if (!(optimizations & OPT_EMPTY)) { + return matrix_clear_format(A, optimizations); + } + + if (A->nvals == 0) { + return GrB_SUCCESS; + } + + return matrix_clear_format(A, optimizations); +} + +// duplicate methods + +GrB_Info matrix_dup(Matrix *output, Matrix *input) { + if (output == input) { + return GrB_SUCCESS; + } + + GrB_Info result = GrB_Matrix_apply(output->base, GrB_NULL, GrB_NULL, + GrB_IDENTITY_BOOL, input->base, GrB_NULL); + CFL_matrix_update(output); + + return result; +} + +GrB_Info matrix_dup_format(Matrix *output, Matrix *input, int8_t optimizations) { + if (!(optimizations & OPT_FORMAT)) { + return matrix_dup(output, input); + } + + if (!output->is_both) { + Matrix *larger = output->nvals > input->nvals ? output : input; + + matrix_to_format(output, larger->format, false); + matrix_to_format(input, larger->format, false); + + return matrix_dup(output, input); + } + + matrix_to_format(output, GrB_ROWMAJOR, false); + GrB_Info result = matrix_dup(output, input); + + if (result < GrB_SUCCESS) { + return result; + } + + matrix_to_format(output, GrB_COLMAJOR, false); + return matrix_dup(output, input); +} + +GrB_Info matrix_dup_empty(Matrix *output, Matrix *input, int8_t optimizations) { + if (!(optimizations & OPT_EMPTY)) { + return matrix_dup_format(output, input, optimizations); + } + + if (input->nvals == 0) { + return matrix_clear_empty(output, optimizations); + } + + return matrix_dup_format(output, input, optimizations); +} + +GrB_Info block_matrix_hyper_rotate_i(Matrix *matrix, enum CFL_Matrix_block format); + +GrB_Info matrix_dup_block(Matrix *output, Matrix *input, int8_t optimizations) { + if (!(optimizations & OPT_BLOCK)) { + return matrix_dup_empty(output, input, optimizations); + } + + if (output->block_type == CELL && input->block_type == CELL) { + return matrix_dup_empty(output, input, optimizations); + } + + block_matrix_hyper_rotate_i(input, output->block_type); + return matrix_dup_empty(output, input, optimizations); +} + +// block optimization specific methods + +GrB_Info block_matrix_hyper_rotate_i(Matrix *matrix, enum CFL_Matrix_block format) { + if (matrix->is_lazy) { + for (size_t i = 0; i < matrix->base_matrices_count; i++) { + block_matrix_hyper_rotate_i(&matrix->base_matrices[i], format); + } + + CFL_matrix_update(matrix); + return GrB_SUCCESS; + } + + if (matrix->block_type == CELL) { + return GrB_SUCCESS; + } + + if (matrix->block_type == format) { + return GrB_SUCCESS; + } + + GrB_Scalar scalar_true; + GrB_Scalar_new(&scalar_true, GrB_BOOL); + GrB_Scalar_setElement_BOOL(scalar_true, true); + + if (matrix->block_type == VEC_VERT) { + // fix: change to lagraph malloc + GrB_Index *nrows = malloc(matrix->nvals * sizeof(GrB_Index)); + GrB_Index *ncols = malloc(matrix->nvals * sizeof(GrB_Index)); + + GrB_Matrix_extractTuples_BOOL(nrows, ncols, NULL, &matrix->nvals, matrix->base); + + for (size_t i = 0; i < matrix->nvals; i++) { + ncols[i] = ncols[i] + nrows[i] / matrix->ncols * matrix->ncols; + nrows[i] = nrows[i] % matrix->ncols; + } + + GrB_Matrix new; + GrB_Matrix_new(&new, GrB_BOOL, matrix->ncols, matrix->nrows); + GxB_Matrix_build_Scalar(new, nrows, ncols, scalar_true, matrix->nvals); + CFL_matrix_free(matrix); + *matrix = + matrix->is_lazy ? CFL_matrix_from_base_lazy(new) : CFL_matrix_from_base(new); + free(nrows); + free(ncols); + GrB_free(&scalar_true); + return GrB_SUCCESS; + } + + if (matrix->block_type == VEC_HORIZ) { + GrB_Index *nrows = malloc(matrix->nvals * sizeof(GrB_Index)); + GrB_Index *ncols = malloc(matrix->nvals * sizeof(GrB_Index)); + + GrB_Matrix_extractTuples_BOOL(nrows, ncols, NULL, &matrix->nvals, matrix->base); + + for (size_t i = 0; i < matrix->nvals; i++) { + nrows[i] = nrows[i] + ncols[i] / matrix->nrows * matrix->nrows; + ncols[i] = ncols[i] % matrix->nrows; + } + + GrB_Matrix new; + GrB_Matrix_new(&new, GrB_BOOL, matrix->ncols, matrix->nrows); + GxB_Matrix_build_Scalar(new, nrows, ncols, scalar_true, matrix->nvals); + CFL_matrix_free(matrix); + *matrix = + matrix->is_lazy ? CFL_matrix_from_base_lazy(new) : CFL_matrix_from_base(new); + free(nrows); + free(ncols); + GrB_free(&scalar_true); + return GrB_SUCCESS; + } +} + +void block_matrix_to_diag(Matrix *diag, Matrix *input) { + if (input->block_type == CELL) { + exit(-1); + } + + GrB_Scalar scalar_true; + GrB_Scalar_new(&scalar_true, GrB_BOOL); + GrB_Scalar_setElement_BOOL(scalar_true, true); + + GrB_Index *rows = malloc(input->nvals * sizeof(GrB_Index)); + GrB_Index *cols = malloc(input->nvals * sizeof(GrB_Index)); + GrB_Matrix_extractTuples_BOOL(rows, cols, NULL, &input->nvals, input->base); + + if (input->block_type == VEC_HORIZ) { + for (size_t i = 0; i < input->nvals; i++) { + rows[i] = rows[i] + cols[i] / input->nrows * input->nrows; + } + } + + if (input->block_type == VEC_VERT) { + for (size_t i = 0; i < input->nvals; i++) { + cols[i] = cols[i] + rows[i] / input->ncols * input->ncols; + } + } + + GxB_Matrix_build_Scalar(diag->base, rows, cols, scalar_true, input->nvals); + + free(rows); + free(cols); + GrB_free(&scalar_true); +} + +void block_matrix_reduce(Matrix *matrix, Matrix *input, int8_t optimizations) { + if (input->block_type == CELL) { + matrix_dup_block(matrix, input, optimizations); + } + + GrB_Scalar scalar_true; + GrB_Scalar_new(&scalar_true, GrB_BOOL); + GrB_Scalar_setElement_BOOL(scalar_true, true); + + GrB_Index *rows = malloc(input->nvals * sizeof(GrB_Index)); + GrB_Index *cols = malloc(input->nvals * sizeof(GrB_Index)); + GrB_Matrix_extractTuples_BOOL(rows, cols, NULL, &input->nvals, input->base); + + if (input->block_type == VEC_VERT) { + for (size_t i = 0; i < input->nvals; i++) { + rows[i] = rows[i] % input->ncols; + } + } + + if (input->block_type == VEC_HORIZ) { + for (size_t i = 0; i < input->nvals; i++) { + cols[i] = cols[i] % input->nrows; + } + } + + GxB_Matrix_build_Scalar(matrix->base, rows, cols, scalar_true, input->nvals); + CFL_matrix_update(matrix); + + free(rows); + free(cols); + GrB_free(&scalar_true); +} + +void block_matrix_repeat_into_vector(Matrix *matrix, Matrix *input, + GrB_Index block_count) { + GrB_Matrix *tiles = malloc(block_count * sizeof(GrB_Matrix)); + for (size_t i = 0; i < block_count; i++) { + tiles[i] = input->base; + } + + GxB_Matrix_concat(matrix->base, tiles, block_count, 1, GrB_NULL); + CFL_matrix_update(matrix); +} + +// lazy optimization specific methods + +GrB_Info matrix_wise_empty(Matrix *output, Matrix *first, Matrix *second, bool accum, + int8_t optimizations); + +GrB_Info matrix_sort_lazy(Matrix *A, bool reverse) { + for (size_t i = 0; i < A->base_matrices_count; i++) { + for (size_t j = i + 1; j < A->base_matrices_count; j++) { + Matrix first = reverse ? A->base_matrices[i] : A->base_matrices[j]; + Matrix second = reverse ? A->base_matrices[j] : A->base_matrices[i]; + if (first.nvals < second.nvals) { + Matrix temp = A->base_matrices[i]; + A->base_matrices[i] = A->base_matrices[j]; + A->base_matrices[j] = temp; + } + } + } + + return GrB_SUCCESS; +} + +GrB_Matrix CFL_matrix_lazy_to_base(Matrix *matrix, int8_t optimizations) { + GrB_Matrix _acc; + GrB_Matrix_new(&_acc, GrB_BOOL, matrix->nrows, matrix->ncols); + Matrix acc = CFL_matrix_from_base(_acc); + + matrix_sort_lazy(matrix, false); + for (size_t j = 0; j < matrix->base_matrices_count; j++) { + CFL_wise(&acc, &acc, &matrix->base_matrices[j], false, optimizations); + GrB_free(&matrix->base_matrices[j].base); + } + + return acc.base; +} + +GrB_Info matrix_combine_lazy(Matrix *A, size_t threshold, int8_t optimizations) { + Matrix *new_matrices = malloc(sizeof(Matrix) * 50); + size_t new_size = 0; + + matrix_sort_lazy(A, false); + + for (size_t i = 0; i < A->base_matrices_count; i++) { + if (new_size == 0 || A->base_matrices[i].nvals > threshold) { + new_matrices[new_size++] = A->base_matrices[i]; + continue; + } + + matrix_wise_empty(&new_matrices[new_size - 1], &new_matrices[new_size - 1], + &A->base_matrices[i], false, optimizations); + GrB_free(&A->base_matrices[i].base); + } + + A->base_matrices = new_matrices; + A->base_matrices_count = new_size; + CFL_matrix_update(A); + + return GrB_SUCCESS; +} + +// create and update methods + void CFL_matrix_update(Matrix *matrix) { if (!matrix->is_lazy) { GrB_Matrix_nvals(&matrix->nvals, matrix->base); @@ -107,4 +461,527 @@ Matrix CFL_matrix_create(GrB_Index nrows, GrB_Index ncols) { void CFL_matrix_free(Matrix *matrix) { free(matrix->base_matrices); GrB_free(&matrix->base); +} + +// mxm operations + +GrB_Info matrix_mxm(Matrix *output, Matrix *first, Matrix *second, bool accum, + bool swap) { + Matrix *left = swap ? second : first; + Matrix *right = swap ? first : second; + + GrB_Info result = GrB_mxm(output->base, GrB_NULL, accum ? GxB_ANY_BOOL : GrB_NULL, + GxB_ANY_PAIR_BOOL, left->base, right->base, GrB_NULL); + // IS_ISO(output->base, "MXM output"); + CFL_matrix_update(output); + return result; +} + +GrB_Info matrix_mxm_format(Matrix *output, Matrix *first, Matrix *second, bool accum, + bool swap, int8_t optimizations) { + if (!(optimizations & OPT_FORMAT)) { + return matrix_mxm(output, first, second, accum, swap); + } + + GrB_Index left_nvals = swap ? second->nvals : first->nvals; + GrB_Index right_nvals = swap ? first->nvals : second->nvals; + + int32_t desired_orientation = left_nvals <= right_nvals ? GrB_ROWMAJOR : GrB_COLMAJOR; + + if (!first->is_both && first->format != desired_orientation && + !(first->nvals > second->nvals / 3.0)) { + GrB_Info result = matrix_mxm(output, first, second, accum, swap); + return result; + } + + matrix_to_format(first, desired_orientation, true); + matrix_to_format(second, desired_orientation, false); + matrix_to_format(output, desired_orientation, false); + GrB_Info result = matrix_mxm(output, first, second, accum, swap); + return result; +} + +GrB_Info matrix_mxm_empty(Matrix *output, Matrix *first, Matrix *second, bool accum, + bool swap, int8_t optimizations) { + if (!(optimizations & OPT_EMPTY)) { + return matrix_mxm_format(output, first, second, accum, swap, optimizations); + } + + if (first->nvals == 0 || second->nvals == 0) { + if (accum) { + return GrB_SUCCESS; + } + + if (output->nvals == 0) { + return GrB_SUCCESS; + } + + matrix_clear_empty(output, optimizations); + } + + return matrix_mxm_format(output, first, second, accum, swap, optimizations); +} + +GrB_Info matrix_mxm_lazy(Matrix *output, Matrix *first, Matrix *second, bool accum, + bool swap, int8_t optimizations) { + if (!(optimizations & OPT_LAZY)) { + return matrix_mxm_empty(output, first, second, accum, swap, optimizations); + } + + if (!first->is_lazy) { + return matrix_mxm_empty(output, first, second, accum, swap, optimizations); + } + + matrix_combine_lazy(first, second->nvals, optimizations); + matrix_sort_lazy(first, false); + + GrB_Matrix *accs = malloc(sizeof(GrB_Matrix) * first->base_matrices_count); + Matrix *acc_matrices = malloc(sizeof(Matrix) * first->base_matrices_count); + for (size_t i = 0; i < first->base_matrices_count; i++) { + GrB_Matrix_new(&accs[i], GrB_BOOL, swap ? second->nrows : first->nrows, + swap ? first->ncols : second->ncols); + acc_matrices[i] = CFL_matrix_from_base(accs[i]); + } + + for (size_t i = 0; i < first->base_matrices_count; i++) { + matrix_mxm_empty(&acc_matrices[i], &first->base_matrices[i], second, false, swap, + optimizations); + } + + for (size_t i = 0; i < first->base_matrices_count; i++) { + for (size_t j = i + 1; j < first->base_matrices_count; j++) { + if (acc_matrices[i].nvals > acc_matrices[j].nvals) { + Matrix temp = acc_matrices[i]; + acc_matrices[i] = acc_matrices[j]; + acc_matrices[j] = temp; + } + } + } + + GrB_Matrix acc; + GrB_Matrix_new(&acc, GrB_BOOL, swap ? second->nrows : first->nrows, + swap ? first->ncols : second->ncols); + Matrix acc_matrix = CFL_matrix_from_base(acc); + + for (size_t i = 0; i < first->base_matrices_count; i++) { + matrix_wise_empty(&acc_matrix, &acc_matrix, &acc_matrices[i], false, + optimizations); + GrB_free(&acc_matrices[i].base); + } + + if (accum) { + return matrix_wise_empty(output, output, &acc_matrix, false, optimizations); + } + + GrB_Info result = matrix_dup_block(output, &acc_matrix, optimizations); + GrB_free(&acc_matrix.base); + + return result; +} + +GrB_Info matrix_wise_block(Matrix *output, Matrix *first, Matrix *second, bool accum, + int8_t optimizations); + +GrB_Info matrix_mxm_block(Matrix *output, Matrix *first, Matrix *second, bool accum, + bool swap, int8_t optimizations) { + if (!(optimizations & OPT_BLOCK)) { + return matrix_mxm_lazy(output, first, second, accum, swap, optimizations); + } + + if (first->block_type == CELL && second->block_type == CELL) { + return matrix_mxm_lazy(output, first, second, accum, swap, optimizations); + } + + if (first->block_type == CELL) { + block_matrix_hyper_rotate_i(second, swap ? VEC_VERT : VEC_HORIZ); + block_matrix_hyper_rotate_i(output, swap ? VEC_VERT : VEC_HORIZ); + + Matrix temp = CFL_matrix_create(swap ? second->nrows : first->nrows, + swap ? first->ncols : second->ncols); + matrix_mxm_lazy(&temp, first, second, accum, swap, optimizations); + matrix_wise_block(output, output, &temp, false, optimizations); + CFL_matrix_free(&temp); + + return GrB_SUCCESS; + } + + if (second->block_type == CELL) { + block_matrix_hyper_rotate_i(first, swap ? VEC_HORIZ : VEC_VERT); + block_matrix_hyper_rotate_i(output, swap ? VEC_HORIZ : VEC_VERT); + + Matrix temp = CFL_matrix_create(swap ? second->nrows : first->nrows, + swap ? first->ncols : first->ncols); + matrix_mxm_lazy(&temp, first, second, accum, swap, optimizations); + matrix_wise_block(output, output, &temp, false, optimizations); + CFL_matrix_free(&temp); + + return GrB_SUCCESS; + } + + GrB_Index size = first->nrows > first->ncols ? first->nrows : first->ncols; + GrB_Matrix _diag; + GrB_Matrix_new(&_diag, GrB_BOOL, size, size); + Matrix diag = CFL_matrix_from_base(_diag); + block_matrix_to_diag(&diag, second); + CFL_matrix_update(&diag); + + block_matrix_hyper_rotate_i(first, swap ? VEC_VERT : VEC_HORIZ); + block_matrix_hyper_rotate_i(output, swap ? VEC_VERT : VEC_HORIZ); + + Matrix temp = CFL_matrix_create(first->nrows, diag.ncols); + matrix_mxm_lazy(&temp, first, &diag, false, swap, optimizations); + return matrix_wise_block(output, output, &temp, false, optimizations); +} + +// wise operations + +GrB_Info matrix_wise(Matrix *output, Matrix *first, Matrix *second, bool accum) { + GrB_BinaryOp accum_op = accum ? GxB_ANY_BOOL : GrB_NULL; + if (output == first) + accum_op = GrB_NULL; + + GrB_Info result = GrB_eWiseAdd(output->base, GrB_NULL, accum_op, GxB_ANY_BOOL, + first->base, second->base, GrB_NULL); + + CFL_matrix_update(output); + return result; +} + +GrB_Info matrix_wise_format(Matrix *output, Matrix *first, Matrix *second, bool accum, + int8_t optimizations) { + if (!(optimizations & OPT_FORMAT)) { + return matrix_wise(output, first, second, accum); + } + + if (!output->is_both) { + Matrix *larger = output->nvals > first->nvals ? output : first; + larger = larger->nvals > second->nvals ? larger : second; + + matrix_to_format(output, larger->format, false); + matrix_to_format(first, larger->format, false); + matrix_to_format(second, larger->format, false); + + return matrix_wise(output, first, second, accum); + } + + matrix_to_format(output, GrB_ROWMAJOR, false); + matrix_to_format(first, output->format, false); + matrix_to_format(second, output->format, false); + GrB_Info result = matrix_wise(output, first, second, accum); + + if (result < GrB_SUCCESS) { + return result; + } + + matrix_to_format(output, GrB_COLMAJOR, false); + matrix_to_format(first, output->format, false); + matrix_to_format(second, output->format, false); + return matrix_wise(output, first, second, accum); +} + +GrB_Info matrix_wise_empty(Matrix *output, Matrix *first, Matrix *second, bool accum, + int8_t optimizations) { + if (!(optimizations & OPT_EMPTY)) { + return matrix_wise_format(output, first, second, accum, optimizations); + } + + if (output == first) { + if (first->nvals == 0) { + return matrix_dup_empty(first, second, optimizations); + } + + if (second->nvals == 0) { + return GrB_SUCCESS; + } + + return matrix_wise_format(output, first, second, accum, optimizations); + } + + if (first->nvals == 0 && second->nvals == 0) { + if (accum || output->nvals == 0) { + return GrB_SUCCESS; + } + + return matrix_clear_empty(output, optimizations); + } + + if (first->nvals == 0) { + if (accum) { + return matrix_wise_empty(output, output, second, false, optimizations); + } + + return matrix_dup_empty(output, second, optimizations); + } + + if (second->nvals == 0) { + if (accum) { + return matrix_wise_empty(output, output, first, false, optimizations); + } + + return matrix_dup_empty(output, first, optimizations); + } + + return matrix_wise_format(output, first, second, accum, optimizations); +} + +GrB_Info matrix_wise_lazy(Matrix *output, Matrix *first, Matrix *second, bool accum, + int8_t optimizations) { + if (!(optimizations & OPT_LAZY)) { + return matrix_wise_empty(output, first, second, accum, optimizations); + } + + if (!first->is_lazy && !second->is_lazy) { + return matrix_wise_empty(output, first, second, accum, optimizations); + } + + if (!first->is_lazy && second->is_lazy) { + for (size_t i = 0; i < second->base_matrices_count; i++) { + matrix_wise_empty(output, first, &second->base_matrices[i], false, + optimizations); + } + + return GrB_SUCCESS; + } + + GrB_Matrix _other; + GrB_Matrix_new(&_other, GrB_BOOL, output->nrows, output->ncols); + Matrix other = CFL_matrix_from_base(_other); + matrix_dup_empty(&other, second, optimizations); + + size_t other_nvals = other.nvals >= 10 ? other.nvals : 10; + + while (true) { + bool found = false; + + for (size_t i = 0; i < first->base_matrices_count; i++) { + size_t self_nvals = + first->base_matrices[i].nvals >= 10 ? first->base_matrices[i].nvals : 10; + + if (other_nvals / 10 <= self_nvals && self_nvals <= other_nvals * 10) { + matrix_wise_empty(&other, &other, &first->base_matrices[i], accum, + optimizations); + GrB_free(&first->base_matrices[i].base); + for (size_t j = i + 1; j < first->base_matrices_count; j++) { + first->base_matrices[j - 1] = first->base_matrices[j]; + } + first->base_matrices_count--; + found = true; + break; + } + } + + if (found) { + continue; + } + + first->base_matrices[first->base_matrices_count++] = other; + break; + } + + return GrB_SUCCESS; +} + +// - Any operation on two hyper vectors is performed block-wise +// - When hyper vector is added in-place to a cell, then sum of hyper vector's blocks is +// added to a cell +// - When cell is added in-place to a hyper vector, then cell is added to each of +// hyper vector's blocks +GrB_Info matrix_wise_block(Matrix *output, Matrix *first, Matrix *second, bool accum, + int8_t optimizations) { + if (!(optimizations & OPT_BLOCK)) { + return matrix_wise_lazy(output, first, second, accum, optimizations); + } + + if (output != first) { + fprintf(stderr, "Matrix wise currently support only iadd operation"); + exit(-122); + } + + if (first->block_type == CELL && second->block_type == CELL) { + return matrix_wise_lazy(output, first, second, accum, optimizations); + } + + // second is vector + if (first->block_type == CELL) { + Matrix temp_reduced = CFL_matrix_create(first->nrows, first->ncols); + block_matrix_reduce(&temp_reduced, second, optimizations); + + GrB_Info info = + matrix_wise_lazy(output, first, &temp_reduced, accum, optimizations); + CFL_matrix_free(&temp_reduced); + return info; + } + + // first is vector + if (second->block_type == CELL) { + // LG_SET_BURBLE(true); + Matrix temp_vector = CFL_matrix_create(first->nrows, first->ncols); + GrB_Index block_count = first->nrows > first->ncols ? first->nrows : first->ncols; + block_matrix_repeat_into_vector(&temp_vector, second, block_count); + + block_matrix_hyper_rotate_i(&temp_vector, first->block_type); + GrB_Info info = + matrix_wise_lazy(output, first, &temp_vector, accum, optimizations); + CFL_matrix_free(&temp_vector); + return info; + } + + // both are vector + block_matrix_hyper_rotate_i(second, first->block_type); + return matrix_wise_lazy(output, first, second, accum, optimizations); +} + +// rsub methods + +GrB_Info matrix_rsub(Matrix *output, Matrix *mask) { + GrB_Info result = GrB_eWiseAdd(output->base, mask->base, GrB_NULL, GxB_ANY_BOOL, + output->base, output->base, GrB_DESC_RSC); + + CFL_matrix_update(output); + return result; +} + +GrB_Info matrix_rsub_format(Matrix *output, Matrix *mask, int8_t optimizations) { + if (!(optimizations & OPT_FORMAT)) { + return matrix_rsub(output, mask); + } + + Matrix *larger_matrix = output->nvals > mask->nvals ? output : mask; + matrix_to_format(output, larger_matrix->format, false); + matrix_to_format(mask, larger_matrix->format, false); + + if (!output->is_both) { + return matrix_rsub(output, mask); + } + + printf("LOOOOOO\n\n"); + + matrix_to_format(output, GrB_ROWMAJOR, false); + GrB_Info result = matrix_rsub(output, mask); + + if (result < GrB_SUCCESS) { + return result; + } + + matrix_to_format(output, GrB_COLMAJOR, false); + return matrix_rsub(output, mask); +} + +GrB_Info matrix_rsub_empty(Matrix *output, Matrix *mask, int8_t optimizations) { + if (!(optimizations & OPT_EMPTY)) { + return matrix_rsub_format(output, mask, optimizations); + } + + if (mask->nvals == 0 || output->nvals == 0) { + return GrB_SUCCESS; + } + + return matrix_rsub_format(output, mask, optimizations); +} + +GrB_Info matrix_rsub_lazy(Matrix *output, Matrix *mask, int8_t optimizations) { + if (!(optimizations & OPT_LAZY)) { + return matrix_rsub_empty(output, mask, optimizations); + } + + if (!mask->is_lazy) { + return matrix_rsub_empty(output, mask, optimizations); + } + + matrix_combine_lazy(mask, output->nvals, optimizations); + matrix_sort_lazy(mask, true); + + for (size_t i = 0; i < mask->base_matrices_count; i++) { + matrix_rsub_empty(output, &mask->base_matrices[i], optimizations); + } + + return GrB_SUCCESS; +} + +GrB_Info matrix_rsub_block(Matrix *output, Matrix *mask, int8_t optimizations) { + if (!(optimizations & OPT_BLOCK)) { + return matrix_rsub_lazy(output, mask, optimizations); + } + + if ((output->block_type == CELL && mask->block_type != CELL) || + (output->block_type != CELL && mask->block_type == CELL)) { + fprintf(stderr, "Don't support rsub operation between cell and vector"); + exit(-1); + } + + if (output->block_type == CELL) { + return matrix_rsub_lazy(output, mask, optimizations); + } + + block_matrix_hyper_rotate_i(output, mask->block_type); + return matrix_rsub_lazy(output, mask, optimizations); +} + +// utility methods + +// void matrix_print_lazy(Matrix *A) { +// return; +// GxB_Print_Level pr = 1; + +// if (!A->is_lazy) { +// CFL_matrix_update(A); +// GxB_print(A->base, pr); +// // printf("nnz: %ld\n", A->nvals); +// return; +// } + +// if (A->base_matrices_count == 1) { +// CFL_matrix_update(A); +// // printf("nnz: %ld\n", A->nvals); +// GxB_print(A->base_matrices[0].base, pr); +// return; +// } + +// GrB_Matrix _temp; +// GrB_Matrix_new(&_temp, GrB_BOOL, A->nrows, A->ncols); +// Matrix temp = CFL_matrix_from_base(_temp); +// for (size_t i = 0; i < A->base_matrices_count; i++) { +// matrix_wise_empty(&temp, &temp, &A->base_matrices[i], false, optimizations); +// } + +// A = &temp; +// GxB_print(A->base, pr); +// // printf("nnz: %ld\n", A->nvals); +// GrB_free(&_temp); +// } + +void print_graph_info(Matrix *matrices, size_t count) { + GrB_Index nnz = 0; + + for (size_t i = 0; i < count; i++) { + Matrix *A = &matrices[i]; + CFL_matrix_update(A); + nnz += A->nvals; + } + + printf("NNZ: %ld\n", nnz); +} + +// order of optimizations: block -> lazy -> empty -> format + +GrB_Info CFL_mxm(Matrix *output, Matrix *first, Matrix *second, bool accum, bool swap, + int8_t optimizations) { + return matrix_mxm_block(output, first, second, accum, swap, optimizations); +} + +GrB_Info CFL_wise(Matrix *output, Matrix *first, Matrix *second, bool accum, + int8_t optimizations) { + return matrix_wise_block(output, first, second, accum, optimizations); +} + +GrB_Info CFL_rsub(Matrix *output, Matrix *mask, int8_t optimizations) { + return matrix_rsub_block(output, mask, optimizations); +} + +GrB_Info CFL_dup(Matrix *output, Matrix *input, int8_t optimizations) { + return matrix_dup_block(output, input, optimizations); +} + +GrB_Info CFL_clear(Matrix *A, int8_t optimizations) { + return matrix_clear_empty(A, optimizations); } \ No newline at end of file diff --git a/experimental/algorithm/LAGraph_CFL_reachability_advanced.c b/experimental/algorithm/LAGraph_CFL_reachability_advanced.c index 2b28807629..2c4c3748aa 100644 --- a/experimental/algorithm/LAGraph_CFL_reachability_advanced.c +++ b/experimental/algorithm/LAGraph_CFL_reachability_advanced.c @@ -132,9 +132,6 @@ continue; \ } -#define TO_COL(matrix) GrB_set(matrix, GrB_COLMAJOR, GrB_STORAGE_ORIENTATION_HINT) -#define TO_ROW(matrix) GrB_set(matrix, GrB_ROWMAJOR, GrB_STORAGE_ORIENTATION_HINT) - #define TRY(GrB_method) \ { \ GrB_Info LG_GrB_Info = GrB_method; \ @@ -147,748 +144,6 @@ typedef CFL_Matrix Matrix; typedef enum CFL_Matrix_block Matrix_block; -GrB_Info matrix_to_format(Matrix *matrix, int32_t format, bool is_both) { - // Matrix contain both formats so just switch base matrix - if (matrix->is_both) { - matrix->base = format == GrB_ROWMAJOR ? matrix->base_row : matrix->base_col; - matrix->format = format; - return GrB_SUCCESS; - } - - // No changes required - if (matrix->format == format) { - return GrB_SUCCESS; - } - - // Matrix contain just one matrix and format is not same - GrB_Matrix *new_matrix = - matrix->format == GrB_ROWMAJOR ? &matrix->base_col : &matrix->base_row; - GrB_Matrix *old_matrix = - matrix->format == GrB_ROWMAJOR ? &matrix->base_row : &matrix->base_col; - - if (is_both) { - TRY(GrB_Matrix_new(new_matrix, GrB_BOOL, matrix->nrows, matrix->ncols)); - TRY(GrB_Matrix_assign(*new_matrix, GrB_NULL, GrB_NULL, *old_matrix, GrB_ALL, - matrix->nrows, GrB_ALL, matrix->ncols, GrB_NULL)); - matrix->is_both = true; - } else { - *new_matrix = *old_matrix; - *old_matrix = NULL; - } - - matrix->base = format == GrB_ROWMAJOR ? matrix->base_row : matrix->base_col; - format == GrB_ROWMAJOR ? TO_ROW(matrix->base) : TO_COL(matrix->base); - matrix->format = format; - return GrB_SUCCESS; -} - -GrB_Info matrix_clear(Matrix *A) { - GrB_Info result = GrB_Matrix_clear(A->base); - TRY(result); - CFL_matrix_update(A); - return result; -} - -GrB_Info matrix_clear_format(Matrix *A) { - if (!A->is_both) { - return matrix_clear(A); - } - - matrix_to_format(A, GrB_ROWMAJOR, false); - GrB_Info result = matrix_clear(A); - - if (result < GrB_SUCCESS) { - return result; - } - - matrix_to_format(A, GrB_COLMAJOR, false); - return matrix_clear(A); -} - -GrB_Info matrix_clear_empty(Matrix *A) { - if (A->nvals == 0) { - return GrB_SUCCESS; - } - - return matrix_clear_format(A); -} - -GrB_Info block_matrix_hyper_rotate_i(Matrix *matrix, enum CFL_Matrix_block format) { - if (matrix->is_lazy) { - for (size_t i = 0; i < matrix->base_matrices_count; i++) { - TRY(block_matrix_hyper_rotate_i(&matrix->base_matrices[i], format)); - } - - CFL_matrix_update(matrix); - return GrB_SUCCESS; - } - - if (matrix->block_type == CELL) { - return GrB_SUCCESS; - } - - if (matrix->block_type == format) { - return GrB_SUCCESS; - } - - GrB_Scalar scalar_true; - TRY(GrB_Scalar_new(&scalar_true, GrB_BOOL)); - TRY(GrB_Scalar_setElement_BOOL(scalar_true, true)); - - if (matrix->block_type == VEC_VERT) { - // fix: change to lagraph malloc - GrB_Index *nrows = malloc(matrix->nvals * sizeof(GrB_Index)); - GrB_Index *ncols = malloc(matrix->nvals * sizeof(GrB_Index)); - - TRY(GrB_Matrix_extractTuples_BOOL(nrows, ncols, NULL, &matrix->nvals, - matrix->base)); - - for (size_t i = 0; i < matrix->nvals; i++) { - ncols[i] = ncols[i] + nrows[i] / matrix->ncols * matrix->ncols; - nrows[i] = nrows[i] % matrix->ncols; - } - - GrB_Matrix new; - TRY(GrB_Matrix_new(&new, GrB_BOOL, matrix->ncols, matrix->nrows)); - TRY(GxB_Matrix_build_Scalar(new, nrows, ncols, scalar_true, matrix->nvals)); - CFL_matrix_free(matrix); - *matrix = - matrix->is_lazy ? CFL_matrix_from_base_lazy(new) : CFL_matrix_from_base(new); - free(nrows); - free(ncols); - GrB_free(&scalar_true); - return GrB_SUCCESS; - } - - if (matrix->block_type == VEC_HORIZ) { - GrB_Index *nrows = malloc(matrix->nvals * sizeof(GrB_Index)); - GrB_Index *ncols = malloc(matrix->nvals * sizeof(GrB_Index)); - - TRY(GrB_Matrix_extractTuples_BOOL(nrows, ncols, NULL, &matrix->nvals, - matrix->base)); - - for (size_t i = 0; i < matrix->nvals; i++) { - nrows[i] = nrows[i] + ncols[i] / matrix->nrows * matrix->nrows; - ncols[i] = ncols[i] % matrix->nrows; - } - - GrB_Matrix new; - TRY(GrB_Matrix_new(&new, GrB_BOOL, matrix->ncols, matrix->nrows)); - TRY(GxB_Matrix_build_Scalar(new, nrows, ncols, scalar_true, matrix->nvals)); - CFL_matrix_free(matrix); - *matrix = - matrix->is_lazy ? CFL_matrix_from_base_lazy(new) : CFL_matrix_from_base(new); - free(nrows); - free(ncols); - GrB_free(&scalar_true); - return GrB_SUCCESS; - } -} - -void block_matrix_to_diag(Matrix *diag, Matrix *input) { - if (input->block_type == CELL) { - exit(-1); - } - - GrB_Scalar scalar_true; - GrB_Scalar_new(&scalar_true, GrB_BOOL); - GrB_Scalar_setElement_BOOL(scalar_true, true); - - GrB_Index *rows = malloc(input->nvals * sizeof(GrB_Index)); - GrB_Index *cols = malloc(input->nvals * sizeof(GrB_Index)); - GrB_Matrix_extractTuples_BOOL(rows, cols, NULL, &input->nvals, input->base); - - if (input->block_type == VEC_HORIZ) { - for (size_t i = 0; i < input->nvals; i++) { - rows[i] = rows[i] + cols[i] / input->nrows * input->nrows; - } - } - - if (input->block_type == VEC_VERT) { - for (size_t i = 0; i < input->nvals; i++) { - cols[i] = cols[i] + rows[i] / input->ncols * input->ncols; - } - } - - GxB_Matrix_build_Scalar(diag->base, rows, cols, scalar_true, input->nvals); - - free(rows); - free(cols); - GrB_free(&scalar_true); -} - -GrB_Info matrix_dup_empty(Matrix *output, Matrix *input); -GrB_Info matrix_dup_block(Matrix *output, Matrix *input); - -void block_matrix_reduce(Matrix *matrix, Matrix *input) { - if (input->block_type == CELL) { - matrix_dup_block(matrix, input); - } - - GrB_Scalar scalar_true; - GrB_Scalar_new(&scalar_true, GrB_BOOL); - GrB_Scalar_setElement_BOOL(scalar_true, true); - - GrB_Index *rows = malloc(input->nvals * sizeof(GrB_Index)); - GrB_Index *cols = malloc(input->nvals * sizeof(GrB_Index)); - GrB_Matrix_extractTuples_BOOL(rows, cols, NULL, &input->nvals, input->base); - - if (input->block_type == VEC_VERT) { - for (size_t i = 0; i < input->nvals; i++) { - rows[i] = rows[i] % input->ncols; - } - } - - if (input->block_type == VEC_HORIZ) { - for (size_t i = 0; i < input->nvals; i++) { - cols[i] = cols[i] % input->nrows; - } - } - - GxB_Matrix_build_Scalar(matrix->base, rows, cols, scalar_true, input->nvals); - CFL_matrix_update(matrix); - - free(rows); - free(cols); - GrB_free(&scalar_true); -} - -void block_matrix_repeat_into_vector(Matrix *matrix, Matrix *input, - GrB_Index block_count) { - GrB_Matrix *tiles = malloc(block_count * sizeof(GrB_Matrix)); - for (size_t i = 0; i < block_count; i++) { - tiles[i] = input->base; - } - - GxB_Matrix_concat(matrix->base, tiles, block_count, 1, GrB_NULL); - CFL_matrix_update(matrix); -} - -GrB_Info matrix_dup(Matrix *output, Matrix *input) { - if (output == input) { - return GrB_SUCCESS; - } - - GrB_Info result = GrB_Matrix_apply(output->base, GrB_NULL, GrB_NULL, - GrB_IDENTITY_BOOL, input->base, GrB_NULL); - TRY(result); - CFL_matrix_update(output); - - return result; -} - -GrB_Info matrix_dup_format(Matrix *output, Matrix *input) { - if (!output->is_both) { - Matrix *larger = output->nvals > input->nvals ? output : input; - - matrix_to_format(output, larger->format, false); - matrix_to_format(input, larger->format, false); - - return matrix_dup(output, input); - } - - matrix_to_format(output, GrB_ROWMAJOR, false); - GrB_Info result = matrix_dup(output, input); - - if (result < GrB_SUCCESS) { - return result; - } - - matrix_to_format(output, GrB_COLMAJOR, false); - return matrix_dup(output, input); -} - -GrB_Info matrix_dup_empty(Matrix *output, Matrix *input) { - if (input->nvals == 0) { - return matrix_clear_empty(output); - } - - return matrix_dup_format(output, input); -} - -GrB_Info matrix_dup_block(Matrix *output, Matrix *input) { - if (output->block_type == CELL && input->block_type == CELL) { - return matrix_dup_empty(output, input); - } - - block_matrix_hyper_rotate_i(input, output->block_type); - return matrix_dup_empty(output, input); -} - -GrB_Info matrix_wise_empty(Matrix *output, Matrix *first, Matrix *second, bool accum); - -GrB_Info matrix_sort_lazy(Matrix *A, bool reverse) { - for (size_t i = 0; i < A->base_matrices_count; i++) { - for (size_t j = i + 1; j < A->base_matrices_count; j++) { - Matrix first = reverse ? A->base_matrices[i] : A->base_matrices[j]; - Matrix second = reverse ? A->base_matrices[j] : A->base_matrices[i]; - if (first.nvals < second.nvals) { - Matrix temp = A->base_matrices[i]; - A->base_matrices[i] = A->base_matrices[j]; - A->base_matrices[j] = temp; - } - } - } - - return GrB_SUCCESS; -} - -GrB_Info matrix_combine_lazy(Matrix *A, size_t threshold) { - Matrix *new_matrices = malloc(sizeof(Matrix) * 50); - size_t new_size = 0; - - TRY(matrix_sort_lazy(A, false)); - - for (size_t i = 0; i < A->base_matrices_count; i++) { - if (new_size == 0 || A->base_matrices[i].nvals > threshold) { - new_matrices[new_size++] = A->base_matrices[i]; - continue; - } - - TRY(matrix_wise_empty(&new_matrices[new_size - 1], &new_matrices[new_size - 1], - &A->base_matrices[i], false)); - GrB_free(&A->base_matrices[i].base); - } - - A->base_matrices = new_matrices; - A->base_matrices_count = new_size; - CFL_matrix_update(A); - - return GrB_SUCCESS; -} - -GrB_Info matrix_mxm(Matrix *output, Matrix *first, Matrix *second, bool accum, - bool swap) { - Matrix *left = swap ? second : first; - Matrix *right = swap ? first : second; - - GrB_Info result = GrB_mxm(output->base, GrB_NULL, accum ? GxB_ANY_BOOL : GrB_NULL, - GxB_ANY_PAIR_BOOL, left->base, right->base, GrB_NULL); - IS_ISO(output->base, "MXM output"); - CFL_matrix_update(output); - return result; -} - -GrB_Info matrix_mxm_format(Matrix *output, Matrix *first, Matrix *second, bool accum, - bool swap) { - GrB_Index left_nvals = swap ? second->nvals : first->nvals; - GrB_Index right_nvals = swap ? first->nvals : second->nvals; - - int32_t desired_orientation = left_nvals <= right_nvals ? GrB_ROWMAJOR : GrB_COLMAJOR; - - if (!first->is_both && first->format != desired_orientation && - !(first->nvals > second->nvals / 3.0)) { - GrB_Info result = matrix_mxm(output, first, second, accum, swap); - return result; - } - - matrix_to_format(first, desired_orientation, true); - matrix_to_format(second, desired_orientation, false); - matrix_to_format(output, desired_orientation, false); - GrB_Info result = matrix_mxm(output, first, second, accum, swap); - return result; -} - -GrB_Info matrix_mxm_empty(Matrix *output, Matrix *first, Matrix *second, bool accum, - bool swap) { - if (first->nvals == 0 || second->nvals == 0) { - if (accum) { - return GrB_SUCCESS; - } - - if (output->nvals == 0) { - return GrB_SUCCESS; - } - - matrix_clear_empty(output); - } - - return matrix_mxm_format(output, first, second, accum, swap); -} - -GrB_Info matrix_mxm_lazy(Matrix *output, Matrix *first, Matrix *second, bool accum, - bool swap) { - if (!first->is_lazy) { - return matrix_mxm_empty(output, first, second, accum, swap); - } - - matrix_combine_lazy(first, second->nvals); - matrix_sort_lazy(first, false); - - GrB_Matrix *accs = malloc(sizeof(GrB_Matrix) * first->base_matrices_count); - Matrix *acc_matrices = malloc(sizeof(Matrix) * first->base_matrices_count); - for (size_t i = 0; i < first->base_matrices_count; i++) { - GrB_Matrix_new(&accs[i], GrB_BOOL, swap ? second->nrows : first->nrows, - swap ? first->ncols : second->ncols); - acc_matrices[i] = CFL_matrix_from_base(accs[i]); - } - - for (size_t i = 0; i < first->base_matrices_count; i++) { - matrix_mxm_empty(&acc_matrices[i], &first->base_matrices[i], second, false, swap); - } - - for (size_t i = 0; i < first->base_matrices_count; i++) { - for (size_t j = i + 1; j < first->base_matrices_count; j++) { - if (acc_matrices[i].nvals > acc_matrices[j].nvals) { - Matrix temp = acc_matrices[i]; - acc_matrices[i] = acc_matrices[j]; - acc_matrices[j] = temp; - } - } - } - - GrB_Matrix acc; - GrB_Matrix_new(&acc, GrB_BOOL, swap ? second->nrows : first->nrows, - swap ? first->ncols : second->ncols); - Matrix acc_matrix = CFL_matrix_from_base(acc); - - for (size_t i = 0; i < first->base_matrices_count; i++) { - matrix_wise_empty(&acc_matrix, &acc_matrix, &acc_matrices[i], false); - GrB_free(&acc_matrices[i].base); - } - - if (accum) { - return matrix_wise_empty(output, output, &acc_matrix, false); - } - - GrB_Info result = matrix_dup_block(output, &acc_matrix); - GrB_free(&acc_matrix.base); - - return result; -} - -GrB_Info matrix_wise_block(Matrix *output, Matrix *first, Matrix *second, bool accum); - -GrB_Info matrix_mxm_block(Matrix *output, Matrix *first, Matrix *second, bool accum, - bool swap) { - if (first->block_type == CELL && second->block_type == CELL) { - return matrix_mxm_lazy(output, first, second, accum, swap); - } - - if (first->block_type == CELL) { - block_matrix_hyper_rotate_i(second, swap ? VEC_VERT : VEC_HORIZ); - block_matrix_hyper_rotate_i(output, swap ? VEC_VERT : VEC_HORIZ); - - Matrix temp = CFL_matrix_create(swap ? second->nrows : first->nrows, - swap ? first->ncols : second->ncols); - matrix_mxm_lazy(&temp, first, second, accum, swap); - matrix_wise_block(output, output, &temp, false); - CFL_matrix_free(&temp); - - return GrB_SUCCESS; - } - - if (second->block_type == CELL) { - block_matrix_hyper_rotate_i(first, swap ? VEC_HORIZ : VEC_VERT); - block_matrix_hyper_rotate_i(output, swap ? VEC_HORIZ : VEC_VERT); - - Matrix temp = CFL_matrix_create(swap ? second->nrows : first->nrows, - swap ? first->ncols : first->ncols); - matrix_mxm_lazy(&temp, first, second, accum, swap); - matrix_wise_block(output, output, &temp, false); - CFL_matrix_free(&temp); - - return GrB_SUCCESS; - } - - GrB_Index size = first->nrows > first->ncols ? first->nrows : first->ncols; - GrB_Matrix _diag; - GrB_Matrix_new(&_diag, GrB_BOOL, size, size); - Matrix diag = CFL_matrix_from_base(_diag); - block_matrix_to_diag(&diag, second); - CFL_matrix_update(&diag); - - block_matrix_hyper_rotate_i(first, swap ? VEC_VERT : VEC_HORIZ); - block_matrix_hyper_rotate_i(output, swap ? VEC_VERT : VEC_HORIZ); - - Matrix temp = CFL_matrix_create(first->nrows, diag.ncols); - matrix_mxm_lazy(&temp, first, &diag, false, swap); - return matrix_wise_block(output, output, &temp, false); -} - -GrB_Info matrix_wise(Matrix *output, Matrix *first, Matrix *second, bool accum) { - GrB_BinaryOp accum_op = accum ? GxB_ANY_BOOL : GrB_NULL; - if (output == first) - accum_op = GrB_NULL; - - GrB_Info result = GrB_eWiseAdd(output->base, GrB_NULL, accum_op, GxB_ANY_BOOL, - first->base, second->base, GrB_NULL); - - CFL_matrix_update(output); - return result; -} - -GrB_Info matrix_wise_format(Matrix *output, Matrix *first, Matrix *second, bool accum) { - if (!output->is_both) { - Matrix *larger = output->nvals > first->nvals ? output : first; - larger = larger->nvals > second->nvals ? larger : second; - - matrix_to_format(output, larger->format, false); - matrix_to_format(first, larger->format, false); - matrix_to_format(second, larger->format, false); - - return matrix_wise(output, first, second, accum); - } - - matrix_to_format(output, GrB_ROWMAJOR, false); - matrix_to_format(first, output->format, false); - matrix_to_format(second, output->format, false); - GrB_Info result = matrix_wise(output, first, second, accum); - - if (result < GrB_SUCCESS) { - return result; - } - - matrix_to_format(output, GrB_COLMAJOR, false); - matrix_to_format(first, output->format, false); - matrix_to_format(second, output->format, false); - return matrix_wise(output, first, second, accum); -} - -GrB_Info matrix_wise_empty(Matrix *output, Matrix *first, Matrix *second, bool accum) { - if (output == first) { - if (first->nvals == 0) { - return matrix_dup_empty(first, second); - } - - if (second->nvals == 0) { - return GrB_SUCCESS; - } - - return matrix_wise_format(output, first, second, accum); - } - - if (first->nvals == 0 && second->nvals == 0) { - if (accum || output->nvals == 0) { - return GrB_SUCCESS; - } - - return matrix_clear_empty(output); - } - - if (first->nvals == 0) { - if (accum) { - return matrix_wise_empty(output, output, second, false); - } - - return matrix_dup_empty(output, second); - } - - if (second->nvals == 0) { - if (accum) { - return matrix_wise_empty(output, output, first, false); - } - - return matrix_dup_empty(output, first); - } - - return matrix_wise_format(output, first, second, accum); -} - -GrB_Info matrix_wise_lazy(Matrix *output, Matrix *first, Matrix *second, bool accum) { - if (!first->is_lazy && !second->is_lazy) { - return matrix_wise_empty(output, first, second, accum); - } - - if (!first->is_lazy && second->is_lazy) { - for (size_t i = 0; i < second->base_matrices_count; i++) { - matrix_wise_empty(output, first, &second->base_matrices[i], false); - } - - return GrB_SUCCESS; - } - - GrB_Matrix _other; - GrB_Matrix_new(&_other, GrB_BOOL, output->nrows, output->ncols); - Matrix other = CFL_matrix_from_base(_other); - matrix_dup_empty(&other, second); - - size_t other_nvals = other.nvals >= 10 ? other.nvals : 10; - - while (true) { - bool found = false; - - for (size_t i = 0; i < first->base_matrices_count; i++) { - size_t self_nvals = - first->base_matrices[i].nvals >= 10 ? first->base_matrices[i].nvals : 10; - - if (other_nvals / 10 <= self_nvals && self_nvals <= other_nvals * 10) { - matrix_wise_empty(&other, &other, &first->base_matrices[i], accum); - GrB_free(&first->base_matrices[i].base); - for (size_t j = i + 1; j < first->base_matrices_count; j++) { - first->base_matrices[j - 1] = first->base_matrices[j]; - } - first->base_matrices_count--; - found = true; - break; - } - } - - if (found) { - continue; - } - - first->base_matrices[first->base_matrices_count++] = other; - break; - } - - return GrB_SUCCESS; -} - -// - Any operation on two hyper vectors is performed block-wise -// - When hyper vector is added in-place to a cell, then sum of hyper vector's blocks is -// added to a cell -// - When cell is added in-place to a hyper vector, then cell is added to each of -// hyper vector's blocks -GrB_Info matrix_wise_block(Matrix *output, Matrix *first, Matrix *second, bool accum) { - if (output != first) { - fprintf(stderr, "Matrix wise currently support only iadd operation"); - exit(-122); - } - - if (first->block_type == CELL && second->block_type == CELL) { - return matrix_wise_lazy(output, first, second, accum); - } - - // second is vector - if (first->block_type == CELL) { - Matrix temp_reduced = CFL_matrix_create(first->nrows, first->ncols); - block_matrix_reduce(&temp_reduced, second); - - GrB_Info info = matrix_wise_lazy(output, first, &temp_reduced, accum); - CFL_matrix_free(&temp_reduced); - return info; - } - - // first is vector - if (second->block_type == CELL) { - // LG_SET_BURBLE(true); - Matrix temp_vector = CFL_matrix_create(first->nrows, first->ncols); - GrB_Index block_count = first->nrows > first->ncols ? first->nrows : first->ncols; - block_matrix_repeat_into_vector(&temp_vector, second, block_count); - - block_matrix_hyper_rotate_i(&temp_vector, first->block_type); - GrB_Info info = matrix_wise_lazy(output, first, &temp_vector, accum); - CFL_matrix_free(&temp_vector); - return info; - } - - // both are vector - block_matrix_hyper_rotate_i(second, first->block_type); - return matrix_wise_lazy(output, first, second, accum); -} - -GrB_Info matrix_rsub(Matrix *output, Matrix *mask) { - GrB_Info result = GrB_eWiseAdd(output->base, mask->base, GrB_NULL, GxB_ANY_BOOL, - output->base, output->base, GrB_DESC_RSC); - - CFL_matrix_update(output); - return result; -} - -GrB_Info matrix_rsub_format(Matrix *output, Matrix *mask) { - Matrix *larger_matrix = output->nvals > mask->nvals ? output : mask; - TRY(matrix_to_format(output, larger_matrix->format, false)); - TRY(matrix_to_format(mask, larger_matrix->format, false)); - - if (!output->is_both) { - return matrix_rsub(output, mask); - } - - printf("LOOOOOO\n\n"); - - matrix_to_format(output, GrB_ROWMAJOR, false); - GrB_Info result = matrix_rsub(output, mask); - - if (result < GrB_SUCCESS) { - return result; - } - - matrix_to_format(output, GrB_COLMAJOR, false); - return matrix_rsub(output, mask); -} - -GrB_Info matrix_rsub_empty(Matrix *output, Matrix *mask) { - if (mask->nvals == 0 || output->nvals == 0) { - return GrB_SUCCESS; - } - - return matrix_rsub_format(output, mask); -} - -GrB_Info matrix_rsub_lazy(Matrix *output, Matrix *mask) { - if (!mask->is_lazy) { - return matrix_rsub_empty(output, mask); - } - - TRY(matrix_combine_lazy(mask, output->nvals)); - TRY(matrix_sort_lazy(mask, true)); - - for (size_t i = 0; i < mask->base_matrices_count; i++) { - TRY(matrix_rsub_empty(output, &mask->base_matrices[i])); - } - - return GrB_SUCCESS; -} - -GrB_Info matrix_rsub_block(Matrix *output, Matrix *mask) { - if ((output->block_type == CELL && mask->block_type != CELL) || - (output->block_type != CELL && mask->block_type == CELL)) { - fprintf(stderr, "Don't support rsub operation between cell and vector"); - exit(-1); - } - - if (output->block_type == CELL) { - return matrix_rsub_lazy(output, mask); - } - - TRY(block_matrix_hyper_rotate_i(output, mask->block_type)); - return matrix_rsub_lazy(output, mask); -} - -void matrix_print_lazy(Matrix *A) { - return; - GxB_Print_Level pr = 1; - - if (!A->is_lazy) { - CFL_matrix_update(A); - GxB_print(A->base, pr); - // printf("nnz: %ld\n", A->nvals); - return; - } - - if (A->base_matrices_count == 1) { - CFL_matrix_update(A); - // printf("nnz: %ld\n", A->nvals); - GxB_print(A->base_matrices[0].base, pr); - return; - } - - GrB_Matrix _temp; - GrB_Matrix_new(&_temp, GrB_BOOL, A->nrows, A->ncols); - Matrix temp = CFL_matrix_from_base(_temp); - for (size_t i = 0; i < A->base_matrices_count; i++) { - matrix_wise_empty(&temp, &temp, &A->base_matrices[i], false); - } - - A = &temp; - GxB_print(A->base, pr); - // printf("nnz: %ld\n", A->nvals); - GrB_free(&_temp); -} - -void print_graph_info(Matrix *matrices, size_t count) { - GrB_Index nnz = 0; - - for (size_t i = 0; i < count; i++) { - Matrix *A = &matrices[i]; - CFL_matrix_update(A); - nnz += A->nvals; - } - - printf("NNZ: %ld\n", nnz); -} - #define IS_NONTERM(index) \ { \ for (size_t m = 0; m < rules_count; m++) { \ @@ -1127,49 +382,14 @@ GrB_Info LAGraph_CFL_reachability_adv( return GrB_INVALID_VALUE; } - typedef GrB_Info (*matrix_mxm_fn)(Matrix *output, Matrix *first, Matrix *second, - bool accum, bool swap); - typedef GrB_Info (*matrix_wise_fn)(Matrix *output, Matrix *first, Matrix *second, - bool accum); - typedef GrB_Info (*matrix_rsub_fn)(Matrix *input, Matrix *mask); - - matrix_mxm_fn mxm; - matrix_wise_fn wise; - matrix_rsub_fn rsub; - - if (optimizations & OPT_LAZY) { - mxm = matrix_mxm_lazy; - wise = matrix_wise_lazy; - rsub = matrix_rsub_lazy; - } - if (optimizations & OPT_EMPTY) { - mxm = matrix_mxm_empty; - wise = matrix_wise_empty; - rsub = matrix_rsub_empty; - } - if (optimizations & OPT_FORMAT) { - mxm = matrix_mxm_format; - wise = matrix_wise_format; - rsub = matrix_rsub_format; - } - if (optimizations & OPT_BLOCK) { - mxm = matrix_mxm_block; - wise = matrix_wise_block; - rsub = matrix_rsub_block; - } - if (optimizations == 0x0) { - mxm = matrix_mxm; - wise = matrix_wise; - rsub = matrix_rsub; - } - // Rule [Variable -> term] for (size_t i = 0; i < term_rules_count; i++) { LAGraph_rule_WCNF term_rule = rules[term_rules[i]]; Matrix *nonterm_matrix = &delta_matrices[term_rule.nonterm]; Matrix *term_matrix = &delta_matrices[term_rule.prod_A]; - GRB_TRY(wise(nonterm_matrix, nonterm_matrix, term_matrix, true)); + GRB_TRY( + CFL_wise(nonterm_matrix, nonterm_matrix, term_matrix, true, optimizations)); #ifdef DEBUG_CFL_REACHBILITY // GxB_Matrix_iso(&iso_flag, T[term_rule.nonterm]); @@ -1190,7 +410,7 @@ GrB_Info LAGraph_CFL_reachability_adv( Matrix *nonterm_matrix = &delta_matrices[eps_rule.nonterm]; - wise(nonterm_matrix, nonterm_matrix, &iden, true); + CFL_wise(nonterm_matrix, nonterm_matrix, &iden, true, optimizations); #ifdef DEBUG_CFL_REACHBILITY // GxB_Matrix_iso(&iso_flag, T[eps_rule.nonterm]); @@ -1221,7 +441,7 @@ GrB_Info LAGraph_CFL_reachability_adv( #endif for (size_t i = 0; i < symbols_amount; i++) { - GRB_TRY(matrix_clear_empty(&temp_matrices[i])); + GRB_TRY(CFL_clear(&temp_matrices[i], optimizations)); } TIMER_START(); @@ -1235,7 +455,7 @@ GrB_Info LAGraph_CFL_reachability_adv( // matrix_print_lazy(A); // matrix_print_lazy(B); // matrix_print_lazy(C); - mxm(C, A, B, true, false); + CFL_mxm(C, A, B, true, false, optimizations); // matrix_print_lazy(C); } TIMER_STOP("MXM 1", &mxm1); @@ -1251,7 +471,7 @@ GrB_Info LAGraph_CFL_reachability_adv( // printf("WISE 1 iteration: %ld i: %ld\n", iteration, i); // matrix_print_lazy(A); // matrix_print_lazy(C); - wise(C, C, A, false); + CFL_wise(C, C, A, false, optimizations); // matrix_print_lazy(C); } TIMER_STOP("WISE 1", &wise1); @@ -1270,7 +490,7 @@ GrB_Info LAGraph_CFL_reachability_adv( // matrix_print_lazy(A); // matrix_print_lazy(B); // matrix_print_lazy(C); - mxm(C, A, B, true, true); + CFL_mxm(C, A, B, true, true, optimizations); // matrix_print_lazy(C); } TIMER_STOP("MXM 2", &mxm2); @@ -1287,7 +507,7 @@ GrB_Info LAGraph_CFL_reachability_adv( // printf("Simple rules iteration: %ld i: %ld\n", iteration, i); // matrix_print_lazy(A); // matrix_print_lazy(B); - wise(A, A, B, true); + CFL_wise(A, A, B, true, optimizations); // matrix_print_lazy(A); } // printf("Simple rules\n"); @@ -1297,7 +517,7 @@ GrB_Info LAGraph_CFL_reachability_adv( TIMER_START(); for (size_t i = 0; i < symbols_amount; i++) { - matrix_dup_block(&delta_matrices[i], &temp_matrices[i]); + CFL_dup(&delta_matrices[i], &temp_matrices[i], optimizations); } TIMER_STOP("WISE 2 (copy)", &wise2); // print_graph_info(matrices, symbols_amount); @@ -1312,7 +532,7 @@ GrB_Info LAGraph_CFL_reachability_adv( // printf("RSUB iteration: %ld i: %ld\n", iteration, i); // matrix_print_lazy(A); // matrix_print_lazy(C); - TRY(rsub(C, A)); + TRY(CFL_rsub(C, A, optimizations)); // matrix_print_lazy(C); } TIMER_STOP("WISE 3 (MASK)", &rsubt); @@ -1354,18 +574,7 @@ GrB_Info LAGraph_CFL_reachability_adv( if (matrices[i].base_matrices_count == 0) { outputs[i] = matrices[i].base; } else { - // TODO: new method for getting acc from lazy matrix - GrB_Matrix _acc; - GrB_Matrix_new(&_acc, GrB_BOOL, matrices[i].nrows, matrices[i].ncols); - Matrix acc = CFL_matrix_from_base(_acc); - - matrix_sort_lazy(&matrices[i], false); - for (size_t j = 0; j < matrices[i].base_matrices_count; j++) { - matrix_wise_empty(&acc, &acc, &matrices[i].base_matrices[j], false); - GrB_free(&matrices[i].base_matrices[j].base); - } - - outputs[i] = acc.base; + outputs[i] = CFL_matrix_lazy_to_base(&matrices[i], optimizations); } // outputs[i] = matrices[i].base; } diff --git a/include/LAGraphX.h b/include/LAGraphX.h index ca85338b68..df1149eb72 100644 --- a/include/LAGraphX.h +++ b/include/LAGraphX.h @@ -1151,6 +1151,15 @@ CFL_Matrix CFL_matrix_from_base_lazy(GrB_Matrix matrix); CFL_Matrix CFL_matrix_create(GrB_Index nrows, GrB_Index ncols); void CFL_matrix_free(CFL_Matrix *matrix); +GrB_Info CFL_mxm(CFL_Matrix *output, CFL_Matrix *first, CFL_Matrix *second, bool accum, + bool swap, int8_t optimizations); +GrB_Info CFL_wise(CFL_Matrix *output, CFL_Matrix *first, CFL_Matrix *second, bool accum, + int8_t optimizations); +GrB_Info CFL_rsub(CFL_Matrix *output, CFL_Matrix *mask, int8_t optimizations); +GrB_Info CFL_dup(CFL_Matrix *output, CFL_Matrix *input, int8_t optimizations); +GrB_Matrix CFL_matrix_lazy_to_base(CFL_Matrix *matrix, int8_t optimizations); +GrB_Info CFL_clear(CFL_Matrix *A, int8_t optimizations); + //------------------------------------------------------------------------------ // a simple example of an algorithm //------------------------------------------------------------------------------ From 2334b27ee9e6c61ac08d9bd2b25e96eed9a77652 Mon Sep 17 00:00:00 2001 From: Homka122 Date: Wed, 15 Oct 2025 06:54:06 +0300 Subject: [PATCH 100/122] Refactor: delete unused code and fix types of structures --- .../LAGraph_CFL_reachability_advanced.c | 88 +++++-------------- 1 file changed, 24 insertions(+), 64 deletions(-) diff --git a/experimental/algorithm/LAGraph_CFL_reachability_advanced.c b/experimental/algorithm/LAGraph_CFL_reachability_advanced.c index 2c4c3748aa..aeefb67229 100644 --- a/experimental/algorithm/LAGraph_CFL_reachability_advanced.c +++ b/experimental/algorithm/LAGraph_CFL_reachability_advanced.c @@ -17,10 +17,7 @@ #define LG_FREE_WORK \ { \ - LAGraph_Free((void **)&nnzs, msg); \ - GrB_free(&true_scalar); \ GrB_free(&identity_matrix); \ - LAGraph_Free((void **)&indexes, msg); \ } #define LG_FREE_ALL \ @@ -126,12 +123,6 @@ #define OPT_LAZY (1 << 2) #define OPT_BLOCK (1 << 3) -#define SKIP_IF_NULL(matrix) \ - GrB_Matrix_nvals(&new_nnz, matrix); \ - if (new_nnz == 0) { \ - continue; \ - } - #define TRY(GrB_method) \ { \ GrB_Info LG_GrB_Info = GrB_method; \ @@ -141,29 +132,6 @@ } \ } -typedef CFL_Matrix Matrix; -typedef enum CFL_Matrix_block Matrix_block; - -#define IS_NONTERM(index) \ - { \ - for (size_t m = 0; m < rules_count; m++) { \ - if (rules[m].nonterm == index) \ - return true; \ - } \ - \ - return false; \ - } - -bool is_nonterm(int index, const LAGraph_rule_WCNF *rules, size_t rules_count) { - for (size_t i = 0; i < rules_count; i++) { - if (rules[i].nonterm == index) { - return true; - } - } - - return false; -} - // LAGraph_CFL_reachability: Context-Free Language Reachability Matrix-Based Algorithm // // This function determines the set of vertex pairs (u, v) in a graph (represented by @@ -230,22 +198,17 @@ GrB_Info LAGraph_CFL_reachability_adv( int8_t optimizations // Optimizations flags ) { // Declare workspace and clear the msg string, if not NULL - Matrix *delta_matrices; - Matrix *matrices; - Matrix *temp_matrices; + CFL_Matrix *delta_matrices, *matrices, *temp_matrices; + CFL_Matrix iden; GrB_Matrix identity_matrix = NULL; - uint64_t *nnzs = NULL; LG_CLEAR_MSG; size_t msg_len = 0; // For error formatting - GrB_Index *indexes = NULL; - GrB_Scalar true_scalar; - GrB_Scalar_new(&true_scalar, GrB_BOOL); - GrB_Scalar_setElement_BOOL(true_scalar, true); - - LG_TRY(LAGraph_Calloc((void **)&delta_matrices, symbols_amount, sizeof(Matrix), msg)); - LG_TRY(LAGraph_Calloc((void **)&matrices, symbols_amount, sizeof(Matrix), msg)); - LG_TRY(LAGraph_Calloc((void **)&temp_matrices, symbols_amount, sizeof(Matrix), msg)); + LG_TRY(LAGraph_Calloc((void **)&delta_matrices, symbols_amount, sizeof(CFL_Matrix), + msg)); + LG_TRY(LAGraph_Calloc((void **)&matrices, symbols_amount, sizeof(CFL_Matrix), msg)); + LG_TRY( + LAGraph_Calloc((void **)&temp_matrices, symbols_amount, sizeof(CFL_Matrix), msg)); LG_ASSERT_MSG(symbols_amount > 0, GrB_INVALID_VALUE, "The number of symbols must be greater than zero."); @@ -289,8 +252,7 @@ GrB_Info LAGraph_CFL_reachability_adv( GrB_Index ncols; GrB_Matrix_ncols(&ncols, adj_matrices[i]); - GrB_Matrix_dup(&delta_matrices[i].base, adj_matrices[i]); - delta_matrices[i] = CFL_matrix_from_base(delta_matrices[i].base); + delta_matrices[i] = CFL_matrix_from_base(adj_matrices[i]); GRB_TRY(GrB_Matrix_new(&matrix, GrB_BOOL, nrows, ncols)); matrices[i] = ((optimizations & OPT_LAZY) || (optimizations & OPT_BLOCK)) @@ -385,8 +347,8 @@ GrB_Info LAGraph_CFL_reachability_adv( // Rule [Variable -> term] for (size_t i = 0; i < term_rules_count; i++) { LAGraph_rule_WCNF term_rule = rules[term_rules[i]]; - Matrix *nonterm_matrix = &delta_matrices[term_rule.nonterm]; - Matrix *term_matrix = &delta_matrices[term_rule.prod_A]; + CFL_Matrix *nonterm_matrix = &delta_matrices[term_rule.nonterm]; + CFL_Matrix *term_matrix = &delta_matrices[term_rule.prod_A]; GRB_TRY( CFL_wise(nonterm_matrix, nonterm_matrix, term_matrix, true, optimizations)); @@ -402,13 +364,13 @@ GrB_Info LAGraph_CFL_reachability_adv( GRB_TRY(GrB_Vector_assign_BOOL(v_diag, GrB_NULL, GrB_NULL, true, GrB_ALL, n, NULL)); GRB_TRY(GrB_Matrix_diag(&identity_matrix, v_diag, 0)); GRB_TRY(GrB_free(&v_diag)); - Matrix iden = CFL_matrix_from_base(identity_matrix); + iden = CFL_matrix_from_base(identity_matrix); // Rule [Variable -> eps] for (size_t i = 0; i < eps_rules_count; i++) { LAGraph_rule_WCNF eps_rule = rules[eps_rules[i]]; - Matrix *nonterm_matrix = &delta_matrices[eps_rule.nonterm]; + CFL_Matrix *nonterm_matrix = &delta_matrices[eps_rule.nonterm]; CFL_wise(nonterm_matrix, nonterm_matrix, &iden, true, optimizations); @@ -419,8 +381,6 @@ GrB_Info LAGraph_CFL_reachability_adv( } // Rule [Variable -> Variable1 Variable2] - LG_TRY(LAGraph_Calloc((void **)&nnzs, symbols_amount, sizeof(uint64_t), msg)); - double start_time, end_time; bool changed = true; size_t iteration = 0; @@ -447,9 +407,9 @@ GrB_Info LAGraph_CFL_reachability_adv( TIMER_START(); for (size_t i = 0; i < bin_rules_count; i++) { LAGraph_rule_WCNF bin_rule = rules[bin_rules[i]]; - Matrix *A = &matrices[bin_rule.prod_A]; - Matrix *B = &delta_matrices[bin_rule.prod_B]; - Matrix *C = &temp_matrices[bin_rule.nonterm]; + CFL_Matrix *A = &matrices[bin_rule.prod_A]; + CFL_Matrix *B = &delta_matrices[bin_rule.prod_B]; + CFL_Matrix *C = &temp_matrices[bin_rule.nonterm]; // printf("MXM 1 iteration: %ld i: %ld\n", iteration, i); // matrix_print_lazy(A); @@ -465,8 +425,8 @@ GrB_Info LAGraph_CFL_reachability_adv( TIMER_START() for (size_t i = 0; i < symbols_amount; i++) { - Matrix *A = &delta_matrices[i]; - Matrix *C = &matrices[i]; + CFL_Matrix *A = &delta_matrices[i]; + CFL_Matrix *C = &matrices[i]; // printf("WISE 1 iteration: %ld i: %ld\n", iteration, i); // matrix_print_lazy(A); @@ -482,9 +442,9 @@ GrB_Info LAGraph_CFL_reachability_adv( TIMER_START() for (size_t i = 0; i < bin_rules_count; i++) { LAGraph_rule_WCNF bin_rule = rules[bin_rules[i]]; - Matrix *A = &matrices[bin_rule.prod_B]; - Matrix *B = &delta_matrices[bin_rule.prod_A]; - Matrix *C = &temp_matrices[bin_rule.nonterm]; + CFL_Matrix *A = &matrices[bin_rule.prod_B]; + CFL_Matrix *B = &delta_matrices[bin_rule.prod_A]; + CFL_Matrix *C = &temp_matrices[bin_rule.nonterm]; // printf("MXM 2 iteration: %ld i: %ld\n", iteration, i); // matrix_print_lazy(A); @@ -501,8 +461,8 @@ GrB_Info LAGraph_CFL_reachability_adv( // Rule [Variable -> term] for (size_t i = 0; i < term_rules_count; i++) { LAGraph_rule_WCNF term_rule = rules[term_rules[i]]; - Matrix *A = &temp_matrices[term_rule.nonterm]; - Matrix *B = &delta_matrices[term_rule.prod_A]; + CFL_Matrix *A = &temp_matrices[term_rule.nonterm]; + CFL_Matrix *B = &delta_matrices[term_rule.prod_A]; // printf("Simple rules iteration: %ld i: %ld\n", iteration, i); // matrix_print_lazy(A); @@ -526,8 +486,8 @@ GrB_Info LAGraph_CFL_reachability_adv( TIMER_START(); for (size_t i = 0; i < symbols_amount; i++) { - Matrix *A = &matrices[i]; - Matrix *C = &delta_matrices[i]; + CFL_Matrix *A = &matrices[i]; + CFL_Matrix *C = &delta_matrices[i]; // printf("RSUB iteration: %ld i: %ld\n", iteration, i); // matrix_print_lazy(A); From c7ba5c01af6f19e3c48f2b4f93c9a35230ceaaee Mon Sep 17 00:00:00 2001 From: Homka122 Date: Thu, 16 Oct 2025 17:16:59 +0300 Subject: [PATCH 101/122] test: add tests for adv algorithm --- experimental/test/test_CFL_reachability_adv.c | 707 ++++++++++++++++++ 1 file changed, 707 insertions(+) create mode 100644 experimental/test/test_CFL_reachability_adv.c diff --git a/experimental/test/test_CFL_reachability_adv.c b/experimental/test/test_CFL_reachability_adv.c new file mode 100644 index 0000000000..8b40c79c3e --- /dev/null +++ b/experimental/test/test_CFL_reachability_adv.c @@ -0,0 +1,707 @@ +//------------------------------------------------------------------------------ +// LAGraph/experimental/test/LAGraph_CFL_reachability.c: test cases for Context-Free +// Language Reachability Matrix-Based Algorithm +//------------------------------------------------------------------------------ +// +// LAGraph, (c) 2019-2024 by The LAGraph Contributors, All Rights Reserved. +// SPDX-License-Identifier: BSD-2-Clause + +// Contributed by Ilhom Kombaev, Semyon Grigoriev, St. Petersburg State University. + +//------------------------------------------------------------------------------ + +#include +#include +#include +#include +#include +#include + +#define run_algorithm() \ + LAGraph_CFL_reachability_adv(outputs, adj_matrices, grammar.nonterms_count, \ + grammar.rules, grammar.rules_count, msg, 0) + +#define check_error(error) \ + { \ + retval = run_algorithm(); \ + TEST_CHECK(retval == error); \ + TEST_MSG("retval = %d (%s)", retval, msg); \ + } + +#define check_result(result) \ + { \ + char *expected = output_to_str(0); \ + TEST_CHECK(strcmp(result, expected) == 0); \ + TEST_MSG("Wrong result. Actual: %s", expected); \ + LAGraph_Free ((void **) &expected, msg); \ + } + +typedef struct { + size_t nonterms_count; + size_t terms_count; + size_t rules_count; + LAGraph_rule_WCNF *rules; +} grammar_t; + +GrB_Matrix *adj_matrices = NULL; +int n_adj_matrices = 0 ; +GrB_Matrix *outputs = NULL; +grammar_t grammar = {0, 0, 0, NULL}; +char msg[LAGRAPH_MSG_LEN]; + +void setup() { LAGraph_Init(msg); } + +void teardown(void) { LAGraph_Finalize(msg); } + +void init_outputs() { + LAGraph_Calloc((void **)&outputs, grammar.nonterms_count + grammar.terms_count, + sizeof(GrB_Matrix), msg); +} + +char *output_to_str(size_t nonterm) { + GrB_Index nnz = 0; + OK(GrB_Matrix_nvals(&nnz, outputs[nonterm])); + GrB_Index *row = NULL ; + GrB_Index *col = NULL ; + bool *val = NULL ; + LAGraph_Malloc ((void **) &row, nnz, sizeof (GrB_Index), msg) ; + LAGraph_Malloc ((void **) &col, nnz, sizeof (GrB_Index), msg) ; + LAGraph_Malloc ((void **) &val, nnz, sizeof (GrB_Index), msg) ; + + OK(GrB_Matrix_extractTuples(row, col, val, &nnz, outputs[nonterm])); + + // 11 - size of " (%ld, %ld)" + char *result_str = NULL ; + LAGraph_Malloc ((void **) &result_str, 11*nnz, sizeof (char), msg) ; + + result_str[0] = '\0'; + for (size_t i = 0; i < nnz; i++) { + sprintf(result_str + strlen(result_str), i == 0 ? + "(%" PRIu64 ", %" PRIu64 ")" : " (%" PRIu64 ", %" PRIu64 ")", + row[i], col[i]); + } + + LAGraph_Free ((void **) &row, msg); + LAGraph_Free ((void **) &col, msg); + LAGraph_Free ((void **) &val, msg); + + return result_str; +} + +void free_workspace() { + + if (adj_matrices != NULL) + { + for (size_t i = 0; i < n_adj_matrices ; i++) + { + GrB_free(&adj_matrices[i]); + } + } + LAGraph_Free ((void **) &adj_matrices, msg); + + if (outputs != NULL) + { + for (size_t i = 0; i < grammar.nonterms_count; i++) + { + GrB_free(&outputs[i]); + } + } + LAGraph_Free ((void **) &outputs, msg); + + LAGraph_Free ((void **) &grammar.rules, msg); + grammar = (grammar_t){0, 0, 0, NULL}; +} + +//==================== +// Grammars +//==================== + +// S -> aSb | ab in WCNF +// +// Terms: [0 a] [1 b] +// Nonterms: [0 S] [1 A] [2 B] [3 C] +// S -> AB [0 1 2 0] +// S -> AC [0 1 3 0] +// C -> SB [3 0 2 0] +// A -> a [1 0 -1 0] +// B -> b [2 1 -1 0] +void init_grammar_aSb() { + LAGraph_rule_WCNF *rules = NULL ; + LAGraph_Calloc ((void **) &rules, 5, sizeof(LAGraph_rule_WCNF), msg); + + rules[0] = (LAGraph_rule_WCNF){0, 1, 2, 0}; + rules[1] = (LAGraph_rule_WCNF){0, 1, 3, 0}; + rules[2] = (LAGraph_rule_WCNF){3, 0, 2, 0}; + rules[3] = (LAGraph_rule_WCNF){1, 4, -1, 0}; + rules[4] = (LAGraph_rule_WCNF){2, 5, -1, 0}; + + grammar = (grammar_t){ + .nonterms_count = 4, .terms_count = 2, .rules_count = 5, .rules = rules}; +} + +// S -> aS | a | eps in WCNF +// +// Terms: [0 a] +// Nonterms: [0 S] +// S -> SS [0 0 0 0] +// S -> a [0 0 -1 0] +// S -> eps [0 -1 -1 0] +void init_grammar_aS() { + LAGraph_rule_WCNF *rules = NULL ; + LAGraph_Calloc ((void **) &rules, 3, sizeof(LAGraph_rule_WCNF), msg); + + rules[0] = (LAGraph_rule_WCNF){0, 0, 0, 0}; + rules[1] = (LAGraph_rule_WCNF){0, 1, -1, 0}; + rules[2] = (LAGraph_rule_WCNF){0, -1, -1, 0}; + + grammar = (grammar_t){ + .nonterms_count = 1, .terms_count = 1, .rules_count = 3, .rules = rules}; +} + +// Complex grammar +// aaaabbbb or aaabbb +// +// Terms: [0 a] [1 b] +// Nonterms: [0 S] [n Sn] +// S -> S1 S2 [0 1 2 0] +// S -> S15 S16 [0 15 16 0] +// S1 -> S3 S4 [1 3 4 0] +// S2 -> S5 S6 [2 5 6 0] +// S3 -> S7 S8 [3 7 8 0] +// S4 -> S9 S10 [4 9 10 0] +// S5 -> S11 S12 [5 11 12 0] +// S6 -> S13 S14 [6 13 14 0] +// S16 -> S17 S18 [16 17 18 0] +// S17 -> S19 S20 [17 19 20 0] +// S18 -> S21 S22 [18 21 22 0] +// S22 -> S23 S24 [22 23 24 0] +// S7 -> a [7 0 -1 0] +// S8 -> a [8 0 -1 0] +// S9 -> a [9 0 -1 0] +// S10 -> a [10 0 -1 0] +// S11 -> b [11 1 -1 0] +// S12 -> b [12 1 -1 0] +// S13 -> b [13 1 -1 0] +// S14 -> b [14 1 -1 0] +// S15 -> a [15 0 -1 0] +// S19 -> a [19 0 -1 0] +// S20 -> a [20 0 -1 0] +// S21 -> b [21 1 -1 0] +// S23 -> b [23 1 -1 0] +// S24 -> b [24 1 -1 0] +void init_grammar_complex() { + LAGraph_rule_WCNF *rules = NULL ; + LAGraph_Calloc ((void **) &rules, 26, sizeof(LAGraph_rule_WCNF), msg); + + rules[0] = (LAGraph_rule_WCNF){0, 1, 2, 0}; + rules[1] = (LAGraph_rule_WCNF){0, 15, 16, 0}; + rules[2] = (LAGraph_rule_WCNF){1, 3, 4, 0}; + rules[3] = (LAGraph_rule_WCNF){2, 5, 6, 0}; + rules[4] = (LAGraph_rule_WCNF){3, 7, 8, 0}; + rules[5] = (LAGraph_rule_WCNF){4, 9, 10, 0}; + rules[6] = (LAGraph_rule_WCNF){5, 11, 12, 0}; + rules[7] = (LAGraph_rule_WCNF){6, 13, 14, 0}; + rules[8] = (LAGraph_rule_WCNF){16, 17, 18, 0}; + rules[9] = (LAGraph_rule_WCNF){17, 19, 20, 0}; + rules[10] = (LAGraph_rule_WCNF){18, 21, 22, 0}; + rules[11] = (LAGraph_rule_WCNF){22, 23, 24, 0}; + rules[12] = (LAGraph_rule_WCNF){7, 25, -1, 0}; + rules[13] = (LAGraph_rule_WCNF){8, 25, -1, 0}; + rules[14] = (LAGraph_rule_WCNF){9, 25, -1, 0}; + rules[15] = (LAGraph_rule_WCNF){10, 25, -1, 0}; + rules[16] = (LAGraph_rule_WCNF){11, 26, -1, 0}; + rules[17] = (LAGraph_rule_WCNF){12, 26, -1, 0}; + rules[18] = (LAGraph_rule_WCNF){13, 26, -1, 0}; + rules[19] = (LAGraph_rule_WCNF){14, 26, -1, 0}; + rules[20] = (LAGraph_rule_WCNF){15, 25, -1, 0}; + rules[21] = (LAGraph_rule_WCNF){19, 25, -1, 0}; + rules[22] = (LAGraph_rule_WCNF){20, 25, -1, 0}; + rules[23] = (LAGraph_rule_WCNF){21, 26, -1, 0}; + rules[24] = (LAGraph_rule_WCNF){23, 26, -1, 0}; + rules[25] = (LAGraph_rule_WCNF){24, 26, -1, 0}; + + grammar = (grammar_t){ + .nonterms_count = 25, .terms_count = 2, .rules_count = 26, .rules = rules}; +} + +//==================== +// Graphs +//==================== + +void init_nonterms_graphs() { + LAGraph_Realloc((void **)&adj_matrices, n_adj_matrices + grammar.nonterms_count, + n_adj_matrices, sizeof(GrB_Matrix), msg); + + GrB_Index size; + GrB_Matrix_nrows(&size, adj_matrices[0]); + + for (size_t i = 0; i < n_adj_matrices; i++) { + adj_matrices[grammar.nonterms_count + i] = adj_matrices[i]; + } + + for (size_t i = 0; i < grammar.nonterms_count; i++) { + GrB_Matrix temp; + GrB_Matrix_new(&temp, GrB_BOOL, size, size); + adj_matrices[i] = temp; + n_adj_matrices++; + } + + return; +} + +// Graph: +// +// 0 -a-> 1 +// 1 -a-> 2 +// 2 -a-> 0 +// 0 -b-> 3 +// 3 -b-> 0 +void init_graph_double_cycle() { + LAGraph_Calloc ((void **) &adj_matrices, 2, sizeof (GrB_Matrix), msg) ; + n_adj_matrices = 2 ; + + GrB_Matrix adj_matrix_a, adj_matrix_b; + OK(GrB_Matrix_new(&adj_matrix_a, GrB_BOOL, 4, 4)); + OK(GrB_Matrix_new(&adj_matrix_b, GrB_BOOL, 4, 4)); + + OK(GrB_Matrix_setElement(adj_matrix_a, true, 0, 1)); + OK(GrB_Matrix_setElement(adj_matrix_a, true, 1, 2)); + OK(GrB_Matrix_setElement(adj_matrix_a, true, 2, 0)); + + OK(GrB_Matrix_setElement(adj_matrix_b, true, 0, 3)); + OK(GrB_Matrix_setElement(adj_matrix_b, true, 3, 0)); + + adj_matrices[0] = adj_matrix_a; + adj_matrices[1] = adj_matrix_b; +} + +// Graph: +// +// 0 -a-> 1 +// 1 -a-> 2 +// 2 -a-> 3 +// 3 -a-> 4 +// 3 -b-> 5 +// 4 -b-> 3 +// 5 -b-> 6 +// 6 -b-> 7 +void init_graph_1() { + LAGraph_Calloc ((void **) &adj_matrices, 2, sizeof (GrB_Matrix), msg) ; + n_adj_matrices = 2 ; + + GrB_Matrix adj_matrix_a, adj_matrix_b; + OK(GrB_Matrix_new(&adj_matrix_a, GrB_BOOL, 8, 8)); + OK(GrB_Matrix_new(&adj_matrix_b, GrB_BOOL, 8, 8)); + + OK(GrB_Matrix_setElement(adj_matrix_a, true, 0, 1)); + OK(GrB_Matrix_setElement(adj_matrix_a, true, 1, 2)); + OK(GrB_Matrix_setElement(adj_matrix_a, true, 2, 3)); + OK(GrB_Matrix_setElement(adj_matrix_a, true, 3, 4)); + + OK(GrB_Matrix_setElement(adj_matrix_b, true, 3, 5)); + OK(GrB_Matrix_setElement(adj_matrix_b, true, 4, 3)); + OK(GrB_Matrix_setElement(adj_matrix_b, true, 5, 6)); + OK(GrB_Matrix_setElement(adj_matrix_b, true, 6, 7)); + + adj_matrices[0] = adj_matrix_a; + adj_matrices[1] = adj_matrix_b; +} + +// Graph: +// +// 0 -a-> 2 +// 1 -a-> 2 +// 3 -a-> 5 +// 4 -a-> 5 +// 2 -a-> 6 +// 5 -a-> 6 +// 2 -b-> 0 +// 2 -b-> 1 +// 5 -b-> 3 +// 5 -b-> 4 +// 6 -b-> 2 +// 6 -b-> 5 +void init_graph_tree() { + LAGraph_Calloc ((void **) &adj_matrices, 2, sizeof (GrB_Matrix), msg) ; + n_adj_matrices = 2 ; + + GrB_Matrix adj_matrix_a, adj_matrix_b; + OK(GrB_Matrix_new(&adj_matrix_a, GrB_BOOL, 7, 7)); + OK(GrB_Matrix_new(&adj_matrix_b, GrB_BOOL, 7, 7)); + + OK(GrB_Matrix_setElement(adj_matrix_a, true, 0, 2)); + OK(GrB_Matrix_setElement(adj_matrix_a, true, 1, 2)); + OK(GrB_Matrix_setElement(adj_matrix_a, true, 3, 5)); + OK(GrB_Matrix_setElement(adj_matrix_a, true, 4, 5)); + OK(GrB_Matrix_setElement(adj_matrix_a, true, 2, 6)); + OK(GrB_Matrix_setElement(adj_matrix_a, true, 5, 6)); + + OK(GrB_Matrix_setElement(adj_matrix_b, true, 2, 0)); + OK(GrB_Matrix_setElement(adj_matrix_b, true, 2, 1)); + OK(GrB_Matrix_setElement(adj_matrix_b, true, 5, 3)); + OK(GrB_Matrix_setElement(adj_matrix_b, true, 5, 4)); + OK(GrB_Matrix_setElement(adj_matrix_b, true, 6, 2)); + OK(GrB_Matrix_setElement(adj_matrix_b, true, 6, 5)); + + adj_matrices[0] = adj_matrix_a; + adj_matrices[1] = adj_matrix_b; +} + +// Graph: +// +// 0 -a-> 1 +// 1 -a-> 2 +// 2 -a-> 0 +void init_graph_one_cycle() { + LAGraph_Calloc ((void **) &adj_matrices, 1, sizeof (GrB_Matrix), msg) ; + n_adj_matrices = 1 ; + + GrB_Matrix adj_matrix_a; + GrB_Matrix_new(&adj_matrix_a, GrB_BOOL, 3, 3); + + OK(GrB_Matrix_setElement(adj_matrix_a, true, 0, 1)); + OK(GrB_Matrix_setElement(adj_matrix_a, true, 1, 2)); + OK(GrB_Matrix_setElement(adj_matrix_a, true, 2, 0)); + + adj_matrices[0] = adj_matrix_a; +} + +// Graph: + +// 0 -a-> 1 +// 1 -a-> 2 +// 2 -b-> 3 +// 3 -b-> 4 +void init_graph_line() { + LAGraph_Calloc ((void **) &adj_matrices, 2, sizeof (GrB_Matrix), msg) ; + n_adj_matrices = 2 ; + + GrB_Matrix adj_matrix_a, adj_matrix_b; + GrB_Matrix_new(&adj_matrix_a, GrB_BOOL, 5, 5); + GrB_Matrix_new(&adj_matrix_b, GrB_BOOL, 5, 5); + + OK(GrB_Matrix_setElement(adj_matrix_a, true, 0, 1)); + OK(GrB_Matrix_setElement(adj_matrix_a, true, 1, 2)); + + OK(GrB_Matrix_setElement(adj_matrix_b, true, 2, 3)); + OK(GrB_Matrix_setElement(adj_matrix_b, true, 3, 4)); + + adj_matrices[0] = adj_matrix_a; + adj_matrices[1] = adj_matrix_b; +} + +// Graph: + +// 0 -a-> 0 +// 0 -b-> 1 +// 1 -c-> 2 +void init_graph_2() { + LAGraph_Calloc ((void **) &adj_matrices, 3, sizeof (GrB_Matrix), msg) ; + n_adj_matrices = 3 ; + + GrB_Matrix adj_matrix_a, adj_matrix_b, adj_matrix_c; + GrB_Matrix_new(&adj_matrix_a, GrB_BOOL, 3, 3); + GrB_Matrix_new(&adj_matrix_b, GrB_BOOL, 3, 3); + GrB_Matrix_new(&adj_matrix_c, GrB_BOOL, 3, 3); + + OK(GrB_Matrix_setElement(adj_matrix_a, true, 0, 0)); + OK(GrB_Matrix_setElement(adj_matrix_b, true, 0, 1)); + OK(GrB_Matrix_setElement(adj_matrix_c, true, 1, 2)); + + adj_matrices[0] = adj_matrix_a; + adj_matrices[1] = adj_matrix_b; + adj_matrices[2] = adj_matrix_c; +} + +// Graph: + +// 0 -a-> 1 +// 1 -a-> 0 +// 0 -b-> 0 +void init_graph_3() { + LAGraph_Calloc ((void **) &adj_matrices, 2, sizeof (GrB_Matrix), msg) ; + n_adj_matrices = 2 ; + + GrB_Matrix adj_matrix_a, adj_matrix_b; + GrB_Matrix_new(&adj_matrix_a, GrB_BOOL, 2, 2); + GrB_Matrix_new(&adj_matrix_b, GrB_BOOL, 2, 2); + + OK(GrB_Matrix_setElement(adj_matrix_a, true, 0, 1)); + OK(GrB_Matrix_setElement(adj_matrix_a, true, 1, 0)); + OK(GrB_Matrix_setElement(adj_matrix_b, true, 0, 0)); + + adj_matrices[0] = adj_matrix_a; + adj_matrices[1] = adj_matrix_b; +} + +// Graph: + +// 0 -b-> 1 +// 1 -b-> 0 +void init_graph_4() { + LAGraph_Calloc ((void **) &adj_matrices, 2, sizeof (GrB_Matrix), msg) ; + n_adj_matrices = 2 ; + + GrB_Matrix adj_matrix_a, adj_matrix_b; + GrB_Matrix_new(&adj_matrix_a, GrB_BOOL, 2, 2); + GrB_Matrix_new(&adj_matrix_b, GrB_BOOL, 2, 2); + + OK(GrB_Matrix_setElement(adj_matrix_b, true, 0, 1)); + OK(GrB_Matrix_setElement(adj_matrix_b, true, 1, 0)); + + adj_matrices[0] = adj_matrix_a; + adj_matrices[1] = adj_matrix_b; +} + +//==================== +// Tests with valid result +//==================== + +void test_CFL_reachability_cycle(void) { + setup(); + GrB_Info retval; + + init_grammar_aS(); + init_graph_one_cycle(); + init_nonterms_graphs(); + init_outputs() ; + + OK(run_algorithm()); + check_result("(0, 0) (0, 1) (0, 2) (1, 0) (1, 1) (1, 2) (2, 0) (2, 1) (2, 2)"); + + free_workspace(); + teardown(); +} + +void test_CFL_reachability_two_cycle(void) { + setup(); + GrB_Info retval; + + init_grammar_aSb(); + init_graph_double_cycle(); + init_nonterms_graphs(); + init_outputs() ; + + OK(run_algorithm()); + check_result("(0, 0) (0, 3) (1, 0) (1, 3) (2, 0) (2, 3)"); + + free_workspace(); + teardown(); +} + +void test_CFL_reachability_labels_more_than_nonterms(void) { + setup(); + GrB_Info retval; + + init_grammar_aSb(); + init_graph_2(); + init_nonterms_graphs(); + init_outputs() ; + + OK(run_algorithm()); + check_result("(0, 1)"); + + free_workspace(); + teardown(); +} + +void test_CFL_reachability_complex_grammar(void) { + setup(); + GrB_Info retval; + + init_grammar_complex(); + init_graph_1(); + init_nonterms_graphs(); + init_outputs() ; + + OK(run_algorithm()); + check_result("(0, 7) (1, 6)"); + + free_workspace(); + teardown(); +} + +void test_CFL_reachability_tree(void) { + setup(); + GrB_Info retval; + + init_grammar_aSb(); + init_graph_tree(); + init_nonterms_graphs(); + init_outputs() ; + + OK(run_algorithm()); + check_result("(0, 0) (0, 1) (0, 3) (0, 4) (1, 0) (1, 1) (1, 3) (1, 4) (2, 2) (2, 5) " + "(3, 0) (3, 1) (3, 3) (3, 4) (4, 0) (4, 1) (4, 3) (4, 4) (5, 2) (5, 5)"); + + free_workspace(); + teardown(); +} + +void test_CFL_reachability_line(void) { + setup(); + GrB_Info retval; + + init_grammar_aSb(); + init_graph_line(); + init_nonterms_graphs(); + init_outputs() ; + + OK(run_algorithm()); + check_result("(0, 4) (1, 3)"); + + free_workspace(); + teardown(); +} + +void test_CFL_reachability_two_nodes_cycle(void) { + setup(); + GrB_Info retval; + + init_grammar_aSb(); + init_graph_3(); + init_nonterms_graphs(); + init_outputs() ; + + OK(run_algorithm()); + check_result("(0, 0) (1, 0)"); + + free_workspace(); + teardown(); +} + +void test_CFL_reachability_with_empty_adj_matrix(void) { + setup(); + GrB_Info retval; + + init_grammar_aS(); + init_graph_4(); + init_nonterms_graphs(); + init_outputs() ; + + OK(run_algorithm()); + check_result("(0, 0) (1, 1)"); + + free_workspace(); + teardown(); +} + +//==================== +// Tests with invalid result +//==================== + +void test_CFL_reachability_invalid_rules(void) { + setup(); + GrB_Info retval; + + init_grammar_aSb(); + init_graph_double_cycle(); + init_outputs() ; + + // Rule [Variable -> _ B] + grammar.rules[0] = + (LAGraph_rule_WCNF){.nonterm = 0, .prod_A = -1, .prod_B = 1, .index = 0}; + check_error(GrB_INVALID_VALUE); + + // Rule [_ -> A B] + grammar.rules[0] = + (LAGraph_rule_WCNF){.nonterm = -1, .prod_A = 1, .prod_B = 2, .index = 0}; + check_error(GrB_INVALID_VALUE); + + // Rule [C -> A B], where C >= nonterms_count + grammar.rules[0] = + (LAGraph_rule_WCNF){.nonterm = 10, .prod_A = 1, .prod_B = 2, .index = 0}; + check_error(GrB_INVALID_VALUE); + + // Rule [S -> A B], where A >= nonterms_count + grammar.rules[0] = + (LAGraph_rule_WCNF){.nonterm = 0, .prod_A = 10, .prod_B = 2, .index = 0}; + check_error(GrB_INVALID_VALUE); + + // Rule [C -> t], where t >= terms_count + grammar.rules[0] = + (LAGraph_rule_WCNF){.nonterm = 0, .prod_A = 10, .prod_B = -1, .index = 0}; + check_error(GrB_INVALID_VALUE); + + free_workspace(); + teardown(); + + return; +} + +void test_CFL_reachability_null_pointers(void) { +// FIXME: this test fails when testing with CUDA: +// Test CFG_reachability_null_pointers... +// GB_cuda_get_device_count: 2, cudaError_t: 0 +// GB_cuda_init: ngpus: 2 +// Device: 0: memory: 34079899648 SMs: 80 compute: 7.0 +// Device: 1: memory: 34079899648 SMs: 80 compute: 7.0 +// CUDA_VISIBLE_DEVICES = 0,1 +// getting cuda visible devices +// Found device_id 0 +// Found device_id 1 +// devices.size is 2 +// cuda warmup 0 +// cuda warmup 0 OK +// cuda warmup 1 +// cuda warmup 1 OK +// free(): invalid pointer +// Test interrupted by SIGABRT. + + setup(); + GrB_Info retval; + + init_grammar_aSb(); + init_graph_double_cycle(); + init_outputs() ; + +// adj_matrices[0] = NULL; +// adj_matrices[1] = NULL; + GrB_free(&adj_matrices[0]); + GrB_free(&adj_matrices[1]); + + check_error(GrB_NULL_POINTER); + +// adj_matrices = NULL; + LAGraph_Free ((void **) &adj_matrices, msg); + check_error(GrB_NULL_POINTER); + + free_workspace(); + init_grammar_aSb(); + init_graph_double_cycle(); + init_outputs() ; + +// outputs = NULL; + LAGraph_Free ((void **) &outputs, msg); + check_error(GrB_NULL_POINTER); + + free_workspace(); + init_grammar_aSb(); + init_graph_double_cycle(); + init_outputs() ; + +// grammar.rules = NULL; + LAGraph_Free ((void **) &grammar.rules, msg); + check_error(GrB_NULL_POINTER); + + free_workspace(); + teardown(); + + return; +} + +TEST_LIST = {{"CFL_reachability_complex_grammar", test_CFL_reachability_complex_grammar}, + {"CFL_reachability_cycle", test_CFL_reachability_cycle}, + {"CFL_reachability_two_cycle", test_CFL_reachability_two_cycle}, + {"CFL_reachability_labels_more_than_nonterms", + test_CFL_reachability_labels_more_than_nonterms}, + {"CFL_reachability_tree", test_CFL_reachability_tree}, + {"CFL_reachability_line", test_CFL_reachability_line}, + {"CFL_reachability_two_nodes_cycle", test_CFL_reachability_two_nodes_cycle}, + {"CFG_reach_basic_invalid_rules", test_CFL_reachability_invalid_rules}, + {"test_CFL_reachability_with_empty_adj_matrix", + test_CFL_reachability_with_empty_adj_matrix}, +#if !defined(GRAPHBLAS_HAS_CUDA) + {"CFG_reachability_null_pointers", test_CFL_reachability_null_pointers}, +#endif + {NULL, NULL}}; From 9941af10b3a60c967566b66bada3ef666d202419 Mon Sep 17 00:00:00 2001 From: homka122 Date: Thu, 16 Oct 2025 18:34:43 +0300 Subject: [PATCH 102/122] Fix: delete files with algorithm --- include/LAGraphX.h | 26 -------------------------- 1 file changed, 26 deletions(-) diff --git a/include/LAGraphX.h b/include/LAGraphX.h index df1149eb72..e77b0f332d 100644 --- a/include/LAGraphX.h +++ b/include/LAGraphX.h @@ -1096,32 +1096,6 @@ GrB_Info LAGraph_CFL_reachability char *msg // Message string for error reporting. ) ; -GrB_Info LAGraph_CFL_reachability_adv -( - // Output - GrB_Matrix *outputs, // Array of matrices containing results. - // The size of the array must be equal to nonterms_count. - // - // outputs[k]: (i, j) = true if and only if there is a path - // from node i to node j whose edge labels form a word - // derivable from the non-terminal 'k' of the specified CFG. - // Input - const GrB_Matrix *adj_matrices, // Array of adjacency matrices representing the graph. - // The length of this array is equal to the count of - // terminals (terms_count). - // - // adj_matrices[t]: (i, j) == 1 if and only if there - // is an edge between nodes i and j with the label of - // the terminal corresponding to index 't' (where t is - // in the range [0, terms_count - 1]). - size_t symbols_amount, - const LAGraph_rule_WCNF *rules, // The rules of the CFG. - size_t rules_count, // The total number of rules in the CFG. - char *msg, // Message string for error reporting. - int8_t optimizations // Optimizations flags -); - - enum CFL_Matrix_block { CELL, VEC_HORIZ, VEC_VERT }; // Struct for matrix for CFL algorithms with optimizations From 28c6696bcbb3c1317724306c8ed0bb61b2158e80 Mon Sep 17 00:00:00 2001 From: homka122 Date: Fri, 17 Oct 2025 20:44:16 +0300 Subject: [PATCH 103/122] Fix: delete unused files --- .../LAGraph_CFL_reachability_advanced.c | 544 -------------- experimental/test/test_CFL_reachability_adv.c | 707 ------------------ 2 files changed, 1251 deletions(-) delete mode 100644 experimental/algorithm/LAGraph_CFL_reachability_advanced.c delete mode 100644 experimental/test/test_CFL_reachability_adv.c diff --git a/experimental/algorithm/LAGraph_CFL_reachability_advanced.c b/experimental/algorithm/LAGraph_CFL_reachability_advanced.c deleted file mode 100644 index aeefb67229..0000000000 --- a/experimental/algorithm/LAGraph_CFL_reachability_advanced.c +++ /dev/null @@ -1,544 +0,0 @@ -//------------------------------------------------------------------------------ -// LAGraph_CFL_reachability.c: Context-Free Language Reachability Matrix-Based -// Algorithm -// ------------------------------------------------------------------------------ -// -// LAGraph, (c) 2019-2024 by The LAGraph Contributors, All Rights Reserved. -// SPDX-License-Identifier: BSD-2-Clause - -// Contributed by Ilhom Kombaev, Semyon Grigoriev, St. Petersburg State University. - -//------------------------------------------------------------------------------ - -// Code is based on the "A matrix-based CFPQ algorithm" described in the -// following paper: * Rustam Azimov, Semyon Grigorev, "Context-Free Path -// Querying Using Linear Algebra", URL: -// https://disser.spbu.ru/files/2022/disser_azimov.pdf - -#define LG_FREE_WORK \ - { \ - GrB_free(&identity_matrix); \ - } - -#define LG_FREE_ALL \ - { \ - for (size_t i = 0; i < symbols_amount; i++) { \ - /* TODO: delete it and free actual matrices */ \ - /* GrB_free(&T[i]); */ \ - } \ - \ - LG_FREE_WORK; \ - } - -#include "LG_internal.h" -#include - -#define ERROR_RULE(msg) \ - { \ - LG_ASSERT_MSGF(false, GrB_INVALID_VALUE, "Rule with index %ld is invalid. " msg, \ - i); \ - } - -#define ADD_TO_MSG(...) \ - { \ - if (msg_len == 0) { \ - msg_len += \ - snprintf(msg, LAGRAPH_MSG_LEN, \ - "LAGraph failure (file %s, line %d): ", __FILE__, __LINE__); \ - } \ - if (msg_len < LAGRAPH_MSG_LEN) { \ - msg_len += snprintf(msg + msg_len, LAGRAPH_MSG_LEN - msg_len, __VA_ARGS__); \ - } \ - } - -#define ADD_INDEX_TO_ERROR_RULE(rule, i) \ - { \ - rule.len_indexes_str += snprintf(rule.indexes_str + rule.len_indexes_str, \ - LAGRAPH_MSG_LEN - rule.len_indexes_str, \ - rule.count == 0 ? "%ld" : ", %ld", i); \ - rule.count++; \ - } - -// clang-format off -#if BENCH_CFL_REACHBILITY - #define IS_ISO(matrix, str) \ - { \ - bool iso_flag; \ - GrB_Index nnz; \ - GxB_Matrix_iso(&iso_flag, matrix); \ - GrB_Matrix_nvals(&nnz, matrix); \ - if (!iso_flag && nnz) { \ - printf("-----ISO ALERT----- (%s)\n", str); \ - GxB_print(matrix, 1); \ - printf("-------------------\n"); \ - } \ - } - - #define TIMER_START() \ - { \ - start_time = LAGraph_WallClockTime(); \ - } - - #define TIMER_STOP(label, accumulator) \ - { \ - end_time = LAGraph_WallClockTime(); \ - printf("%s %.3fs\n", label, end_time - start_time); \ - if (accumulator != NULL) { \ - *(accumulator) += (end_time - start_time); \ - } \ - } - - #define IS_ROW(matrix, str) \ - { \ - int32_t orientation; \ - GrB_get(matrix, &orientation, GrB_STORAGE_ORIENTATION_HINT); \ - if (orientation != GrB_ROWMAJOR) { \ - printf("-----NOT A ROW----- (%s)\n", str); \ - GxB_print(matrix, 1); \ - printf("-------------------\n"); \ - } \ - } - - #define IS_COL(matrix, str) \ - { \ - int32_t orientation; \ - GrB_get(matrix, &orientation, GrB_STORAGE_ORIENTATION_HINT); \ - if (orientation != GrB_COLMAJOR) { \ - printf("-----NOT A COL----- (%s)\n", str); \ - GxB_print(matrix, 1); \ - printf("-------------------\n"); \ - } \ - } -#else - #define IS_ISO(matrix, str) - #define TIMER_START() - #define TIMER_STOP(label, accumulator) - #define IS_ROW(matrix, str) - #define IS_COL(matrix, str) -#endif -// clang-format on - -#define OPT_EMPTY (1 << 0) -#define OPT_FORMAT (1 << 1) -#define OPT_LAZY (1 << 2) -#define OPT_BLOCK (1 << 3) - -#define TRY(GrB_method) \ - { \ - GrB_Info LG_GrB_Info = GrB_method; \ - if (LG_GrB_Info < GrB_SUCCESS) { \ - fprintf(stderr, "LAGraph failure (file %s, line %d): ", __FILE__, __LINE__); \ - exit(LG_GrB_Info); \ - } \ - } - -// LAGraph_CFL_reachability: Context-Free Language Reachability Matrix-Based Algorithm -// -// This function determines the set of vertex pairs (u, v) in a graph (represented by -// adjacency matrices) such that there is a path from u to v, where the edge labels -// form a word from the language generated by the context-free grammar (represented by -// `rules`). -// -// Terminals and non-terminals are enumerated by integers starting from zero. -// The start non-terminal is the non-terminal with index 0. -// -// Example: -// -// Graph: -// ┌───┐ ┌───┐ ┌───┐ ┌───┐ ┌───┐ -// │ 0 ├───► 1 ├───► 2 ├───► 3 ├───► 4 │ -// └───┘ a └─┬─┘ a └─▲─┘ b └───┘ b └───┘ -// │ │ -// │ ┌───┐ │ -// a└─► 5 ├─┘b -// └───┘ -// -// Grammar: S -> aSb | ab -// -// There are paths from node [1] to node [3] and from node [1] to node [2] that form -// the word "ab" ([1]-a->[2]-b->[3] and [1]-a->[5]-b->[2]). The word "ab" is in the -// language generated by our context-free grammar, so the pairs (1, 3) and (1, 2) will -// be included in the result. -// -// Note: It doesn't matter how many paths exist from node [A] to node [B] that form a -// word in the language. If at least one path exists, the pair ([A], [B]) will be -// included in the result. -// -// In contrast, the path from node [1] to node [4] forms the word "abb" -// ([1]-a->[2]-b->[3]-b->[4]) and the word "abbb" ([1]-a->[5]-b->[2]-b->[3]-b->[4]). -// The words "aab" and "abbb" are not in the language, so the pair (1, 4) will not be -// included in the result. -// -// With this graph and grammar, we obtain the following results: -// (0, 4) - because there exists a path (0-1-2-3-4) that forms the word "aabb" -// (1, 3) - because there exists a path (1-2-3) that forms "ab" -// (1, 2) - because there exists a path (1-5-2) that forms the word "ab" -// (0, 3) - because there exists a path (0-1-5-2-3) that forms the word "aabb" -GrB_Info LAGraph_CFL_reachability_adv( - // Output - GrB_Matrix *outputs, // Array of matrices containing results. - // The size of the array must be equal to nonterms_count. - // - // outputs[k]: (i, j) = true if and only if there is a path - // from node i to node j whose edge labels form a word - // derivable from the non-terminal 'k' of the specified CFG. - // Input - const GrB_Matrix *adj_matrices, // Array of adjacency matrices representing the graph. - // The length of this array is equal to the count of - // terminals (terms_count). - // - // adj_matrices[t]: (i, j) == 1 if and only if there - // is an edge between nodes i and j with the label of - // the terminal corresponding to index 't' (where t is - // in the range [0, terms_count - 1]). - size_t symbols_amount, - const LAGraph_rule_WCNF *rules, // The rules of the CFG. - size_t rules_count, // The total number of rules in the CFG. - char *msg, // Message string for error reporting. - int8_t optimizations // Optimizations flags -) { - // Declare workspace and clear the msg string, if not NULL - CFL_Matrix *delta_matrices, *matrices, *temp_matrices; - CFL_Matrix iden; - GrB_Matrix identity_matrix = NULL; - LG_CLEAR_MSG; - size_t msg_len = 0; // For error formatting - - LG_TRY(LAGraph_Calloc((void **)&delta_matrices, symbols_amount, sizeof(CFL_Matrix), - msg)); - LG_TRY(LAGraph_Calloc((void **)&matrices, symbols_amount, sizeof(CFL_Matrix), msg)); - LG_TRY( - LAGraph_Calloc((void **)&temp_matrices, symbols_amount, sizeof(CFL_Matrix), msg)); - - LG_ASSERT_MSG(symbols_amount > 0, GrB_INVALID_VALUE, - "The number of symbols must be greater than zero."); - LG_ASSERT_MSG(rules_count > 0, GrB_INVALID_VALUE, - "The number of rules must be greater than zero."); - LG_ASSERT_MSG(outputs != NULL, GrB_NULL_POINTER, "The outputs array cannot be null."); - LG_ASSERT_MSG(rules != NULL, GrB_NULL_POINTER, "The rules array cannot be null."); - LG_ASSERT_MSG(adj_matrices != NULL, GrB_NULL_POINTER, - "The adjacency matrices array cannot be null."); - - // Find null adjacency matrices - bool found_null = false; - for (size_t i = 0; i < symbols_amount; i++) { - if (adj_matrices[i] != NULL) - continue; - - if (!found_null) { - ADD_TO_MSG("Adjacency matrices with these indexes are null: "); - ADD_TO_MSG("%ld", i); - } else { - ADD_TO_MSG(", %ld", i); - } - - found_null = true; - } - - if (found_null) { - LG_FREE_ALL; - return GrB_NULL_POINTER; - } - - GrB_Index n; - GRB_TRY(GrB_Matrix_ncols(&n, adj_matrices[0])); - - // Create nonterms matrices - for (size_t i = 0; i < symbols_amount; i++) { - GrB_Matrix matrix; - - GrB_Index nrows; - GrB_Matrix_nrows(&nrows, adj_matrices[i]); - GrB_Index ncols; - GrB_Matrix_ncols(&ncols, adj_matrices[i]); - - delta_matrices[i] = CFL_matrix_from_base(adj_matrices[i]); - - GRB_TRY(GrB_Matrix_new(&matrix, GrB_BOOL, nrows, ncols)); - matrices[i] = ((optimizations & OPT_LAZY) || (optimizations & OPT_BLOCK)) - ? CFL_matrix_from_base_lazy(matrix) - : CFL_matrix_from_base(matrix); - - GRB_TRY(GrB_Matrix_new(&matrix, GrB_BOOL, nrows, ncols)); - temp_matrices[i] = CFL_matrix_from_base(matrix); - } - - // Arrays for processing rules - size_t eps_rules[rules_count], eps_rules_count = 0; // [Variable -> eps] - size_t term_rules[rules_count], term_rules_count = 0; // [Variable -> term] - size_t bin_rules[rules_count], bin_rules_count = 0; // [Variable -> AB] - - // Process rules - typedef struct { - size_t count; - size_t len_indexes_str; - char indexes_str[LAGRAPH_MSG_LEN]; - } rule_error_s; - rule_error_s term_err = {0}; - rule_error_s nonterm_err = {0}; - rule_error_s invalid_err = {0}; - for (size_t i = 0; i < rules_count; i++) { - LAGraph_rule_WCNF rule = rules[i]; - - bool is_rule_eps = rule.prod_A == -1 && rule.prod_B == -1; - bool is_rule_term = rule.prod_A != -1 && rule.prod_B == -1; - bool is_rule_bin = rule.prod_A != -1 && rule.prod_B != -1; - - // Check that all rules are well-formed - if (rule.nonterm < 0 || (size_t)rule.nonterm >= symbols_amount) { - ADD_INDEX_TO_ERROR_RULE(nonterm_err, i); - } - - // [Variable -> eps] - if (is_rule_eps) { - eps_rules[eps_rules_count++] = i; - - continue; - } - - // [Variable -> term] - if (is_rule_term) { - term_rules[term_rules_count++] = i; - - if (rule.prod_A < -1 || (size_t)rule.prod_A >= symbols_amount) { - ADD_INDEX_TO_ERROR_RULE(term_err, i); - } - - continue; - } - - // [Variable -> A B] - if (is_rule_bin) { - bin_rules[bin_rules_count++] = i; - - if (rule.prod_A < -1 || (size_t)rule.prod_A >= symbols_amount || - rule.prod_B < -1 || (size_t)rule.prod_B >= symbols_amount) { - ADD_INDEX_TO_ERROR_RULE(nonterm_err, i); - } - - continue; - } - - // [Variable -> _ B] - ADD_INDEX_TO_ERROR_RULE(invalid_err, i); - } - - if (term_err.count + nonterm_err.count + invalid_err.count > 0) { - ADD_TO_MSG("Count of invalid rules: %ld.\n", - term_err.count + nonterm_err.count + invalid_err.count); - - if (nonterm_err.count > 0) { - ADD_TO_MSG("Non-terminals must be in range [0, nonterms_count). "); - ADD_TO_MSG("Indexes of invalid rules: %s\n", nonterm_err.indexes_str) - } - if (term_err.count > 0) { - ADD_TO_MSG("Terminals must be in range [-1, nonterms_count). "); - ADD_TO_MSG("Indexes of invalid rules: %s\n", term_err.indexes_str) - } - if (invalid_err.count > 0) { - ADD_TO_MSG("[Variable -> _ B] type of rule is not acceptable. "); - ADD_TO_MSG("Indexes of invalid rules: %.120s\n", invalid_err.indexes_str) - } - - LG_FREE_ALL; - return GrB_INVALID_VALUE; - } - - // Rule [Variable -> term] - for (size_t i = 0; i < term_rules_count; i++) { - LAGraph_rule_WCNF term_rule = rules[term_rules[i]]; - CFL_Matrix *nonterm_matrix = &delta_matrices[term_rule.nonterm]; - CFL_Matrix *term_matrix = &delta_matrices[term_rule.prod_A]; - - GRB_TRY( - CFL_wise(nonterm_matrix, nonterm_matrix, term_matrix, true, optimizations)); - -#ifdef DEBUG_CFL_REACHBILITY - // GxB_Matrix_iso(&iso_flag, T[term_rule.nonterm]); - printf("[TERM] eWiseUnion: NONTERM: %d (ISO: %d)\n", term_rule.nonterm, iso_flag); -#endif - } - - GrB_Vector v_diag; - GRB_TRY(GrB_Vector_new(&v_diag, GrB_BOOL, n)); - GRB_TRY(GrB_Vector_assign_BOOL(v_diag, GrB_NULL, GrB_NULL, true, GrB_ALL, n, NULL)); - GRB_TRY(GrB_Matrix_diag(&identity_matrix, v_diag, 0)); - GRB_TRY(GrB_free(&v_diag)); - iden = CFL_matrix_from_base(identity_matrix); - - // Rule [Variable -> eps] - for (size_t i = 0; i < eps_rules_count; i++) { - LAGraph_rule_WCNF eps_rule = rules[eps_rules[i]]; - - CFL_Matrix *nonterm_matrix = &delta_matrices[eps_rule.nonterm]; - - CFL_wise(nonterm_matrix, nonterm_matrix, &iden, true, optimizations); - -#ifdef DEBUG_CFL_REACHBILITY - // GxB_Matrix_iso(&iso_flag, T[eps_rule.nonterm]); - printf("[EPS] eWiseUnion: NONTERM: %d (ISO: %d)\n", eps_rule.nonterm, iso_flag); -#endif - } - - // Rule [Variable -> Variable1 Variable2] - double start_time, end_time; - bool changed = true; - size_t iteration = 0; - double mxm1 = 0.0; - double wise1 = 0.0; - double mxm2 = 0.0; - double wise2 = 0.0; - double rsubt = 0.0; - // print_graph_info(matrices, symbols_amount); - // print_graph_info(delta_matrices, symbols_amount); - // print_graph_info(temp_matrices, symbols_amount); - while (changed) { - iteration++; - changed = false; - -#if BENCH_CFL_REACHBILITY - printf("\n--- ITERATARION %ld ---\n", iteration); -#endif - - for (size_t i = 0; i < symbols_amount; i++) { - GRB_TRY(CFL_clear(&temp_matrices[i], optimizations)); - } - - TIMER_START(); - for (size_t i = 0; i < bin_rules_count; i++) { - LAGraph_rule_WCNF bin_rule = rules[bin_rules[i]]; - CFL_Matrix *A = &matrices[bin_rule.prod_A]; - CFL_Matrix *B = &delta_matrices[bin_rule.prod_B]; - CFL_Matrix *C = &temp_matrices[bin_rule.nonterm]; - - // printf("MXM 1 iteration: %ld i: %ld\n", iteration, i); - // matrix_print_lazy(A); - // matrix_print_lazy(B); - // matrix_print_lazy(C); - CFL_mxm(C, A, B, true, false, optimizations); - // matrix_print_lazy(C); - } - TIMER_STOP("MXM 1", &mxm1); - // print_graph_info(matrices, symbols_amount); - // print_graph_info(delta_matrices, symbols_amount); - // print_graph_info(temp_matrices, symbols_amount); - - TIMER_START() - for (size_t i = 0; i < symbols_amount; i++) { - CFL_Matrix *A = &delta_matrices[i]; - CFL_Matrix *C = &matrices[i]; - - // printf("WISE 1 iteration: %ld i: %ld\n", iteration, i); - // matrix_print_lazy(A); - // matrix_print_lazy(C); - CFL_wise(C, C, A, false, optimizations); - // matrix_print_lazy(C); - } - TIMER_STOP("WISE 1", &wise1); - // print_graph_info(matrices, symbols_amount); - // print_graph_info(delta_matrices, symbols_amount); - // print_graph_info(temp_matrices, symbols_amount); - - TIMER_START() - for (size_t i = 0; i < bin_rules_count; i++) { - LAGraph_rule_WCNF bin_rule = rules[bin_rules[i]]; - CFL_Matrix *A = &matrices[bin_rule.prod_B]; - CFL_Matrix *B = &delta_matrices[bin_rule.prod_A]; - CFL_Matrix *C = &temp_matrices[bin_rule.nonterm]; - - // printf("MXM 2 iteration: %ld i: %ld\n", iteration, i); - // matrix_print_lazy(A); - // matrix_print_lazy(B); - // matrix_print_lazy(C); - CFL_mxm(C, A, B, true, true, optimizations); - // matrix_print_lazy(C); - } - TIMER_STOP("MXM 2", &mxm2); - // print_graph_info(matrices, symbols_amount); - // print_graph_info(delta_matrices, symbols_amount); - // print_graph_info(temp_matrices, symbols_amount); - - // Rule [Variable -> term] - for (size_t i = 0; i < term_rules_count; i++) { - LAGraph_rule_WCNF term_rule = rules[term_rules[i]]; - CFL_Matrix *A = &temp_matrices[term_rule.nonterm]; - CFL_Matrix *B = &delta_matrices[term_rule.prod_A]; - - // printf("Simple rules iteration: %ld i: %ld\n", iteration, i); - // matrix_print_lazy(A); - // matrix_print_lazy(B); - CFL_wise(A, A, B, true, optimizations); - // matrix_print_lazy(A); - } - // printf("Simple rules\n"); - // print_graph_info(matrices, symbols_amount); - // print_graph_info(delta_matrices, symbols_amount); - // print_graph_info(temp_matrices, symbols_amount); - - TIMER_START(); - for (size_t i = 0; i < symbols_amount; i++) { - CFL_dup(&delta_matrices[i], &temp_matrices[i], optimizations); - } - TIMER_STOP("WISE 2 (copy)", &wise2); - // print_graph_info(matrices, symbols_amount); - // print_graph_info(delta_matrices, symbols_amount); - // print_graph_info(temp_matrices, symbols_amount); - - TIMER_START(); - for (size_t i = 0; i < symbols_amount; i++) { - CFL_Matrix *A = &matrices[i]; - CFL_Matrix *C = &delta_matrices[i]; - - // printf("RSUB iteration: %ld i: %ld\n", iteration, i); - // matrix_print_lazy(A); - // matrix_print_lazy(C); - TRY(CFL_rsub(C, A, optimizations)); - // matrix_print_lazy(C); - } - TIMER_STOP("WISE 3 (MASK)", &rsubt); - // print_graph_info(matrices, symbols_amount); - // print_graph_info(delta_matrices, symbols_amount); - // print_graph_info(temp_matrices, symbols_amount); - - size_t new_nnz = 0; - for (size_t i = 0; i < symbols_amount; i++) { - CFL_matrix_update(&delta_matrices[i]); - new_nnz += delta_matrices[i].nvals; - } - - if (new_nnz != 0) { - changed = true; - } - -#ifdef DEBUG_CFL_REACHBILITY - // GxB_Matrix_iso(&iso_flag, T[bin_rule.nonterm]); - printf("[TERM1 TERM2] MULTIPLY, S: %d, A: %d, B: %d, " - "I: %ld (ISO: %d)\n", - bin_rule.nonterm, bin_rule.prod_A, bin_rule.prod_B, i, iso_flag); -#endif - } - -#if BENCH_CFL_REACHBILITY - printf("MXM1: %.3f, wise1: %.3f, MXM2: %.3f, wise2: %.3f, rsub: %.3f", mxm1, wise1, - mxm2, wise2, rsubt); -#endif - -#ifdef DEBUG_CFL_REACHBILITY - for (int32_t i = 0; i < nonterms_count; i++) { - printf("MATRIX WITH INDEX %d:\n", i); - // GxB_print(T[i], GxB_SUMMARY); - } -#endif - - for (size_t i = 0; i < symbols_amount; i++) { - if (matrices[i].base_matrices_count == 0) { - outputs[i] = matrices[i].base; - } else { - outputs[i] = CFL_matrix_lazy_to_base(&matrices[i], optimizations); - } - // outputs[i] = matrices[i].base; - } - - LG_FREE_WORK; - return GrB_SUCCESS; -} diff --git a/experimental/test/test_CFL_reachability_adv.c b/experimental/test/test_CFL_reachability_adv.c deleted file mode 100644 index 8b40c79c3e..0000000000 --- a/experimental/test/test_CFL_reachability_adv.c +++ /dev/null @@ -1,707 +0,0 @@ -//------------------------------------------------------------------------------ -// LAGraph/experimental/test/LAGraph_CFL_reachability.c: test cases for Context-Free -// Language Reachability Matrix-Based Algorithm -//------------------------------------------------------------------------------ -// -// LAGraph, (c) 2019-2024 by The LAGraph Contributors, All Rights Reserved. -// SPDX-License-Identifier: BSD-2-Clause - -// Contributed by Ilhom Kombaev, Semyon Grigoriev, St. Petersburg State University. - -//------------------------------------------------------------------------------ - -#include -#include -#include -#include -#include -#include - -#define run_algorithm() \ - LAGraph_CFL_reachability_adv(outputs, adj_matrices, grammar.nonterms_count, \ - grammar.rules, grammar.rules_count, msg, 0) - -#define check_error(error) \ - { \ - retval = run_algorithm(); \ - TEST_CHECK(retval == error); \ - TEST_MSG("retval = %d (%s)", retval, msg); \ - } - -#define check_result(result) \ - { \ - char *expected = output_to_str(0); \ - TEST_CHECK(strcmp(result, expected) == 0); \ - TEST_MSG("Wrong result. Actual: %s", expected); \ - LAGraph_Free ((void **) &expected, msg); \ - } - -typedef struct { - size_t nonterms_count; - size_t terms_count; - size_t rules_count; - LAGraph_rule_WCNF *rules; -} grammar_t; - -GrB_Matrix *adj_matrices = NULL; -int n_adj_matrices = 0 ; -GrB_Matrix *outputs = NULL; -grammar_t grammar = {0, 0, 0, NULL}; -char msg[LAGRAPH_MSG_LEN]; - -void setup() { LAGraph_Init(msg); } - -void teardown(void) { LAGraph_Finalize(msg); } - -void init_outputs() { - LAGraph_Calloc((void **)&outputs, grammar.nonterms_count + grammar.terms_count, - sizeof(GrB_Matrix), msg); -} - -char *output_to_str(size_t nonterm) { - GrB_Index nnz = 0; - OK(GrB_Matrix_nvals(&nnz, outputs[nonterm])); - GrB_Index *row = NULL ; - GrB_Index *col = NULL ; - bool *val = NULL ; - LAGraph_Malloc ((void **) &row, nnz, sizeof (GrB_Index), msg) ; - LAGraph_Malloc ((void **) &col, nnz, sizeof (GrB_Index), msg) ; - LAGraph_Malloc ((void **) &val, nnz, sizeof (GrB_Index), msg) ; - - OK(GrB_Matrix_extractTuples(row, col, val, &nnz, outputs[nonterm])); - - // 11 - size of " (%ld, %ld)" - char *result_str = NULL ; - LAGraph_Malloc ((void **) &result_str, 11*nnz, sizeof (char), msg) ; - - result_str[0] = '\0'; - for (size_t i = 0; i < nnz; i++) { - sprintf(result_str + strlen(result_str), i == 0 ? - "(%" PRIu64 ", %" PRIu64 ")" : " (%" PRIu64 ", %" PRIu64 ")", - row[i], col[i]); - } - - LAGraph_Free ((void **) &row, msg); - LAGraph_Free ((void **) &col, msg); - LAGraph_Free ((void **) &val, msg); - - return result_str; -} - -void free_workspace() { - - if (adj_matrices != NULL) - { - for (size_t i = 0; i < n_adj_matrices ; i++) - { - GrB_free(&adj_matrices[i]); - } - } - LAGraph_Free ((void **) &adj_matrices, msg); - - if (outputs != NULL) - { - for (size_t i = 0; i < grammar.nonterms_count; i++) - { - GrB_free(&outputs[i]); - } - } - LAGraph_Free ((void **) &outputs, msg); - - LAGraph_Free ((void **) &grammar.rules, msg); - grammar = (grammar_t){0, 0, 0, NULL}; -} - -//==================== -// Grammars -//==================== - -// S -> aSb | ab in WCNF -// -// Terms: [0 a] [1 b] -// Nonterms: [0 S] [1 A] [2 B] [3 C] -// S -> AB [0 1 2 0] -// S -> AC [0 1 3 0] -// C -> SB [3 0 2 0] -// A -> a [1 0 -1 0] -// B -> b [2 1 -1 0] -void init_grammar_aSb() { - LAGraph_rule_WCNF *rules = NULL ; - LAGraph_Calloc ((void **) &rules, 5, sizeof(LAGraph_rule_WCNF), msg); - - rules[0] = (LAGraph_rule_WCNF){0, 1, 2, 0}; - rules[1] = (LAGraph_rule_WCNF){0, 1, 3, 0}; - rules[2] = (LAGraph_rule_WCNF){3, 0, 2, 0}; - rules[3] = (LAGraph_rule_WCNF){1, 4, -1, 0}; - rules[4] = (LAGraph_rule_WCNF){2, 5, -1, 0}; - - grammar = (grammar_t){ - .nonterms_count = 4, .terms_count = 2, .rules_count = 5, .rules = rules}; -} - -// S -> aS | a | eps in WCNF -// -// Terms: [0 a] -// Nonterms: [0 S] -// S -> SS [0 0 0 0] -// S -> a [0 0 -1 0] -// S -> eps [0 -1 -1 0] -void init_grammar_aS() { - LAGraph_rule_WCNF *rules = NULL ; - LAGraph_Calloc ((void **) &rules, 3, sizeof(LAGraph_rule_WCNF), msg); - - rules[0] = (LAGraph_rule_WCNF){0, 0, 0, 0}; - rules[1] = (LAGraph_rule_WCNF){0, 1, -1, 0}; - rules[2] = (LAGraph_rule_WCNF){0, -1, -1, 0}; - - grammar = (grammar_t){ - .nonterms_count = 1, .terms_count = 1, .rules_count = 3, .rules = rules}; -} - -// Complex grammar -// aaaabbbb or aaabbb -// -// Terms: [0 a] [1 b] -// Nonterms: [0 S] [n Sn] -// S -> S1 S2 [0 1 2 0] -// S -> S15 S16 [0 15 16 0] -// S1 -> S3 S4 [1 3 4 0] -// S2 -> S5 S6 [2 5 6 0] -// S3 -> S7 S8 [3 7 8 0] -// S4 -> S9 S10 [4 9 10 0] -// S5 -> S11 S12 [5 11 12 0] -// S6 -> S13 S14 [6 13 14 0] -// S16 -> S17 S18 [16 17 18 0] -// S17 -> S19 S20 [17 19 20 0] -// S18 -> S21 S22 [18 21 22 0] -// S22 -> S23 S24 [22 23 24 0] -// S7 -> a [7 0 -1 0] -// S8 -> a [8 0 -1 0] -// S9 -> a [9 0 -1 0] -// S10 -> a [10 0 -1 0] -// S11 -> b [11 1 -1 0] -// S12 -> b [12 1 -1 0] -// S13 -> b [13 1 -1 0] -// S14 -> b [14 1 -1 0] -// S15 -> a [15 0 -1 0] -// S19 -> a [19 0 -1 0] -// S20 -> a [20 0 -1 0] -// S21 -> b [21 1 -1 0] -// S23 -> b [23 1 -1 0] -// S24 -> b [24 1 -1 0] -void init_grammar_complex() { - LAGraph_rule_WCNF *rules = NULL ; - LAGraph_Calloc ((void **) &rules, 26, sizeof(LAGraph_rule_WCNF), msg); - - rules[0] = (LAGraph_rule_WCNF){0, 1, 2, 0}; - rules[1] = (LAGraph_rule_WCNF){0, 15, 16, 0}; - rules[2] = (LAGraph_rule_WCNF){1, 3, 4, 0}; - rules[3] = (LAGraph_rule_WCNF){2, 5, 6, 0}; - rules[4] = (LAGraph_rule_WCNF){3, 7, 8, 0}; - rules[5] = (LAGraph_rule_WCNF){4, 9, 10, 0}; - rules[6] = (LAGraph_rule_WCNF){5, 11, 12, 0}; - rules[7] = (LAGraph_rule_WCNF){6, 13, 14, 0}; - rules[8] = (LAGraph_rule_WCNF){16, 17, 18, 0}; - rules[9] = (LAGraph_rule_WCNF){17, 19, 20, 0}; - rules[10] = (LAGraph_rule_WCNF){18, 21, 22, 0}; - rules[11] = (LAGraph_rule_WCNF){22, 23, 24, 0}; - rules[12] = (LAGraph_rule_WCNF){7, 25, -1, 0}; - rules[13] = (LAGraph_rule_WCNF){8, 25, -1, 0}; - rules[14] = (LAGraph_rule_WCNF){9, 25, -1, 0}; - rules[15] = (LAGraph_rule_WCNF){10, 25, -1, 0}; - rules[16] = (LAGraph_rule_WCNF){11, 26, -1, 0}; - rules[17] = (LAGraph_rule_WCNF){12, 26, -1, 0}; - rules[18] = (LAGraph_rule_WCNF){13, 26, -1, 0}; - rules[19] = (LAGraph_rule_WCNF){14, 26, -1, 0}; - rules[20] = (LAGraph_rule_WCNF){15, 25, -1, 0}; - rules[21] = (LAGraph_rule_WCNF){19, 25, -1, 0}; - rules[22] = (LAGraph_rule_WCNF){20, 25, -1, 0}; - rules[23] = (LAGraph_rule_WCNF){21, 26, -1, 0}; - rules[24] = (LAGraph_rule_WCNF){23, 26, -1, 0}; - rules[25] = (LAGraph_rule_WCNF){24, 26, -1, 0}; - - grammar = (grammar_t){ - .nonterms_count = 25, .terms_count = 2, .rules_count = 26, .rules = rules}; -} - -//==================== -// Graphs -//==================== - -void init_nonterms_graphs() { - LAGraph_Realloc((void **)&adj_matrices, n_adj_matrices + grammar.nonterms_count, - n_adj_matrices, sizeof(GrB_Matrix), msg); - - GrB_Index size; - GrB_Matrix_nrows(&size, adj_matrices[0]); - - for (size_t i = 0; i < n_adj_matrices; i++) { - adj_matrices[grammar.nonterms_count + i] = adj_matrices[i]; - } - - for (size_t i = 0; i < grammar.nonterms_count; i++) { - GrB_Matrix temp; - GrB_Matrix_new(&temp, GrB_BOOL, size, size); - adj_matrices[i] = temp; - n_adj_matrices++; - } - - return; -} - -// Graph: -// -// 0 -a-> 1 -// 1 -a-> 2 -// 2 -a-> 0 -// 0 -b-> 3 -// 3 -b-> 0 -void init_graph_double_cycle() { - LAGraph_Calloc ((void **) &adj_matrices, 2, sizeof (GrB_Matrix), msg) ; - n_adj_matrices = 2 ; - - GrB_Matrix adj_matrix_a, adj_matrix_b; - OK(GrB_Matrix_new(&adj_matrix_a, GrB_BOOL, 4, 4)); - OK(GrB_Matrix_new(&adj_matrix_b, GrB_BOOL, 4, 4)); - - OK(GrB_Matrix_setElement(adj_matrix_a, true, 0, 1)); - OK(GrB_Matrix_setElement(adj_matrix_a, true, 1, 2)); - OK(GrB_Matrix_setElement(adj_matrix_a, true, 2, 0)); - - OK(GrB_Matrix_setElement(adj_matrix_b, true, 0, 3)); - OK(GrB_Matrix_setElement(adj_matrix_b, true, 3, 0)); - - adj_matrices[0] = adj_matrix_a; - adj_matrices[1] = adj_matrix_b; -} - -// Graph: -// -// 0 -a-> 1 -// 1 -a-> 2 -// 2 -a-> 3 -// 3 -a-> 4 -// 3 -b-> 5 -// 4 -b-> 3 -// 5 -b-> 6 -// 6 -b-> 7 -void init_graph_1() { - LAGraph_Calloc ((void **) &adj_matrices, 2, sizeof (GrB_Matrix), msg) ; - n_adj_matrices = 2 ; - - GrB_Matrix adj_matrix_a, adj_matrix_b; - OK(GrB_Matrix_new(&adj_matrix_a, GrB_BOOL, 8, 8)); - OK(GrB_Matrix_new(&adj_matrix_b, GrB_BOOL, 8, 8)); - - OK(GrB_Matrix_setElement(adj_matrix_a, true, 0, 1)); - OK(GrB_Matrix_setElement(adj_matrix_a, true, 1, 2)); - OK(GrB_Matrix_setElement(adj_matrix_a, true, 2, 3)); - OK(GrB_Matrix_setElement(adj_matrix_a, true, 3, 4)); - - OK(GrB_Matrix_setElement(adj_matrix_b, true, 3, 5)); - OK(GrB_Matrix_setElement(adj_matrix_b, true, 4, 3)); - OK(GrB_Matrix_setElement(adj_matrix_b, true, 5, 6)); - OK(GrB_Matrix_setElement(adj_matrix_b, true, 6, 7)); - - adj_matrices[0] = adj_matrix_a; - adj_matrices[1] = adj_matrix_b; -} - -// Graph: -// -// 0 -a-> 2 -// 1 -a-> 2 -// 3 -a-> 5 -// 4 -a-> 5 -// 2 -a-> 6 -// 5 -a-> 6 -// 2 -b-> 0 -// 2 -b-> 1 -// 5 -b-> 3 -// 5 -b-> 4 -// 6 -b-> 2 -// 6 -b-> 5 -void init_graph_tree() { - LAGraph_Calloc ((void **) &adj_matrices, 2, sizeof (GrB_Matrix), msg) ; - n_adj_matrices = 2 ; - - GrB_Matrix adj_matrix_a, adj_matrix_b; - OK(GrB_Matrix_new(&adj_matrix_a, GrB_BOOL, 7, 7)); - OK(GrB_Matrix_new(&adj_matrix_b, GrB_BOOL, 7, 7)); - - OK(GrB_Matrix_setElement(adj_matrix_a, true, 0, 2)); - OK(GrB_Matrix_setElement(adj_matrix_a, true, 1, 2)); - OK(GrB_Matrix_setElement(adj_matrix_a, true, 3, 5)); - OK(GrB_Matrix_setElement(adj_matrix_a, true, 4, 5)); - OK(GrB_Matrix_setElement(adj_matrix_a, true, 2, 6)); - OK(GrB_Matrix_setElement(adj_matrix_a, true, 5, 6)); - - OK(GrB_Matrix_setElement(adj_matrix_b, true, 2, 0)); - OK(GrB_Matrix_setElement(adj_matrix_b, true, 2, 1)); - OK(GrB_Matrix_setElement(adj_matrix_b, true, 5, 3)); - OK(GrB_Matrix_setElement(adj_matrix_b, true, 5, 4)); - OK(GrB_Matrix_setElement(adj_matrix_b, true, 6, 2)); - OK(GrB_Matrix_setElement(adj_matrix_b, true, 6, 5)); - - adj_matrices[0] = adj_matrix_a; - adj_matrices[1] = adj_matrix_b; -} - -// Graph: -// -// 0 -a-> 1 -// 1 -a-> 2 -// 2 -a-> 0 -void init_graph_one_cycle() { - LAGraph_Calloc ((void **) &adj_matrices, 1, sizeof (GrB_Matrix), msg) ; - n_adj_matrices = 1 ; - - GrB_Matrix adj_matrix_a; - GrB_Matrix_new(&adj_matrix_a, GrB_BOOL, 3, 3); - - OK(GrB_Matrix_setElement(adj_matrix_a, true, 0, 1)); - OK(GrB_Matrix_setElement(adj_matrix_a, true, 1, 2)); - OK(GrB_Matrix_setElement(adj_matrix_a, true, 2, 0)); - - adj_matrices[0] = adj_matrix_a; -} - -// Graph: - -// 0 -a-> 1 -// 1 -a-> 2 -// 2 -b-> 3 -// 3 -b-> 4 -void init_graph_line() { - LAGraph_Calloc ((void **) &adj_matrices, 2, sizeof (GrB_Matrix), msg) ; - n_adj_matrices = 2 ; - - GrB_Matrix adj_matrix_a, adj_matrix_b; - GrB_Matrix_new(&adj_matrix_a, GrB_BOOL, 5, 5); - GrB_Matrix_new(&adj_matrix_b, GrB_BOOL, 5, 5); - - OK(GrB_Matrix_setElement(adj_matrix_a, true, 0, 1)); - OK(GrB_Matrix_setElement(adj_matrix_a, true, 1, 2)); - - OK(GrB_Matrix_setElement(adj_matrix_b, true, 2, 3)); - OK(GrB_Matrix_setElement(adj_matrix_b, true, 3, 4)); - - adj_matrices[0] = adj_matrix_a; - adj_matrices[1] = adj_matrix_b; -} - -// Graph: - -// 0 -a-> 0 -// 0 -b-> 1 -// 1 -c-> 2 -void init_graph_2() { - LAGraph_Calloc ((void **) &adj_matrices, 3, sizeof (GrB_Matrix), msg) ; - n_adj_matrices = 3 ; - - GrB_Matrix adj_matrix_a, adj_matrix_b, adj_matrix_c; - GrB_Matrix_new(&adj_matrix_a, GrB_BOOL, 3, 3); - GrB_Matrix_new(&adj_matrix_b, GrB_BOOL, 3, 3); - GrB_Matrix_new(&adj_matrix_c, GrB_BOOL, 3, 3); - - OK(GrB_Matrix_setElement(adj_matrix_a, true, 0, 0)); - OK(GrB_Matrix_setElement(adj_matrix_b, true, 0, 1)); - OK(GrB_Matrix_setElement(adj_matrix_c, true, 1, 2)); - - adj_matrices[0] = adj_matrix_a; - adj_matrices[1] = adj_matrix_b; - adj_matrices[2] = adj_matrix_c; -} - -// Graph: - -// 0 -a-> 1 -// 1 -a-> 0 -// 0 -b-> 0 -void init_graph_3() { - LAGraph_Calloc ((void **) &adj_matrices, 2, sizeof (GrB_Matrix), msg) ; - n_adj_matrices = 2 ; - - GrB_Matrix adj_matrix_a, adj_matrix_b; - GrB_Matrix_new(&adj_matrix_a, GrB_BOOL, 2, 2); - GrB_Matrix_new(&adj_matrix_b, GrB_BOOL, 2, 2); - - OK(GrB_Matrix_setElement(adj_matrix_a, true, 0, 1)); - OK(GrB_Matrix_setElement(adj_matrix_a, true, 1, 0)); - OK(GrB_Matrix_setElement(adj_matrix_b, true, 0, 0)); - - adj_matrices[0] = adj_matrix_a; - adj_matrices[1] = adj_matrix_b; -} - -// Graph: - -// 0 -b-> 1 -// 1 -b-> 0 -void init_graph_4() { - LAGraph_Calloc ((void **) &adj_matrices, 2, sizeof (GrB_Matrix), msg) ; - n_adj_matrices = 2 ; - - GrB_Matrix adj_matrix_a, adj_matrix_b; - GrB_Matrix_new(&adj_matrix_a, GrB_BOOL, 2, 2); - GrB_Matrix_new(&adj_matrix_b, GrB_BOOL, 2, 2); - - OK(GrB_Matrix_setElement(adj_matrix_b, true, 0, 1)); - OK(GrB_Matrix_setElement(adj_matrix_b, true, 1, 0)); - - adj_matrices[0] = adj_matrix_a; - adj_matrices[1] = adj_matrix_b; -} - -//==================== -// Tests with valid result -//==================== - -void test_CFL_reachability_cycle(void) { - setup(); - GrB_Info retval; - - init_grammar_aS(); - init_graph_one_cycle(); - init_nonterms_graphs(); - init_outputs() ; - - OK(run_algorithm()); - check_result("(0, 0) (0, 1) (0, 2) (1, 0) (1, 1) (1, 2) (2, 0) (2, 1) (2, 2)"); - - free_workspace(); - teardown(); -} - -void test_CFL_reachability_two_cycle(void) { - setup(); - GrB_Info retval; - - init_grammar_aSb(); - init_graph_double_cycle(); - init_nonterms_graphs(); - init_outputs() ; - - OK(run_algorithm()); - check_result("(0, 0) (0, 3) (1, 0) (1, 3) (2, 0) (2, 3)"); - - free_workspace(); - teardown(); -} - -void test_CFL_reachability_labels_more_than_nonterms(void) { - setup(); - GrB_Info retval; - - init_grammar_aSb(); - init_graph_2(); - init_nonterms_graphs(); - init_outputs() ; - - OK(run_algorithm()); - check_result("(0, 1)"); - - free_workspace(); - teardown(); -} - -void test_CFL_reachability_complex_grammar(void) { - setup(); - GrB_Info retval; - - init_grammar_complex(); - init_graph_1(); - init_nonterms_graphs(); - init_outputs() ; - - OK(run_algorithm()); - check_result("(0, 7) (1, 6)"); - - free_workspace(); - teardown(); -} - -void test_CFL_reachability_tree(void) { - setup(); - GrB_Info retval; - - init_grammar_aSb(); - init_graph_tree(); - init_nonterms_graphs(); - init_outputs() ; - - OK(run_algorithm()); - check_result("(0, 0) (0, 1) (0, 3) (0, 4) (1, 0) (1, 1) (1, 3) (1, 4) (2, 2) (2, 5) " - "(3, 0) (3, 1) (3, 3) (3, 4) (4, 0) (4, 1) (4, 3) (4, 4) (5, 2) (5, 5)"); - - free_workspace(); - teardown(); -} - -void test_CFL_reachability_line(void) { - setup(); - GrB_Info retval; - - init_grammar_aSb(); - init_graph_line(); - init_nonterms_graphs(); - init_outputs() ; - - OK(run_algorithm()); - check_result("(0, 4) (1, 3)"); - - free_workspace(); - teardown(); -} - -void test_CFL_reachability_two_nodes_cycle(void) { - setup(); - GrB_Info retval; - - init_grammar_aSb(); - init_graph_3(); - init_nonterms_graphs(); - init_outputs() ; - - OK(run_algorithm()); - check_result("(0, 0) (1, 0)"); - - free_workspace(); - teardown(); -} - -void test_CFL_reachability_with_empty_adj_matrix(void) { - setup(); - GrB_Info retval; - - init_grammar_aS(); - init_graph_4(); - init_nonterms_graphs(); - init_outputs() ; - - OK(run_algorithm()); - check_result("(0, 0) (1, 1)"); - - free_workspace(); - teardown(); -} - -//==================== -// Tests with invalid result -//==================== - -void test_CFL_reachability_invalid_rules(void) { - setup(); - GrB_Info retval; - - init_grammar_aSb(); - init_graph_double_cycle(); - init_outputs() ; - - // Rule [Variable -> _ B] - grammar.rules[0] = - (LAGraph_rule_WCNF){.nonterm = 0, .prod_A = -1, .prod_B = 1, .index = 0}; - check_error(GrB_INVALID_VALUE); - - // Rule [_ -> A B] - grammar.rules[0] = - (LAGraph_rule_WCNF){.nonterm = -1, .prod_A = 1, .prod_B = 2, .index = 0}; - check_error(GrB_INVALID_VALUE); - - // Rule [C -> A B], where C >= nonterms_count - grammar.rules[0] = - (LAGraph_rule_WCNF){.nonterm = 10, .prod_A = 1, .prod_B = 2, .index = 0}; - check_error(GrB_INVALID_VALUE); - - // Rule [S -> A B], where A >= nonterms_count - grammar.rules[0] = - (LAGraph_rule_WCNF){.nonterm = 0, .prod_A = 10, .prod_B = 2, .index = 0}; - check_error(GrB_INVALID_VALUE); - - // Rule [C -> t], where t >= terms_count - grammar.rules[0] = - (LAGraph_rule_WCNF){.nonterm = 0, .prod_A = 10, .prod_B = -1, .index = 0}; - check_error(GrB_INVALID_VALUE); - - free_workspace(); - teardown(); - - return; -} - -void test_CFL_reachability_null_pointers(void) { -// FIXME: this test fails when testing with CUDA: -// Test CFG_reachability_null_pointers... -// GB_cuda_get_device_count: 2, cudaError_t: 0 -// GB_cuda_init: ngpus: 2 -// Device: 0: memory: 34079899648 SMs: 80 compute: 7.0 -// Device: 1: memory: 34079899648 SMs: 80 compute: 7.0 -// CUDA_VISIBLE_DEVICES = 0,1 -// getting cuda visible devices -// Found device_id 0 -// Found device_id 1 -// devices.size is 2 -// cuda warmup 0 -// cuda warmup 0 OK -// cuda warmup 1 -// cuda warmup 1 OK -// free(): invalid pointer -// Test interrupted by SIGABRT. - - setup(); - GrB_Info retval; - - init_grammar_aSb(); - init_graph_double_cycle(); - init_outputs() ; - -// adj_matrices[0] = NULL; -// adj_matrices[1] = NULL; - GrB_free(&adj_matrices[0]); - GrB_free(&adj_matrices[1]); - - check_error(GrB_NULL_POINTER); - -// adj_matrices = NULL; - LAGraph_Free ((void **) &adj_matrices, msg); - check_error(GrB_NULL_POINTER); - - free_workspace(); - init_grammar_aSb(); - init_graph_double_cycle(); - init_outputs() ; - -// outputs = NULL; - LAGraph_Free ((void **) &outputs, msg); - check_error(GrB_NULL_POINTER); - - free_workspace(); - init_grammar_aSb(); - init_graph_double_cycle(); - init_outputs() ; - -// grammar.rules = NULL; - LAGraph_Free ((void **) &grammar.rules, msg); - check_error(GrB_NULL_POINTER); - - free_workspace(); - teardown(); - - return; -} - -TEST_LIST = {{"CFL_reachability_complex_grammar", test_CFL_reachability_complex_grammar}, - {"CFL_reachability_cycle", test_CFL_reachability_cycle}, - {"CFL_reachability_two_cycle", test_CFL_reachability_two_cycle}, - {"CFL_reachability_labels_more_than_nonterms", - test_CFL_reachability_labels_more_than_nonterms}, - {"CFL_reachability_tree", test_CFL_reachability_tree}, - {"CFL_reachability_line", test_CFL_reachability_line}, - {"CFL_reachability_two_nodes_cycle", test_CFL_reachability_two_nodes_cycle}, - {"CFG_reach_basic_invalid_rules", test_CFL_reachability_invalid_rules}, - {"test_CFL_reachability_with_empty_adj_matrix", - test_CFL_reachability_with_empty_adj_matrix}, -#if !defined(GRAPHBLAS_HAS_CUDA) - {"CFG_reachability_null_pointers", test_CFL_reachability_null_pointers}, -#endif - {NULL, NULL}}; From 94aecfbbce2117fa800943a17097cff7c26c2442 Mon Sep 17 00:00:00 2001 From: Daniel Vlasenco Date: Fri, 31 Oct 2025 16:12:09 +0300 Subject: [PATCH 104/122] fix: update nvals before reading it --- .../LAGraph_CFL_optimized_matrix_opt.c | 47 +++++++++++++++++-- 1 file changed, 43 insertions(+), 4 deletions(-) diff --git a/experimental/algorithm/LAGraph_CFL_optimized_matrix_opt.c b/experimental/algorithm/LAGraph_CFL_optimized_matrix_opt.c index 2dda2ba681..8123a70438 100644 --- a/experimental/algorithm/LAGraph_CFL_optimized_matrix_opt.c +++ b/experimental/algorithm/LAGraph_CFL_optimized_matrix_opt.c @@ -100,6 +100,7 @@ GrB_Info matrix_clear_empty(Matrix *A, int8_t optimizations) { return matrix_clear_format(A, optimizations); } + CFL_matrix_update(A); if (A->nvals == 0) { return GrB_SUCCESS; } @@ -127,6 +128,8 @@ GrB_Info matrix_dup_format(Matrix *output, Matrix *input, int8_t optimizations) } if (!output->is_both) { + CFL_matrix_update(output); + CFL_matrix_update(input); Matrix *larger = output->nvals > input->nvals ? output : input; matrix_to_format(output, larger->format, false); @@ -151,6 +154,7 @@ GrB_Info matrix_dup_empty(Matrix *output, Matrix *input, int8_t optimizations) { return matrix_dup_format(output, input, optimizations); } + CFL_matrix_update(input); if (input->nvals == 0) { return matrix_clear_empty(output, optimizations); } @@ -197,6 +201,8 @@ GrB_Info block_matrix_hyper_rotate_i(Matrix *matrix, enum CFL_Matrix_block forma GrB_Scalar_new(&scalar_true, GrB_BOOL); GrB_Scalar_setElement_BOOL(scalar_true, true); + CFL_matrix_update(matrix); + if (matrix->block_type == VEC_VERT) { // fix: change to lagraph malloc GrB_Index *nrows = malloc(matrix->nvals * sizeof(GrB_Index)); @@ -254,6 +260,8 @@ void block_matrix_to_diag(Matrix *diag, Matrix *input) { GrB_Scalar_new(&scalar_true, GrB_BOOL); GrB_Scalar_setElement_BOOL(scalar_true, true); + CFL_matrix_update(input); + GrB_Index *rows = malloc(input->nvals * sizeof(GrB_Index)); GrB_Index *cols = malloc(input->nvals * sizeof(GrB_Index)); GrB_Matrix_extractTuples_BOOL(rows, cols, NULL, &input->nvals, input->base); @@ -286,6 +294,8 @@ void block_matrix_reduce(Matrix *matrix, Matrix *input, int8_t optimizations) { GrB_Scalar_new(&scalar_true, GrB_BOOL); GrB_Scalar_setElement_BOOL(scalar_true, true); + CFL_matrix_update(input); + GrB_Index *rows = malloc(input->nvals * sizeof(GrB_Index)); GrB_Index *cols = malloc(input->nvals * sizeof(GrB_Index)); GrB_Matrix_extractTuples_BOOL(rows, cols, NULL, &input->nvals, input->base); @@ -329,9 +339,12 @@ GrB_Info matrix_wise_empty(Matrix *output, Matrix *first, Matrix *second, bool a GrB_Info matrix_sort_lazy(Matrix *A, bool reverse) { for (size_t i = 0; i < A->base_matrices_count; i++) { for (size_t j = i + 1; j < A->base_matrices_count; j++) { - Matrix first = reverse ? A->base_matrices[i] : A->base_matrices[j]; - Matrix second = reverse ? A->base_matrices[j] : A->base_matrices[i]; - if (first.nvals < second.nvals) { + Matrix *first = reverse ? &A->base_matrices[i] : &A->base_matrices[j]; + Matrix *second = reverse ? &A->base_matrices[j] : &A->base_matrices[i]; + CFL_matrix_update(first); + CFL_matrix_update(second); + + if (first->nvals < second->nvals) { Matrix temp = A->base_matrices[i]; A->base_matrices[i] = A->base_matrices[j]; A->base_matrices[j] = temp; @@ -363,6 +376,7 @@ GrB_Info matrix_combine_lazy(Matrix *A, size_t threshold, int8_t optimizations) matrix_sort_lazy(A, false); for (size_t i = 0; i < A->base_matrices_count; i++) { + CFL_matrix_update(&A->base_matrices[i]); if (new_size == 0 || A->base_matrices[i].nvals > threshold) { new_matrices[new_size++] = A->base_matrices[i]; continue; @@ -381,7 +395,6 @@ GrB_Info matrix_combine_lazy(Matrix *A, size_t threshold, int8_t optimizations) } // create and update methods - void CFL_matrix_update(Matrix *matrix) { if (!matrix->is_lazy) { GrB_Matrix_nvals(&matrix->nvals, matrix->base); @@ -483,6 +496,8 @@ GrB_Info matrix_mxm_format(Matrix *output, Matrix *first, Matrix *second, bool a return matrix_mxm(output, first, second, accum, swap); } + CFL_matrix_update(first); + CFL_matrix_update(second); GrB_Index left_nvals = swap ? second->nvals : first->nvals; GrB_Index right_nvals = swap ? first->nvals : second->nvals; @@ -507,11 +522,15 @@ GrB_Info matrix_mxm_empty(Matrix *output, Matrix *first, Matrix *second, bool ac return matrix_mxm_format(output, first, second, accum, swap, optimizations); } + CFL_matrix_update(first); + CFL_matrix_update(second); + if (first->nvals == 0 || second->nvals == 0) { if (accum) { return GrB_SUCCESS; } + CFL_matrix_update(output); if (output->nvals == 0) { return GrB_SUCCESS; } @@ -532,6 +551,8 @@ GrB_Info matrix_mxm_lazy(Matrix *output, Matrix *first, Matrix *second, bool acc return matrix_mxm_empty(output, first, second, accum, swap, optimizations); } + CFL_matrix_update(second); + matrix_combine_lazy(first, second->nvals, optimizations); matrix_sort_lazy(first, false); @@ -549,7 +570,9 @@ GrB_Info matrix_mxm_lazy(Matrix *output, Matrix *first, Matrix *second, bool acc } for (size_t i = 0; i < first->base_matrices_count; i++) { + CFL_matrix_update(&acc_matrices[i]); for (size_t j = i + 1; j < first->base_matrices_count; j++) { + CFL_matrix_update(&acc_matrices[j]); if (acc_matrices[i].nvals > acc_matrices[j].nvals) { Matrix temp = acc_matrices[i]; acc_matrices[i] = acc_matrices[j]; @@ -654,6 +677,10 @@ GrB_Info matrix_wise_format(Matrix *output, Matrix *first, Matrix *second, bool } if (!output->is_both) { + CFL_matrix_update(output); + CFL_matrix_update(first); + CFL_matrix_update(second); + Matrix *larger = output->nvals > first->nvals ? output : first; larger = larger->nvals > second->nvals ? larger : second; @@ -685,6 +712,10 @@ GrB_Info matrix_wise_empty(Matrix *output, Matrix *first, Matrix *second, bool a return matrix_wise_format(output, first, second, accum, optimizations); } + CFL_matrix_update(first); + CFL_matrix_update(second); + CFL_matrix_update(output); + if (output == first) { if (first->nvals == 0) { return matrix_dup_empty(first, second, optimizations); @@ -754,6 +785,7 @@ GrB_Info matrix_wise_lazy(Matrix *output, Matrix *first, Matrix *second, bool ac bool found = false; for (size_t i = 0; i < first->base_matrices_count; i++) { + CFL_matrix_update(&first->base_matrices[i]); size_t self_nvals = first->base_matrices[i].nvals >= 10 ? first->base_matrices[i].nvals : 10; @@ -846,6 +878,9 @@ GrB_Info matrix_rsub_format(Matrix *output, Matrix *mask, int8_t optimizations) return matrix_rsub(output, mask); } + CFL_matrix_update(output); + CFL_matrix_update(mask); + Matrix *larger_matrix = output->nvals > mask->nvals ? output : mask; matrix_to_format(output, larger_matrix->format, false); matrix_to_format(mask, larger_matrix->format, false); @@ -872,6 +907,8 @@ GrB_Info matrix_rsub_empty(Matrix *output, Matrix *mask, int8_t optimizations) { return matrix_rsub_format(output, mask, optimizations); } + CFL_matrix_update(mask); + CFL_matrix_update(output); if (mask->nvals == 0 || output->nvals == 0) { return GrB_SUCCESS; } @@ -888,6 +925,7 @@ GrB_Info matrix_rsub_lazy(Matrix *output, Matrix *mask, int8_t optimizations) { return matrix_rsub_empty(output, mask, optimizations); } + CFL_matrix_update(output); matrix_combine_lazy(mask, output->nvals, optimizations); matrix_sort_lazy(mask, true); @@ -946,6 +984,7 @@ GrB_Info matrix_rsub_block(Matrix *output, Matrix *mask, int8_t optimizations) { // A = &temp; // GxB_print(A->base, pr); +// CFL_matrix_update(A); // // printf("nnz: %ld\n", A->nvals); // GrB_free(&_temp); // } From 89756bf9cfc4d726db2656af57894a6bae8fd652 Mon Sep 17 00:00:00 2001 From: homka122 Date: Thu, 23 Oct 2025 01:34:30 +0300 Subject: [PATCH 105/122] test: add tests for optimized matrix --- .../test/test_CFL_optimized_matrix_opt.c | 168 ++++++++++++++++++ 1 file changed, 168 insertions(+) create mode 100644 experimental/test/test_CFL_optimized_matrix_opt.c diff --git a/experimental/test/test_CFL_optimized_matrix_opt.c b/experimental/test/test_CFL_optimized_matrix_opt.c new file mode 100644 index 0000000000..5d86fe468c --- /dev/null +++ b/experimental/test/test_CFL_optimized_matrix_opt.c @@ -0,0 +1,168 @@ +//------------------------------------------------------------------------------ +// LAGraph/experimental/test/LAGraph_CFL_reachability.c: test cases for +// operations for Optimized Context-Free Language Reachability Matrix-Based +// Algorithm +//------------------------------------------------------------------------------ +// +// LAGraph, (c) 2019-2024 by The LAGraph Contributors, All Rights Reserved. +// SPDX-License-Identifier: BSD-2-Clause + +// Contributed by Ilhom Kombaev, Semyon Grigoriev, St. Petersburg State +// University. + +//------------------------------------------------------------------------------ + +#include +#include +#include +#include +#include +#include + +#define OPT_EMPTY (1 << 0) +#define OPT_FORMAT (1 << 1) +#define OPT_LAZY (1 << 2) +#define OPT_BLOCK (1 << 3) + +#define OPT_N_FLAGS 16 + +char msg[LAGRAPH_MSG_LEN]; + +typedef CFL_Matrix Matrix; +typedef enum CFL_Matrix_block Matrix_block; + +//------------------------------------------------------------------------------ +// helpers +//------------------------------------------------------------------------------ + +static void setup(void) { OK(LAGraph_Init(msg)); } + +static void teardown(void) { OK(LAGraph_Finalize(msg)); } + +// 0 1 .. +// 1 0 .. +// .. .. .. +static Matrix make_simple_matrix(int n) { + GrB_Matrix A; + OK(GrB_Matrix_new(&A, GrB_BOOL, n, n)); + OK(GrB_Matrix_setElement_BOOL(A, true, 0, 1)); + OK(GrB_Matrix_setElement_BOOL(A, true, 1, 0)); + Matrix M = CFL_matrix_from_base(A); + return M; +} + +static void free_matrix(Matrix *M) { CFL_matrix_free(M); } + +//------------------------------------------------------------------------------ +// Сreation and Free +//------------------------------------------------------------------------------ + +static void test_CFL_create_free(void) { +#if LAGRAPH_SUITESPARSE + setup(); + + CFL_Matrix A = CFL_matrix_create(4, 4); + TEST_CHECK(A.nrows == 4); + TEST_CHECK(A.ncols == 4); + TEST_CHECK(A.base != NULL); + + CFL_matrix_free(&A); + TEST_CHECK(A.base == NULL); + + teardown(); +#endif +} + +//------------------------------------------------------------------------------ +// Multiplication +//------------------------------------------------------------------------------ + +static void test_CFL_mxm(void) { +#if LAGRAPH_SUITESPARSE + setup(); + + for (int mask = 0; mask < OPT_N_FLAGS; mask++) { + Matrix A = make_simple_matrix(2); + Matrix B = make_simple_matrix(2); + Matrix C = CFL_matrix_create(2, 2); + + GrB_Info info = CFL_mxm(&C, &A, &B, false, false, mask); + TEST_CHECK(info == GrB_SUCCESS); + TEST_MSG("matrix_mxm_opt failed for mask=%d", mask); + + // Validate result (A*B should have two true element) + GrB_Index nvals = 0; + OK(GrB_Matrix_nvals(&nvals, C.base)); + TEST_CHECK(nvals == 2); + TEST_CHECK(C.nvals == 2); + TEST_MSG("Unexpected empty result, mask=%d", mask); + + free_matrix(&A); + free_matrix(&B); + free_matrix(&C); + } + + teardown(); +#endif +} + +//------------------------------------------------------------------------------ +// Clear +//------------------------------------------------------------------------------ + +static void test_CFL_clear(void) { +#if LAGRAPH_SUITESPARSE + setup(); + + for (int mask = 0; mask < OPT_N_FLAGS; mask++) { + Matrix A = make_simple_matrix(3); + + // Clear nonempty matrix + CFL_clear(&A, mask); + GrB_Index nvals; + TEST_CHECK(A.nvals == 0); + + free_matrix(&A); + } + + teardown(); +#endif +} + +//------------------------------------------------------------------------------ +// Duplicate +//------------------------------------------------------------------------------ + +static void test_CFL_dup(void) { +#if LAGRAPH_SUITESPARSE + setup(); + + for (int mask = 0; mask < OPT_N_FLAGS; mask++) { + CFL_Matrix A = make_simple_matrix(3); + CFL_Matrix B = CFL_matrix_create(3, 3); + + OK(CFL_dup(&A, &B, OPT_FORMAT)); + + GrB_Index nvals_A, nvals_B; + OK(GrB_Matrix_nvals(&nvals_A, A.base)); + OK(GrB_Matrix_nvals(&nvals_B, B.base)); + + TEST_CHECK(nvals_A == nvals_B); + TEST_CHECK(A.nvals == B.nvals); + free_matrix(&A); + free_matrix(&B); + } + + teardown(); +#endif +} + +//------------------------------------------------------------------------------ +// TEST LIST +//------------------------------------------------------------------------------ + +TEST_LIST = {{"test CFL create and free", test_CFL_create_free}, + {"test CFL mxm", test_CFL_mxm}, + {"test CFL clear", test_CFL_clear}, + {"test CFL dup", test_CFL_dup}, + {NULL, NULL}}; \ No newline at end of file From aa2d64a8463e10fe178edf03e414eb90d0d0cf62 Mon Sep 17 00:00:00 2001 From: homka122 Date: Mon, 3 Nov 2025 07:08:56 +0300 Subject: [PATCH 106/122] Test: add tests for matrix_opt: wise, rsub, format optimization Signed-off-by: homka122 --- .../test/test_CFL_optimized_matrix_opt.c | 449 +++++++++++++++--- 1 file changed, 380 insertions(+), 69 deletions(-) diff --git a/experimental/test/test_CFL_optimized_matrix_opt.c b/experimental/test/test_CFL_optimized_matrix_opt.c index 5d86fe468c..0fed400092 100644 --- a/experimental/test/test_CFL_optimized_matrix_opt.c +++ b/experimental/test/test_CFL_optimized_matrix_opt.c @@ -31,6 +31,10 @@ char msg[LAGRAPH_MSG_LEN]; typedef CFL_Matrix Matrix; typedef enum CFL_Matrix_block Matrix_block; +extern GrB_Info matrix_to_format(Matrix *matrix, int32_t format, bool is_bool); +extern GrB_Info matrix_clear_format(Matrix *A, int8_t optimizations); +extern GrB_Info matrix_dup_format(Matrix *output, Matrix *input, int8_t optimizations); + //------------------------------------------------------------------------------ // helpers //------------------------------------------------------------------------------ @@ -39,16 +43,35 @@ static void setup(void) { OK(LAGraph_Init(msg)); } static void teardown(void) { OK(LAGraph_Finalize(msg)); } -// 0 1 .. -// 1 0 .. -// .. .. .. +// 0 1 .. 0 +// 1 0 .. 0 +// .. .. .. .. +// 0 0 .. 0 static Matrix make_simple_matrix(int n) { - GrB_Matrix A; - OK(GrB_Matrix_new(&A, GrB_BOOL, n, n)); - OK(GrB_Matrix_setElement_BOOL(A, true, 0, 1)); - OK(GrB_Matrix_setElement_BOOL(A, true, 1, 0)); - Matrix M = CFL_matrix_from_base(A); - return M; + GrB_Matrix A; + OK(GrB_Matrix_new(&A, GrB_BOOL, n, n)); + OK(GrB_Matrix_setElement_BOOL(A, true, 0, 1)); + OK(GrB_Matrix_setElement_BOOL(A, true, 1, 0)); + Matrix M = CFL_matrix_from_base(A); + return M; +} + +// 1 1 .. 1 +// 1 1 .. 1 +// .. .. .. .. +// 1 1 .. 1 +static Matrix make_ones_matrix(int n) { + GrB_Matrix A; + OK(GrB_Matrix_new(&A, GrB_BOOL, n, n)); + + for (size_t i = 0; i < n; i++) { + for (size_t j = 0; j < n; j++) { + OK(GrB_Matrix_setElement_BOOL(A, true, i, j)); + } + } + + Matrix M = CFL_matrix_from_base(A); + return M; } static void free_matrix(Matrix *M) { CFL_matrix_free(M); } @@ -59,17 +82,17 @@ static void free_matrix(Matrix *M) { CFL_matrix_free(M); } static void test_CFL_create_free(void) { #if LAGRAPH_SUITESPARSE - setup(); + setup(); - CFL_Matrix A = CFL_matrix_create(4, 4); - TEST_CHECK(A.nrows == 4); - TEST_CHECK(A.ncols == 4); - TEST_CHECK(A.base != NULL); + CFL_Matrix A = CFL_matrix_create(4, 4); + TEST_CHECK(A.nrows == 4); + TEST_CHECK(A.ncols == 4); + TEST_CHECK(A.base != NULL); - CFL_matrix_free(&A); - TEST_CHECK(A.base == NULL); + CFL_matrix_free(&A); + TEST_CHECK(A.base == NULL); - teardown(); + teardown(); #endif } @@ -79,30 +102,95 @@ static void test_CFL_create_free(void) { static void test_CFL_mxm(void) { #if LAGRAPH_SUITESPARSE - setup(); - - for (int mask = 0; mask < OPT_N_FLAGS; mask++) { - Matrix A = make_simple_matrix(2); - Matrix B = make_simple_matrix(2); - Matrix C = CFL_matrix_create(2, 2); - - GrB_Info info = CFL_mxm(&C, &A, &B, false, false, mask); - TEST_CHECK(info == GrB_SUCCESS); - TEST_MSG("matrix_mxm_opt failed for mask=%d", mask); - - // Validate result (A*B should have two true element) - GrB_Index nvals = 0; - OK(GrB_Matrix_nvals(&nvals, C.base)); - TEST_CHECK(nvals == 2); - TEST_CHECK(C.nvals == 2); - TEST_MSG("Unexpected empty result, mask=%d", mask); - - free_matrix(&A); - free_matrix(&B); - free_matrix(&C); - } - - teardown(); + setup(); + + for (int mask = 0; mask < OPT_N_FLAGS; mask++) { + Matrix A = make_simple_matrix(2); + Matrix B = make_simple_matrix(2); + matrix_to_format(&A, GrB_ROWMAJOR, true); + Matrix C = CFL_matrix_create(2, 2); + + GrB_Info info = CFL_mxm(&C, &A, &B, false, false, mask); + TEST_CHECK(info == GrB_SUCCESS); + TEST_MSG("matrix_mxm_opt failed for mask=%d", mask); + + // Validate result (A*B should have two true element) + GrB_Index nvals = 0; + OK(GrB_Matrix_nvals(&nvals, C.base)); + TEST_CHECK(nvals == 2); + TEST_CHECK(C.nvals == 2); + TEST_MSG("Unexpected empty result, mask=%d", mask); + + free_matrix(&A); + free_matrix(&B); + free_matrix(&C); + } + + teardown(); +#endif +} + +//------------------------------------------------------------------------------ +// Wise +//------------------------------------------------------------------------------ + +static void test_CFL_wise(void) { +#if LAGRAPH_SUITESPARSE + setup(); + + for (int mask = 0; mask < OPT_N_FLAGS; mask++) { + Matrix A = make_simple_matrix(2); + Matrix B = make_simple_matrix(2); + matrix_to_format(&A, GrB_ROWMAJOR, true); + + GrB_Info info = CFL_wise(&A, &A, &B, false, mask); + TEST_CHECK(info == GrB_SUCCESS); + TEST_MSG("matrix_wise failed for mask=%d", mask); + + // Validate result (A+B should have two true element) + GrB_Index nvals = 0; + OK(GrB_Matrix_nvals(&nvals, A.base)); + TEST_CHECK(nvals == 2); + TEST_CHECK(A.nvals == 2); + TEST_MSG("Unexpected empty result, mask=%d", mask); + + free_matrix(&A); + free_matrix(&B); + } + + teardown(); +#endif +} + +//------------------------------------------------------------------------------ +// Rsub +//------------------------------------------------------------------------------ + +static void test_CFL_rsub(void) { +#if LAGRAPH_SUITESPARSE + setup(); + + for (int mask = 0; mask < OPT_N_FLAGS; mask++) { + Matrix A = make_simple_matrix(2); + Matrix B = make_simple_matrix(2); + matrix_to_format(&A, GrB_ROWMAJOR, true); + + GrB_Info info = CFL_rsub(&A, &B, mask); + TEST_CHECK(info == GrB_SUCCESS); + TEST_MSG("matrix_rsub failed for mask=%d", mask); + + // Validate result (A-B should have zero true element) + GrB_Index nvals = 0; + OK(GrB_Matrix_nvals(&nvals, A.base)); + TEST_CHECK(nvals == 0); + TEST_CHECK(A.nvals == 0); + TEST_MSG("Unexpected non-empty result, mask=%d", mask); + + free_matrix(&A); + free_matrix(&B); + } + + teardown(); #endif } @@ -112,20 +200,20 @@ static void test_CFL_mxm(void) { static void test_CFL_clear(void) { #if LAGRAPH_SUITESPARSE - setup(); + setup(); - for (int mask = 0; mask < OPT_N_FLAGS; mask++) { - Matrix A = make_simple_matrix(3); + for (int mask = 0; mask < OPT_N_FLAGS; mask++) { + Matrix A = make_simple_matrix(3); - // Clear nonempty matrix - CFL_clear(&A, mask); - GrB_Index nvals; - TEST_CHECK(A.nvals == 0); + // Clear nonempty matrix + CFL_clear(&A, mask); + GrB_Index nvals; + TEST_CHECK(A.nvals == 0); - free_matrix(&A); - } + free_matrix(&A); + } - teardown(); + teardown(); #endif } @@ -135,25 +223,238 @@ static void test_CFL_clear(void) { static void test_CFL_dup(void) { #if LAGRAPH_SUITESPARSE - setup(); + setup(); + + for (int mask = 0; mask < OPT_N_FLAGS; mask++) { + CFL_Matrix A = make_simple_matrix(3); + CFL_Matrix B = CFL_matrix_create(3, 3); + + OK(CFL_dup(&A, &B, OPT_FORMAT)); + + GrB_Index nvals_A, nvals_B; + OK(GrB_Matrix_nvals(&nvals_A, A.base)); + OK(GrB_Matrix_nvals(&nvals_B, B.base)); + + TEST_CHECK(nvals_A == nvals_B); + TEST_CHECK(A.nvals == B.nvals); + free_matrix(&A); + free_matrix(&B); + } + + teardown(); +#endif +} + +//------------------------------------------------------------------------------ +// Format optimization +//------------------------------------------------------------------------------ + +static void test_CFL_format_create_rowmajor_matrix(void) { +#if LAGRAPH_SUITESPARSE + setup(); + + Matrix A = make_simple_matrix(5); + TEST_CHECK(A.is_both == false); + TEST_CHECK(A.base_col == NULL); + TEST_CHECK(A.base_row != NULL); + TEST_CHECK(A.base == A.base_row); + TEST_CHECK(A.format == GrB_ROWMAJOR); + + CFL_matrix_free(&A); + + teardown(); +#endif +} + +static void test_CFL_format_to_format(void) { +#if LAGRAPH_SUITESPARSE + setup(); + + Matrix A = make_simple_matrix(5); + + // same + OK(matrix_to_format(&A, GrB_ROWMAJOR, false)); + TEST_CHECK(A.is_both == false); + TEST_CHECK(A.base_col == NULL); + TEST_CHECK(A.base_row != NULL); + TEST_CHECK(A.base == A.base_row); + TEST_CHECK(A.format == GrB_ROWMAJOR); + + // switch to another + OK(matrix_to_format(&A, GrB_COLMAJOR, false)); + TEST_CHECK(A.is_both == false); + TEST_CHECK(A.base_col != NULL); + TEST_CHECK(A.base_row == NULL); + TEST_CHECK(A.base == A.base_col); + TEST_CHECK(A.format == GrB_COLMAJOR); + + // create both matrices, same format + OK(matrix_to_format(&A, GrB_COLMAJOR, true)); + TEST_CHECK(A.is_both == false); + TEST_CHECK(A.base_col != NULL); + TEST_CHECK(A.base_row == NULL); + TEST_CHECK(A.base == A.base_col); + TEST_CHECK(A.format == GrB_COLMAJOR); + + // switch to another, both + OK(matrix_to_format(&A, GrB_ROWMAJOR, true)); + TEST_CHECK(A.is_both == true); + TEST_CHECK(A.base_col != NULL); + TEST_CHECK(A.base_row != NULL); + TEST_CHECK(A.base == A.base_row); + TEST_CHECK(A.format == GrB_ROWMAJOR); + + // switch to another, when matrix already in both state + OK(matrix_to_format(&A, GrB_COLMAJOR, true)); + TEST_CHECK(A.is_both == true); + TEST_CHECK(A.base_col != NULL); + TEST_CHECK(A.base_row != NULL); + TEST_CHECK(A.base == A.base_col); + TEST_CHECK(A.format == GrB_COLMAJOR); + + CFL_matrix_free(&A); + + teardown(); +#endif +} + +static void test_CFL_format_clear_format(void) { +#if LAGRAPH_SUITESPARSE + setup(); + + Matrix A = make_simple_matrix(5); + + // create matrix in both state + OK(matrix_to_format(&A, GrB_COLMAJOR, true)); + OK(matrix_clear_format(&A, OPT_FORMAT)); + + TEST_CHECK(A.nvals == 0); + + // NULL Matrix + GrB_Matrix old_base = A.base; + GrB_Matrix old_base_row = A.base; + A.base = NULL; + A.base_row = NULL; + GrB_Info result = matrix_clear_format(&A, OPT_FORMAT); + OK(!result); + + A.base = old_base; + A.base_row = old_base_row; + CFL_matrix_free(&A); - for (int mask = 0; mask < OPT_N_FLAGS; mask++) { - CFL_Matrix A = make_simple_matrix(3); - CFL_Matrix B = CFL_matrix_create(3, 3); + teardown(); +#endif +} - OK(CFL_dup(&A, &B, OPT_FORMAT)); +static void test_CFL_format_dup_format(void) { +#if LAGRAPH_SUITESPARSE + setup(); - GrB_Index nvals_A, nvals_B; - OK(GrB_Matrix_nvals(&nvals_A, A.base)); - OK(GrB_Matrix_nvals(&nvals_B, B.base)); + Matrix A = make_simple_matrix(5); + Matrix B = CFL_matrix_create(5, 5); + + // create matrix in both state + OK(matrix_to_format(&A, GrB_COLMAJOR, true)); + OK(matrix_dup_format(&A, &B, OPT_FORMAT)); - TEST_CHECK(nvals_A == nvals_B); TEST_CHECK(A.nvals == B.nvals); - free_matrix(&A); - free_matrix(&B); - } + TEST_CHECK(A.base != B.base); + + GrB_Index nvals_A = A.nvals; + GrB_Index nvals_B = B.nvals; + + GrB_Index *rows_A = malloc(nvals_A * sizeof(GrB_Index)); + GrB_Index *cols_A = malloc(nvals_A * sizeof(GrB_Index)); + bool *vals_A = malloc(nvals_A * sizeof(bool)); + + GrB_Index *rows_B = malloc(nvals_B * sizeof(GrB_Index)); + GrB_Index *cols_B = malloc(nvals_B * sizeof(GrB_Index)); + bool *vals_B = malloc(nvals_B * sizeof(bool)); + + GrB_Matrix_extractTuples_BOOL(rows_A, cols_A, vals_A, &nvals_A, A.base); + GrB_Matrix_extractTuples_BOOL(rows_B, cols_B, vals_B, &nvals_B, B.base); + + bool equal = true; + for (GrB_Index i = 0; i < nvals_A; i++) { + bool found = false; + for (GrB_Index j = 0; j < nvals_B; j++) { + if (rows_A[i] == rows_B[j] && cols_A[i] == cols_B[j] && + vals_A[i] == vals_B[j]) { + found = true; + break; + } + } + if (!found) { + equal = false; + break; + } + } + TEST_CHECK(equal); + + // NULL Matrix + GrB_Matrix old_base = A.base; + GrB_Matrix old_base_row = A.base; + A.base = NULL; + A.base_row = NULL; + GrB_Info result = matrix_dup_format(&A, &B, OPT_FORMAT); + OK(!result); + + A.base = old_base; + A.base_row = old_base_row; + CFL_matrix_free(&A); + CFL_matrix_free(&B); + + // Without optimization flag + A = make_simple_matrix(5); + B = CFL_matrix_create(5, 5); + OK(matrix_to_format(&A, GrB_COLMAJOR, true)); + OK(matrix_dup_format(&A, &B, 0)); + + teardown(); +#endif +} + +static void test_CFL_format_mxm_second_greather_then_k(void) { +#if LAGRAPH_SUITESPARSE + setup(); + + Matrix A = CFL_matrix_create(5, 5); + Matrix B = make_ones_matrix(5); + Matrix C = CFL_matrix_create(5, 5); + + OK(matrix_to_format(&A, GrB_COLMAJOR, false)); + OK(CFL_mxm(&C, &A, &B, false, false, OPT_FORMAT)); + TEST_CHECK(C.nvals == 0); + + teardown(); +#endif +} + +static void test_CFL_format_wise_when_both(void) { +#if LAGRAPH_SUITESPARSE + setup(); + + Matrix A = CFL_matrix_create(5, 5); + Matrix B = make_ones_matrix(5); + + OK(matrix_to_format(&A, GrB_COLMAJOR, true)); + OK(CFL_wise(&A, &A, &B, false, OPT_FORMAT)); + TEST_CHECK(A.nvals == 25); + + // NULL Matrix + GrB_Matrix old_base = A.base; + GrB_Matrix old_base_row = A.base; + A.base = NULL; + A.base_row = NULL; + GrB_Info result = CFL_wise(&A, &A, &B, false, OPT_FORMAT); + A.base = old_base; + A.base_row = old_base_row; + OK(!result); + + CFL_matrix_free(&A); + CFL_matrix_free(&B); - teardown(); + teardown(); #endif } @@ -161,8 +462,18 @@ static void test_CFL_dup(void) { // TEST LIST //------------------------------------------------------------------------------ -TEST_LIST = {{"test CFL create and free", test_CFL_create_free}, - {"test CFL mxm", test_CFL_mxm}, - {"test CFL clear", test_CFL_clear}, - {"test CFL dup", test_CFL_dup}, - {NULL, NULL}}; \ No newline at end of file +TEST_LIST = { + {"test CFL create and free", test_CFL_create_free}, + {"test CFL mxm", test_CFL_mxm}, + {"test CFL clear", test_CFL_clear}, + {"test CFL dup", test_CFL_dup}, + {"test_CFL_wise", test_CFL_wise}, + {"test_CFL_rsub", test_CFL_rsub}, + {"test_CFL_format_create_rowmajor_matrix", test_CFL_format_create_rowmajor_matrix}, + {"test_CFL_format_to_format", test_CFL_format_to_format}, + {"test_CFL_format_clear_format", test_CFL_format_clear_format}, + {"test_CFL_format_dup_format", test_CFL_format_dup_format}, + {"test_CFL_format_wise_when_both", test_CFL_format_wise_when_both}, + {"test_CFL_format_mxm_second_greather_then_k", + test_CFL_format_mxm_second_greather_then_k}, + {NULL, NULL}}; \ No newline at end of file From ae1daffb5cea82081bf144ea65494200397062fa Mon Sep 17 00:00:00 2001 From: homka122 Date: Mon, 3 Nov 2025 07:54:48 +0300 Subject: [PATCH 107/122] Test: add tests for matrix_opt: empty optimization --- .../test/test_CFL_optimized_matrix_opt.c | 191 +++++++++++++++++- 1 file changed, 190 insertions(+), 1 deletion(-) diff --git a/experimental/test/test_CFL_optimized_matrix_opt.c b/experimental/test/test_CFL_optimized_matrix_opt.c index 0fed400092..7473c849fa 100644 --- a/experimental/test/test_CFL_optimized_matrix_opt.c +++ b/experimental/test/test_CFL_optimized_matrix_opt.c @@ -35,6 +35,12 @@ extern GrB_Info matrix_to_format(Matrix *matrix, int32_t format, bool is_bool); extern GrB_Info matrix_clear_format(Matrix *A, int8_t optimizations); extern GrB_Info matrix_dup_format(Matrix *output, Matrix *input, int8_t optimizations); +// extern GrB_Info matrix_clear_empty(Matrix *A, int8_t optimizations); +// extern GrB_Info matrix_mxm_empty(Matrix *output, Matrix *first, Matrix *second, +// bool accum, bool swap, int8_t optimizations); +// extern GrB_Info matrix_wise_empty(Matrix *output, Matrix *first, Matrix *second, +// bool accum, int8_t optimizations); + //------------------------------------------------------------------------------ // helpers //------------------------------------------------------------------------------ @@ -229,7 +235,7 @@ static void test_CFL_dup(void) { CFL_Matrix A = make_simple_matrix(3); CFL_Matrix B = CFL_matrix_create(3, 3); - OK(CFL_dup(&A, &B, OPT_FORMAT)); + OK(CFL_dup(&A, &B, mask)); GrB_Index nvals_A, nvals_B; OK(GrB_Matrix_nvals(&nvals_A, A.base)); @@ -245,6 +251,19 @@ static void test_CFL_dup(void) { #endif } +static void test_CFL_dup_same(void) { +#if LAGRAPH_SUITESPARSE + setup(); + + CFL_Matrix A = make_simple_matrix(3); + OK(CFL_dup(&A, &A, 0)); + + free_matrix(&A); + + teardown(); +#endif +} + //------------------------------------------------------------------------------ // Format optimization //------------------------------------------------------------------------------ @@ -458,6 +477,170 @@ static void test_CFL_format_wise_when_both(void) { #endif } +//------------------------------------------------------------------------------ +// Empty optimization +//------------------------------------------------------------------------------ + +static void test_CFL_empty_clear_empty_matrix(void) { +#if LAGRAPH_SUITESPARSE + setup(); + + Matrix A = CFL_matrix_create(5, 5); + + OK(CFL_clear(&A, OPT_EMPTY)); + TEST_CHECK(A.nvals == 0); + + CFL_matrix_free(&A); + + teardown(); +#endif +} + +static void test_CFL_empty_dup(void) { +#if LAGRAPH_SUITESPARSE + setup(); + + Matrix A = CFL_matrix_create(5, 5); + Matrix B = make_ones_matrix(5); + + OK(CFL_dup(&A, &B, OPT_EMPTY)); + TEST_CHECK(A.nvals == 25); + + CFL_matrix_free(&A); + CFL_matrix_free(&B); + + teardown(); +#endif +} + +static void test_CFL_empty_mxm_one_is_empty(void) { +#if LAGRAPH_SUITESPARSE + setup(); + + Matrix A, B, C; + + // accum + A = CFL_matrix_create(5, 5); + B = make_ones_matrix(5); + C = make_ones_matrix(5); + + OK(CFL_mxm(&C, &A, &B, true, false, OPT_EMPTY)); + TEST_CHECK(C.nvals == 25); + + CFL_matrix_free(&A); + CFL_matrix_free(&B); + CFL_matrix_free(&C); + + // without accum + A = CFL_matrix_create(5, 5); + B = make_ones_matrix(5); + C = make_ones_matrix(5); + + OK(CFL_mxm(&C, &A, &B, false, false, OPT_EMPTY)); + TEST_CHECK(C.nvals == 0); + + CFL_matrix_free(&A); + CFL_matrix_free(&B); + CFL_matrix_free(&C); + + // output empty + A = CFL_matrix_create(5, 5); + B = make_ones_matrix(5); + C = CFL_matrix_create(5, 5); + + OK(CFL_mxm(&C, &A, &B, false, false, OPT_EMPTY)); + TEST_CHECK(C.nvals == 0); + + CFL_matrix_free(&A); + CFL_matrix_free(&B); + CFL_matrix_free(&C); + + teardown(); +#endif +} + +// wise(C, A, B, accum) +// matrix may be empty and full +// we have 16 states +static void test_CFL_empty_wise(void) { +#if LAGRAPH_SUITESPARSE + setup(); + + Matrix A, B, C; + + for (size_t is_first_empty = 0; is_first_empty < 2; is_first_empty++) { + for (size_t is_second_empty = 0; is_second_empty < 2; is_second_empty++) { + for (size_t is_output_empty = 0; is_output_empty < 2; is_output_empty++) { + for (size_t is_accum = 0; is_accum < 2; is_accum++) { + A = is_first_empty ? CFL_matrix_create(5, 5) : make_ones_matrix(5); + B = is_second_empty ? CFL_matrix_create(5, 5) : make_ones_matrix(5); + C = is_output_empty ? CFL_matrix_create(5, 5) : make_ones_matrix(5); + + CFL_wise(&C, &A, &B, is_accum, OPT_EMPTY); + + TEST_CHECK(A.nvals == (is_first_empty ? 0 : 25)); + TEST_CHECK(B.nvals == (is_second_empty ? 0 : 25)); + + if (is_first_empty && is_second_empty) { + if (!is_accum) { + TEST_CHECK(C.nvals == 0); + } else { + TEST_CHECK(C.nvals == (is_output_empty ? 0 : 25)); + } + } else { + TEST_CHECK(C.nvals == 25); + } + + CFL_matrix_free(&A); + CFL_matrix_free(&B); + CFL_matrix_free(&C); + } + } + } + } + + // if output equal first argument (iadd) + for (size_t is_first_empty = 0; is_first_empty < 2; is_first_empty++) { + for (size_t is_second_empty = 0; is_second_empty < 2; is_second_empty++) { + for (size_t is_accum = 0; is_accum < 2; is_accum++) { + A = is_first_empty ? CFL_matrix_create(5, 5) : make_ones_matrix(5); + B = is_second_empty ? CFL_matrix_create(5, 5) : make_ones_matrix(5); + + CFL_wise(&A, &A, &B, is_accum, OPT_EMPTY); + + TEST_CHECK(B.nvals == (is_second_empty ? 0 : 25)); + + if (is_second_empty) { + TEST_CHECK(A.nvals == (is_first_empty ? 0 : 25)); + } else { + TEST_CHECK(A.nvals == 25); + } + + CFL_matrix_free(&A); + CFL_matrix_free(&B); + } + } + } + + teardown(); +#endif +} + +static void test_CFL_empty_rsub_both_empty(void) { +#if LAGRAPH_SUITESPARSE + setup(); + + Matrix A, B; + A = CFL_matrix_create(5, 5); + B = CFL_matrix_create(5, 5); + + OK(CFL_rsub(&A, &B, OPT_EMPTY)); + TEST_CHECK(A.nvals == 0); + + teardown(); +#endif +} + //------------------------------------------------------------------------------ // TEST LIST //------------------------------------------------------------------------------ @@ -467,6 +650,7 @@ TEST_LIST = { {"test CFL mxm", test_CFL_mxm}, {"test CFL clear", test_CFL_clear}, {"test CFL dup", test_CFL_dup}, + {"test_CFL_dup_same", test_CFL_dup_same}, {"test_CFL_wise", test_CFL_wise}, {"test_CFL_rsub", test_CFL_rsub}, {"test_CFL_format_create_rowmajor_matrix", test_CFL_format_create_rowmajor_matrix}, @@ -476,4 +660,9 @@ TEST_LIST = { {"test_CFL_format_wise_when_both", test_CFL_format_wise_when_both}, {"test_CFL_format_mxm_second_greather_then_k", test_CFL_format_mxm_second_greather_then_k}, + {"test_CFL_empty_clear_empty_matrix", test_CFL_empty_clear_empty_matrix}, + {"test_CFL_empty_dup", test_CFL_empty_dup}, + {"test_CFL_empty_mxm_one_is_empty", test_CFL_empty_mxm_one_is_empty}, + {"test_CFL_empty_wise", test_CFL_empty_wise}, + {"test_CFL_empty_rsub_both_empty", test_CFL_empty_rsub_both_empty}, {NULL, NULL}}; \ No newline at end of file From 39bf9da04574a622584843dcf2d63d134ad004b8 Mon Sep 17 00:00:00 2001 From: homka122 Date: Mon, 3 Nov 2025 21:08:44 +0300 Subject: [PATCH 108/122] Refactor: now matrix_to_base don't modify input matrix --- .../LAGraph_CFL_optimized_matrix_opt.c | 32 ++++++++++++------- include/LAGraphX.h | 18 ++++++++++- 2 files changed, 37 insertions(+), 13 deletions(-) diff --git a/experimental/algorithm/LAGraph_CFL_optimized_matrix_opt.c b/experimental/algorithm/LAGraph_CFL_optimized_matrix_opt.c index 8123a70438..d66c30f3c9 100644 --- a/experimental/algorithm/LAGraph_CFL_optimized_matrix_opt.c +++ b/experimental/algorithm/LAGraph_CFL_optimized_matrix_opt.c @@ -355,18 +355,25 @@ GrB_Info matrix_sort_lazy(Matrix *A, bool reverse) { return GrB_SUCCESS; } -GrB_Matrix CFL_matrix_lazy_to_base(Matrix *matrix, int8_t optimizations) { - GrB_Matrix _acc; - GrB_Matrix_new(&_acc, GrB_BOOL, matrix->nrows, matrix->ncols); - Matrix acc = CFL_matrix_from_base(_acc); +Matrix CFL_matrix_to_base(const Matrix *input, int8_t optimizations) { + if (!input->is_lazy) { + Matrix result = CFL_matrix_create(input->nrows, input->ncols); + CFL_dup(&result, input, optimizations); + return result; + } + + Matrix acc = CFL_matrix_create(input->nrows, input->ncols); + Matrix matrix = CFL_matrix_create(input->nrows, input->ncols); + CFL_dup(&matrix, input, optimizations); - matrix_sort_lazy(matrix, false); - for (size_t j = 0; j < matrix->base_matrices_count; j++) { - CFL_wise(&acc, &acc, &matrix->base_matrices[j], false, optimizations); - GrB_free(&matrix->base_matrices[j].base); + matrix_sort_lazy(&matrix, false); + for (size_t j = 0; j < matrix.base_matrices_count; j++) { + CFL_wise(&acc, &acc, &matrix.base_matrices[j], false, optimizations); } - return acc.base; + CFL_matrix_free(&matrix); + + return acc; } GrB_Info matrix_combine_lazy(Matrix *A, size_t threshold, int8_t optimizations) { @@ -428,7 +435,7 @@ Matrix CFL_matrix_from_base(GrB_Matrix matrix) { Matrix result; result.base = matrix; - result.nvals = 0; // We will get actual info in update functoin + result.nvals = 0; // We will get actual info in update function result.nrows = 0; result.ncols = 0; @@ -440,7 +447,7 @@ Matrix CFL_matrix_from_base(GrB_Matrix matrix) { // Lazy addition optimization fields result.is_lazy = false; - result.base_matrices = malloc(sizeof(CFL_Matrix) * 40); // TODO: dynamic size + result.base_matrices = NULL; result.base_matrices_count = 0; // Block optimization fields @@ -455,6 +462,7 @@ Matrix CFL_matrix_from_base_lazy(GrB_Matrix matrix) { Matrix lazy_result = CFL_matrix_from_base(matrix); lazy_result.is_lazy = true; + lazy_result.base_matrices = malloc(sizeof(CFL_Matrix) * 40); // TODO: dynamic size lazy_result.base_matrices[0] = result; lazy_result.base_matrices_count = 1; CFL_matrix_update(&lazy_result); @@ -680,7 +688,7 @@ GrB_Info matrix_wise_format(Matrix *output, Matrix *first, Matrix *second, bool CFL_matrix_update(output); CFL_matrix_update(first); CFL_matrix_update(second); - + Matrix *larger = output->nvals > first->nvals ? output : first; larger = larger->nvals > second->nvals ? larger : second; diff --git a/include/LAGraphX.h b/include/LAGraphX.h index e77b0f332d..8945570ecf 100644 --- a/include/LAGraphX.h +++ b/include/LAGraphX.h @@ -1131,7 +1131,23 @@ GrB_Info CFL_wise(CFL_Matrix *output, CFL_Matrix *first, CFL_Matrix *second, boo int8_t optimizations); GrB_Info CFL_rsub(CFL_Matrix *output, CFL_Matrix *mask, int8_t optimizations); GrB_Info CFL_dup(CFL_Matrix *output, CFL_Matrix *input, int8_t optimizations); -GrB_Matrix CFL_matrix_lazy_to_base(CFL_Matrix *matrix, int8_t optimizations); + +// Converts a matrix (lazy or regular) into its evaluated base form by merging +// all underlying base matrices. If the input matrix is not lazy, returns its copy. +// +// Parameters: +// input - [in] Pointer to the source matrix (may be lazy). +// optimizations - [in] Bitmask specifying enabled optimizations. +// +// Returns: +// A new matrix representing the fully evaluated base form. +CFL_Matrix CFL_matrix_to_base +( + // input + const CFL_Matrix *matrix, + int8_t optimizations +) ; + GrB_Info CFL_clear(CFL_Matrix *A, int8_t optimizations); //------------------------------------------------------------------------------ From 9608e2b015453a3b0a404c081cf85963449c4b6d Mon Sep 17 00:00:00 2001 From: homka122 Date: Mon, 3 Nov 2025 21:58:02 +0300 Subject: [PATCH 109/122] Feat: add dup_lazy --- .../LAGraph_CFL_optimized_matrix_opt.c | 38 ++++++++++++++++--- include/LAGraphX.h | 2 +- 2 files changed, 34 insertions(+), 6 deletions(-) diff --git a/experimental/algorithm/LAGraph_CFL_optimized_matrix_opt.c b/experimental/algorithm/LAGraph_CFL_optimized_matrix_opt.c index d66c30f3c9..7c4d4aa39e 100644 --- a/experimental/algorithm/LAGraph_CFL_optimized_matrix_opt.c +++ b/experimental/algorithm/LAGraph_CFL_optimized_matrix_opt.c @@ -162,19 +162,38 @@ GrB_Info matrix_dup_empty(Matrix *output, Matrix *input, int8_t optimizations) { return matrix_dup_format(output, input, optimizations); } +GrB_Info matrix_dup_lazy(Matrix *output, Matrix *input, int8_t optimizations) { + if (!(optimizations & OPT_LAZY)) { + return matrix_dup_empty(output, input, optimizations); + } + + if (!input->is_lazy) { + return matrix_dup_empty(output, input, optimizations); + } + + bool result = true; + for (size_t i = 0; i < input->base_matrices_count; i++) { + result &= matrix_dup_empty(&output->base_matrices[i], &input->base_matrices[i], + optimizations); + } + output->base_matrices_count = input->base_matrices_count; + + return result; +} + GrB_Info block_matrix_hyper_rotate_i(Matrix *matrix, enum CFL_Matrix_block format); GrB_Info matrix_dup_block(Matrix *output, Matrix *input, int8_t optimizations) { if (!(optimizations & OPT_BLOCK)) { - return matrix_dup_empty(output, input, optimizations); + return matrix_dup_lazy(output, input, optimizations); } if (output->block_type == CELL && input->block_type == CELL) { - return matrix_dup_empty(output, input, optimizations); + return matrix_dup_lazy(output, input, optimizations); } block_matrix_hyper_rotate_i(input, output->block_type); - return matrix_dup_empty(output, input, optimizations); + return matrix_dup_lazy(output, input, optimizations); } // block optimization specific methods @@ -355,7 +374,7 @@ GrB_Info matrix_sort_lazy(Matrix *A, bool reverse) { return GrB_SUCCESS; } -Matrix CFL_matrix_to_base(const Matrix *input, int8_t optimizations) { +Matrix CFL_matrix_to_base(Matrix *input, int8_t optimizations) { if (!input->is_lazy) { Matrix result = CFL_matrix_create(input->nrows, input->ncols); CFL_dup(&result, input, optimizations); @@ -363,7 +382,16 @@ Matrix CFL_matrix_to_base(const Matrix *input, int8_t optimizations) { } Matrix acc = CFL_matrix_create(input->nrows, input->ncols); - Matrix matrix = CFL_matrix_create(input->nrows, input->ncols); + + GrB_Matrix _matrix; + GrB_Matrix_new(&_matrix, GrB_BOOL, input->nrows, input->ncols); + Matrix matrix = CFL_matrix_from_base_lazy(_matrix); + + for (size_t i = 0; i < input->base_matrices_count; i++) { + Matrix base = CFL_matrix_create(input->nrows, input->ncols); + matrix.base_matrices[i] = base; + } + CFL_dup(&matrix, input, optimizations); matrix_sort_lazy(&matrix, false); diff --git a/include/LAGraphX.h b/include/LAGraphX.h index 8945570ecf..368261cfec 100644 --- a/include/LAGraphX.h +++ b/include/LAGraphX.h @@ -1144,7 +1144,7 @@ GrB_Info CFL_dup(CFL_Matrix *output, CFL_Matrix *input, int8_t optimizations); CFL_Matrix CFL_matrix_to_base ( // input - const CFL_Matrix *matrix, + CFL_Matrix *matrix, int8_t optimizations ) ; From f1b4a5c367865c6f4a218acdee6512f1294190fc Mon Sep 17 00:00:00 2001 From: homka122 Date: Tue, 4 Nov 2025 02:03:47 +0300 Subject: [PATCH 110/122] Fix: delete unused sort of matrices --- .../algorithm/LAGraph_CFL_optimized_matrix_opt.c | 16 +++------------- 1 file changed, 3 insertions(+), 13 deletions(-) diff --git a/experimental/algorithm/LAGraph_CFL_optimized_matrix_opt.c b/experimental/algorithm/LAGraph_CFL_optimized_matrix_opt.c index 7c4d4aa39e..d14590ff8a 100644 --- a/experimental/algorithm/LAGraph_CFL_optimized_matrix_opt.c +++ b/experimental/algorithm/LAGraph_CFL_optimized_matrix_opt.c @@ -605,18 +605,6 @@ GrB_Info matrix_mxm_lazy(Matrix *output, Matrix *first, Matrix *second, bool acc optimizations); } - for (size_t i = 0; i < first->base_matrices_count; i++) { - CFL_matrix_update(&acc_matrices[i]); - for (size_t j = i + 1; j < first->base_matrices_count; j++) { - CFL_matrix_update(&acc_matrices[j]); - if (acc_matrices[i].nvals > acc_matrices[j].nvals) { - Matrix temp = acc_matrices[i]; - acc_matrices[i] = acc_matrices[j]; - acc_matrices[j] = temp; - } - } - } - GrB_Matrix acc; GrB_Matrix_new(&acc, GrB_BOOL, swap ? second->nrows : first->nrows, swap ? first->ncols : second->ncols); @@ -803,7 +791,7 @@ GrB_Info matrix_wise_lazy(Matrix *output, Matrix *first, Matrix *second, bool ac if (!first->is_lazy && second->is_lazy) { for (size_t i = 0; i < second->base_matrices_count; i++) { - matrix_wise_empty(output, first, &second->base_matrices[i], false, + matrix_wise_empty(output, first, &second->base_matrices[i], true, optimizations); } @@ -846,6 +834,8 @@ GrB_Info matrix_wise_lazy(Matrix *output, Matrix *first, Matrix *second, bool ac break; } + CFL_matrix_update(output); + return GrB_SUCCESS; } From 098bc8c87fdb7dd9e4a3b9b128414f8dda89c3ed Mon Sep 17 00:00:00 2001 From: homka122 Date: Tue, 4 Nov 2025 02:05:20 +0300 Subject: [PATCH 111/122] Fix: delete unreacheable block of code in rsub --- .../algorithm/LAGraph_CFL_optimized_matrix_opt.c | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/experimental/algorithm/LAGraph_CFL_optimized_matrix_opt.c b/experimental/algorithm/LAGraph_CFL_optimized_matrix_opt.c index d14590ff8a..3a70def6c7 100644 --- a/experimental/algorithm/LAGraph_CFL_optimized_matrix_opt.c +++ b/experimental/algorithm/LAGraph_CFL_optimized_matrix_opt.c @@ -914,18 +914,6 @@ GrB_Info matrix_rsub_format(Matrix *output, Matrix *mask, int8_t optimizations) if (!output->is_both) { return matrix_rsub(output, mask); } - - printf("LOOOOOO\n\n"); - - matrix_to_format(output, GrB_ROWMAJOR, false); - GrB_Info result = matrix_rsub(output, mask); - - if (result < GrB_SUCCESS) { - return result; - } - - matrix_to_format(output, GrB_COLMAJOR, false); - return matrix_rsub(output, mask); } GrB_Info matrix_rsub_empty(Matrix *output, Matrix *mask, int8_t optimizations) { From a6e0148e591e280a6a3c9a684197409a2d2cb765 Mon Sep 17 00:00:00 2001 From: homka122 Date: Tue, 4 Nov 2025 02:07:49 +0300 Subject: [PATCH 112/122] Test: add tests for lazy optimization --- .../test/test_CFL_optimized_matrix_opt.c | 279 ++++++++++++++++++ 1 file changed, 279 insertions(+) diff --git a/experimental/test/test_CFL_optimized_matrix_opt.c b/experimental/test/test_CFL_optimized_matrix_opt.c index 7473c849fa..76b769b6cf 100644 --- a/experimental/test/test_CFL_optimized_matrix_opt.c +++ b/experimental/test/test_CFL_optimized_matrix_opt.c @@ -62,6 +62,19 @@ static Matrix make_simple_matrix(int n) { return M; } +// 1 0 .. 0 +// 0 1 .. 0 +// .. .. .. .. +// 0 0 .. 0 +static Matrix make_simple_matrix_inverted(int n) { + GrB_Matrix A; + OK(GrB_Matrix_new(&A, GrB_BOOL, n, n)); + OK(GrB_Matrix_setElement_BOOL(A, true, 0, 0)); + OK(GrB_Matrix_setElement_BOOL(A, true, 1, 1)); + Matrix M = CFL_matrix_from_base(A); + return M; +} + // 1 1 .. 1 // 1 1 .. 1 // .. .. .. .. @@ -82,6 +95,50 @@ static Matrix make_ones_matrix(int n) { static void free_matrix(Matrix *M) { CFL_matrix_free(M); } +static bool compare_matrices(Matrix first, Matrix second) { + Matrix A, B, C; + A = CFL_matrix_to_base(&first, OPT_LAZY); + B = CFL_matrix_to_base(&second, OPT_LAZY); + C = CFL_matrix_create(A.nrows, A.ncols); + + if (A.nvals != B.nvals) { + CFL_matrix_free(&A); + CFL_matrix_free(&B); + CFL_matrix_free(&C); + + return false; + } + + GrB_eWiseMult(C.base, GrB_NULL, false, GrB_EQ_BOOL, A.base, B.base, GrB_NULL); + CFL_matrix_update(&C); + + bool result = C.nvals == A.nvals; + + CFL_matrix_free(&A); + CFL_matrix_free(&B); + CFL_matrix_free(&C); + + return result; +} + +static void test_compare_matrices_function(void) { +#if LAGRAPH_SUITESPARSE + setup(); + + Matrix A = make_simple_matrix(5); + Matrix B = make_simple_matrix_inverted(5); + + TEST_CHECK(!compare_matrices(A, B)); + TEST_CHECK(compare_matrices(A, A)); + TEST_CHECK(compare_matrices(B, B)); + + CFL_matrix_free(&A); + CFL_matrix_free(&B); + + teardown(); +#endif +} + //------------------------------------------------------------------------------ // Сreation and Free //------------------------------------------------------------------------------ @@ -641,11 +698,229 @@ static void test_CFL_empty_rsub_both_empty(void) { #endif } +//------------------------------------------------------------------------------ +// Lazy optimization +//------------------------------------------------------------------------------ + +static void test_CFL_lazy_create(void) { +#if LAGRAPH_SUITESPARSE + setup(); + + GrB_Matrix A_base; + GrB_Matrix_new(&A_base, GrB_BOOL, 5, 5); + Matrix A = CFL_matrix_from_base_lazy(A_base); + TEST_CHECK(A.base_matrices != NULL); + TEST_CHECK(A.base_matrices_count == 1); + TEST_CHECK(A.is_lazy == true); + TEST_CHECK(A.nvals == 0); + + teardown(); +#endif +} + +// Create lazy matrix +// 1 1 1 0 .. 0 (count of 1: 111) +// 1 0 0 0 .. 0 (count of 1: 1) +// 1 1 0 0 .. 0 (count of 1: 11) +// . . . . .. . +// 0 0 0 0 .. 0 +static Matrix make_lazy_matrix(size_t base_matrices_count) { + size_t n = 0; + Matrix base_matrices[base_matrices_count]; + // 1 -> 1, 2 -> 11, 3 -> 111, 4 -> 1111 + for (size_t i = 0; i < base_matrices_count; i++) { + n *= 10; + n++; + } + + size_t tmp_n = 0; + for (size_t i = 0; i < base_matrices_count; i++) { + tmp_n *= 10; + tmp_n++; + GrB_Matrix base_matrix; + GrB_Matrix_new(&base_matrix, GrB_BOOL, n, n); + for (size_t j = 0; j < tmp_n; j++) { + // i+1 for future testing of sorting matrices + GrB_Matrix_setElement_BOOL(base_matrix, true, (i + 1) % base_matrices_count, + j); + } + + base_matrices[(i + 1) % base_matrices_count] = CFL_matrix_from_base(base_matrix); + } + + GrB_Matrix _result; + GrB_Matrix_new(&_result, GrB_BOOL, n, n); + Matrix result = CFL_matrix_from_base_lazy(_result); + + result.is_lazy = true; + result.base_matrices_count = base_matrices_count; + for (size_t i = 0; i < base_matrices_count; i++) { + result.base_matrices[i] = base_matrices[i]; + } + + CFL_matrix_update(&result); + + return result; +} + +static void test_CFL_lazy_mxm(void) { +#if LAGRAPH_SUITESPARSE + setup(); + + for (size_t is_accum = 0; is_accum < 2; is_accum++) { + for (size_t is_reverse = 0; is_reverse < 2; is_reverse++) { + Matrix A = make_lazy_matrix(4); + Matrix B = make_ones_matrix(1111); + Matrix C = CFL_matrix_create(1111, 1111); + + Matrix A_base = CFL_matrix_to_base(&A, OPT_LAZY); + Matrix B_base = CFL_matrix_to_base(&B, OPT_LAZY); + Matrix C_base = CFL_matrix_to_base(&C, OPT_LAZY); + + CFL_mxm(&C, &A, &B, is_accum, is_reverse, OPT_LAZY); + CFL_mxm(&C_base, &A_base, &B_base, is_accum, is_reverse, 0); + + TEST_CHECK(compare_matrices(C, C_base)); + + free_matrix(&A); + free_matrix(&B); + free_matrix(&C); + free_matrix(&A_base); + free_matrix(&B_base); + free_matrix(&C_base); + } + } + + for (size_t is_accum = 0; is_accum < 2; is_accum++) { + for (size_t is_reverse = 0; is_reverse < 2; is_reverse++) { + Matrix A = make_lazy_matrix(4); + Matrix B = CFL_matrix_create(1111, 1111); + Matrix C = CFL_matrix_create(1111, 1111); + + Matrix A_base = CFL_matrix_to_base(&A, OPT_LAZY); + Matrix B_base = CFL_matrix_to_base(&B, OPT_LAZY); + Matrix C_base = CFL_matrix_to_base(&C, OPT_LAZY); + + CFL_mxm(&C, &A, &B, is_accum, is_reverse, OPT_LAZY); + CFL_mxm(&C_base, &A_base, &B_base, is_accum, is_reverse, 0); + + TEST_CHECK(compare_matrices(C, C_base)); + + free_matrix(&A); + free_matrix(&B); + free_matrix(&C); + free_matrix(&A_base); + free_matrix(&B_base); + free_matrix(&C_base); + } + } + + teardown(); +#endif +} + +static void test_CFL_lazy_wise(void) { +#if LAGRAPH_SUITESPARSE + setup(); + + for (size_t is_accum = 0; is_accum < 2; is_accum++) { + Matrix A = make_lazy_matrix(4); + Matrix B = CFL_matrix_create(1111, 1111); + Matrix C = CFL_matrix_create(1111, 1111); + + Matrix A_base = CFL_matrix_to_base(&A, OPT_LAZY); + Matrix B_base = CFL_matrix_to_base(&B, OPT_LAZY); + Matrix C_base = CFL_matrix_to_base(&C, OPT_LAZY); + + CFL_wise(&C, &A, &B, is_accum, OPT_LAZY); + CFL_wise(&C_base, &A_base, &B_base, is_accum, 0); + + TEST_CHECK(compare_matrices(A, C_base)); + + free_matrix(&A); + free_matrix(&B); + free_matrix(&C); + free_matrix(&A_base); + free_matrix(&B_base); + free_matrix(&C_base); + } + + for (size_t is_accum = 0; is_accum < 2; is_accum++) { + Matrix A = CFL_matrix_create(1111, 1111); + Matrix B = make_lazy_matrix(4); + Matrix C = CFL_matrix_create(1111, 1111); + + Matrix A_base = CFL_matrix_to_base(&A, OPT_LAZY); + Matrix B_base = CFL_matrix_to_base(&B, OPT_LAZY); + Matrix C_base = CFL_matrix_to_base(&C, OPT_LAZY); + + CFL_wise(&C, &A, &B, is_accum, OPT_LAZY); + CFL_wise(&C_base, &A_base, &B_base, is_accum, 0); + + TEST_CHECK(compare_matrices(C, C_base)); + + free_matrix(&A); + free_matrix(&B); + free_matrix(&C); + free_matrix(&A_base); + free_matrix(&B_base); + free_matrix(&C_base); + } + + teardown(); +#endif +} + +static void test_CFL_lazy_rsub(void) { +#if LAGRAPH_SUITESPARSE + setup(); + + { + Matrix A = make_lazy_matrix(4); + Matrix B = CFL_matrix_create(1111, 1111); + + Matrix A_base = CFL_matrix_to_base(&A, OPT_LAZY); + Matrix B_base = CFL_matrix_to_base(&B, OPT_LAZY); + + CFL_rsub(&A, &B, OPT_LAZY); + CFL_rsub(&A_base, &B_base, 0); + + TEST_CHECK(compare_matrices(A, A_base)); + + free_matrix(&A); + free_matrix(&B); + free_matrix(&A_base); + free_matrix(&B_base); + } + + { + Matrix A = CFL_matrix_create(1111, 1111); + Matrix B = make_lazy_matrix(4); + + Matrix A_base = CFL_matrix_to_base(&A, OPT_LAZY); + Matrix B_base = CFL_matrix_to_base(&B, OPT_LAZY); + + CFL_rsub(&A, &B, OPT_LAZY); + CFL_rsub(&A_base, &B_base, 0); + + TEST_CHECK(compare_matrices(A, A_base)); + + free_matrix(&A); + free_matrix(&B); + free_matrix(&A_base); + free_matrix(&B_base); + } + + teardown(); +#endif +} + //------------------------------------------------------------------------------ // TEST LIST //------------------------------------------------------------------------------ TEST_LIST = { + {"test_compare_matrices_function", test_compare_matrices_function}, {"test CFL create and free", test_CFL_create_free}, {"test CFL mxm", test_CFL_mxm}, {"test CFL clear", test_CFL_clear}, @@ -665,4 +940,8 @@ TEST_LIST = { {"test_CFL_empty_mxm_one_is_empty", test_CFL_empty_mxm_one_is_empty}, {"test_CFL_empty_wise", test_CFL_empty_wise}, {"test_CFL_empty_rsub_both_empty", test_CFL_empty_rsub_both_empty}, + {"test_CFL_lazy_create", test_CFL_lazy_create}, + {"test_CFL_lazy_mxm", test_CFL_lazy_mxm}, + {"test_CFL_lazy_wise", test_CFL_lazy_wise}, + {"test_CFL_lazy_rsub", test_CFL_lazy_rsub}, {NULL, NULL}}; \ No newline at end of file From 15bdb6b63dedbe4d9346336b9db28108c9f671fe Mon Sep 17 00:00:00 2001 From: homka122 Date: Tue, 4 Nov 2025 05:50:23 +0300 Subject: [PATCH 113/122] Refactor: reformat matrix_opt file --- .../LAGraph_CFL_optimized_matrix_opt.c | 50 +++++++++---------- 1 file changed, 23 insertions(+), 27 deletions(-) diff --git a/experimental/algorithm/LAGraph_CFL_optimized_matrix_opt.c b/experimental/algorithm/LAGraph_CFL_optimized_matrix_opt.c index 3a70def6c7..34423f928a 100644 --- a/experimental/algorithm/LAGraph_CFL_optimized_matrix_opt.c +++ b/experimental/algorithm/LAGraph_CFL_optimized_matrix_opt.c @@ -246,33 +246,31 @@ GrB_Info block_matrix_hyper_rotate_i(Matrix *matrix, enum CFL_Matrix_block forma return GrB_SUCCESS; } - if (matrix->block_type == VEC_HORIZ) { - GrB_Index *nrows = malloc(matrix->nvals * sizeof(GrB_Index)); - GrB_Index *ncols = malloc(matrix->nvals * sizeof(GrB_Index)); - - GrB_Matrix_extractTuples_BOOL(nrows, ncols, NULL, &matrix->nvals, matrix->base); + GrB_Index *nrows = malloc(matrix->nvals * sizeof(GrB_Index)); + GrB_Index *ncols = malloc(matrix->nvals * sizeof(GrB_Index)); - for (size_t i = 0; i < matrix->nvals; i++) { - nrows[i] = nrows[i] + ncols[i] / matrix->nrows * matrix->nrows; - ncols[i] = ncols[i] % matrix->nrows; - } + GrB_Matrix_extractTuples_BOOL(nrows, ncols, NULL, &matrix->nvals, matrix->base); - GrB_Matrix new; - GrB_Matrix_new(&new, GrB_BOOL, matrix->ncols, matrix->nrows); - GxB_Matrix_build_Scalar(new, nrows, ncols, scalar_true, matrix->nvals); - CFL_matrix_free(matrix); - *matrix = - matrix->is_lazy ? CFL_matrix_from_base_lazy(new) : CFL_matrix_from_base(new); - free(nrows); - free(ncols); - GrB_free(&scalar_true); - return GrB_SUCCESS; + for (size_t i = 0; i < matrix->nvals; i++) { + nrows[i] = nrows[i] + ncols[i] / matrix->nrows * matrix->nrows; + ncols[i] = ncols[i] % matrix->nrows; } + + GrB_Matrix new; + GrB_Matrix_new(&new, GrB_BOOL, matrix->ncols, matrix->nrows); + GxB_Matrix_build_Scalar(new, nrows, ncols, scalar_true, matrix->nvals); + CFL_matrix_free(matrix); + *matrix = + matrix->is_lazy ? CFL_matrix_from_base_lazy(new) : CFL_matrix_from_base(new); + free(nrows); + free(ncols); + GrB_free(&scalar_true); + return GrB_SUCCESS; } void block_matrix_to_diag(Matrix *diag, Matrix *input) { if (input->block_type == CELL) { - exit(-1); + return; } GrB_Scalar scalar_true; @@ -851,8 +849,8 @@ GrB_Info matrix_wise_block(Matrix *output, Matrix *first, Matrix *second, bool a } if (output != first) { - fprintf(stderr, "Matrix wise currently support only iadd operation"); - exit(-122); + // fprintf(stderr, "Matrix wise currently support only iadd operation"); + return GrB_INVALID_VALUE; } if (first->block_type == CELL && second->block_type == CELL) { @@ -911,9 +909,7 @@ GrB_Info matrix_rsub_format(Matrix *output, Matrix *mask, int8_t optimizations) matrix_to_format(output, larger_matrix->format, false); matrix_to_format(mask, larger_matrix->format, false); - if (!output->is_both) { - return matrix_rsub(output, mask); - } + return matrix_rsub(output, mask); } GrB_Info matrix_rsub_empty(Matrix *output, Matrix *mask, int8_t optimizations) { @@ -957,8 +953,8 @@ GrB_Info matrix_rsub_block(Matrix *output, Matrix *mask, int8_t optimizations) { if ((output->block_type == CELL && mask->block_type != CELL) || (output->block_type != CELL && mask->block_type == CELL)) { - fprintf(stderr, "Don't support rsub operation between cell and vector"); - exit(-1); + // fprintf(stderr, "Don't support rsub operation between cell and vector"); + return GrB_INVALID_VALUE; } if (output->block_type == CELL) { From eb151f34cf4fe49d88df433a7e650ecdbc1060f8 Mon Sep 17 00:00:00 2001 From: homka122 Date: Tue, 4 Nov 2025 05:50:58 +0300 Subject: [PATCH 114/122] Refactor: comment print debug functions --- .../LAGraph_CFL_optimized_matrix_opt.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/experimental/algorithm/LAGraph_CFL_optimized_matrix_opt.c b/experimental/algorithm/LAGraph_CFL_optimized_matrix_opt.c index 34423f928a..4a5eb89e7c 100644 --- a/experimental/algorithm/LAGraph_CFL_optimized_matrix_opt.c +++ b/experimental/algorithm/LAGraph_CFL_optimized_matrix_opt.c @@ -999,17 +999,17 @@ GrB_Info matrix_rsub_block(Matrix *output, Matrix *mask, int8_t optimizations) { // GrB_free(&_temp); // } -void print_graph_info(Matrix *matrices, size_t count) { - GrB_Index nnz = 0; +// void print_graph_info(Matrix *matrices, size_t count) { +// GrB_Index nnz = 0; - for (size_t i = 0; i < count; i++) { - Matrix *A = &matrices[i]; - CFL_matrix_update(A); - nnz += A->nvals; - } +// for (size_t i = 0; i < count; i++) { +// Matrix *A = &matrices[i]; +// CFL_matrix_update(A); +// nnz += A->nvals; +// } - printf("NNZ: %ld\n", nnz); -} +// printf("NNZ: %ld\n", nnz); +// } // order of optimizations: block -> lazy -> empty -> format From d13785c427cd3dba45efba2dceabb241c90e0f43 Mon Sep 17 00:00:00 2001 From: homka122 Date: Tue, 4 Nov 2025 05:52:43 +0300 Subject: [PATCH 115/122] Test: add block tests for matrix_opt --- .../test/test_CFL_optimized_matrix_opt.c | 350 ++++++++++++++++++ 1 file changed, 350 insertions(+) diff --git a/experimental/test/test_CFL_optimized_matrix_opt.c b/experimental/test/test_CFL_optimized_matrix_opt.c index 76b769b6cf..d89f741782 100644 --- a/experimental/test/test_CFL_optimized_matrix_opt.c +++ b/experimental/test/test_CFL_optimized_matrix_opt.c @@ -34,6 +34,9 @@ typedef enum CFL_Matrix_block Matrix_block; extern GrB_Info matrix_to_format(Matrix *matrix, int32_t format, bool is_bool); extern GrB_Info matrix_clear_format(Matrix *A, int8_t optimizations); extern GrB_Info matrix_dup_format(Matrix *output, Matrix *input, int8_t optimizations); +extern GrB_Info block_matrix_hyper_rotate_i(Matrix *matrix, enum CFL_Matrix_block format); +extern void block_matrix_to_diag(Matrix *diag, Matrix *input); +extern void block_matrix_reduce(Matrix *matrix, Matrix *input, int8_t optimizations); // extern GrB_Info matrix_clear_empty(Matrix *A, int8_t optimizations); // extern GrB_Info matrix_mxm_empty(Matrix *output, Matrix *first, Matrix *second, @@ -915,6 +918,346 @@ static void test_CFL_lazy_rsub(void) { #endif } +//------------------------------------------------------------------------------ +// Block optimization +//------------------------------------------------------------------------------ + +// Create block vector +static Matrix make_block_vector(size_t n, size_t alpha, Matrix_block format) { + GrB_Matrix result; + switch (format) { + case CELL: + // 1 1 0 0 0 0 . + // 0 1 1 0 0 0 . + // 0 0 1 1 0 0 . + // 0 0 0 1 1 0 . + // 0 0 0 0 1 1 . + // 1 0 0 0 0 1 . + // 1 1 0 0 0 0 . + // . . . . . . . + GrB_Matrix_new(&result, GrB_BOOL, n, n); + for (size_t i = 0; i < n; i++) { + for (size_t j = 0; j < n; j++) { + bool value = j == (i % n) || j == ((i + 1) % n) ? true : false; + if (!value) + continue; + + GrB_Matrix_setElement_BOOL(result, value, i, j); + } + } + + return CFL_matrix_from_base(result); + + case VEC_VERT: + GrB_Matrix_new(&result, GrB_BOOL, n * alpha, n); + for (size_t i = 0; i < n * alpha; i++) { + for (size_t j = 0; j < n; j++) { + bool value = j == (i + 2 % n) || j == ((i + 3) % n) ? true : false; + if (!value) + continue; + + GrB_Matrix_setElement_BOOL(result, value, i, j); + } + } + + return CFL_matrix_from_base(result); + + case VEC_HORIZ: + GrB_Matrix_new(&result, GrB_BOOL, n, n * alpha); + for (size_t i = 0; i < n * alpha; i++) { + for (size_t j = 0; j < n; j++) { + bool value = j == (i + 5 % n) || j == ((i + 6) % n) ? true : false; + if (!value) + continue; + + GrB_Matrix_setElement_BOOL(result, value, i, j); + } + } + + return CFL_matrix_from_base(result); + } +} + +static Matrix make_lazy_block_matrix(size_t base_matrices_count) { + size_t n = 0; + Matrix base_matrices[base_matrices_count]; + // 1 -> 1, 2 -> 11, 3 -> 111, 4 -> 1111 + for (size_t i = 0; i < base_matrices_count; i++) { + n *= 10; + n++; + } + + size_t tmp_n = 0; + for (size_t i = 0; i < base_matrices_count; i++) { + tmp_n *= 10; + tmp_n++; + GrB_Matrix base_matrix; + GrB_Matrix_new(&base_matrix, GrB_BOOL, n, n); + for (size_t j = 0; j < tmp_n; j++) { + // i+1 for future testing of sorting matrices + GrB_Matrix_setElement_BOOL(base_matrix, true, (i + 1) % base_matrices_count, + j); + } + + base_matrices[(i + 1) % base_matrices_count] = CFL_matrix_from_base(base_matrix); + } + + GrB_Matrix _result; + GrB_Matrix_new(&_result, GrB_BOOL, n, n); + Matrix result = CFL_matrix_from_base_lazy(_result); + + result.is_lazy = true; + result.base_matrices_count = base_matrices_count; + for (size_t i = 0; i < base_matrices_count; i++) { + result.base_matrices[i] = base_matrices[i]; + } + + CFL_matrix_update(&result); + + return result; +} + +// TODO: create equality check with basic mxm +static void test_CFL_block_mxm(void) { +#if LAGRAPH_SUITESPARSE + setup(); + + for (size_t is_accum = 0; is_accum < 2; is_accum++) { + for (size_t is_reverse = 0; is_reverse < 2; is_reverse++) { + for (size_t first_format = 0; first_format < 3; first_format++) { + for (size_t second_format = 0; second_format < 3; second_format++) { + Matrix A = make_block_vector(20, 20, first_format); + Matrix B = make_block_vector(20, 20, second_format); + + Matrix C; + if (first_format != CELL && second_format != CELL) { + size_t nrows = first_format == VEC_HORIZ ? 20 : 20 * 20; + size_t ncols = first_format == VEC_HORIZ ? 20 * 20 : 20; + C = CFL_matrix_create(nrows, ncols); + } else { + C = CFL_matrix_create(first_format == CELL ? 20 : 20 * 20, + second_format == CELL ? 20 : 20 * 20); + } + + OK(CFL_mxm(&C, &A, &B, is_accum, is_reverse, OPT_BLOCK)); + + free_matrix(&A); + free_matrix(&B); + free_matrix(&C); + } + } + } + } + + teardown(); +#endif +} + +static void test_CFL_block_dup(void) { +#if LAGRAPH_SUITESPARSE + setup(); + + { + Matrix A = make_block_vector(20, 20, VEC_HORIZ); + Matrix B = CFL_matrix_create(20 * 20, 20); + + OK(CFL_dup(&B, &A, OPT_BLOCK)); + TEST_CHECK(B.nvals == A.nvals); + } + + { + Matrix A = make_block_vector(20, 20, VEC_VERT); + Matrix B = CFL_matrix_create(20 * 20, 20); + + OK(CFL_dup(&B, &A, OPT_BLOCK)); + TEST_CHECK(B.nvals == A.nvals); + } + + { + Matrix A = make_block_vector(20, 20, VEC_HORIZ); + Matrix B = CFL_matrix_create(20, 20 * 20); + + OK(CFL_dup(&B, &A, OPT_BLOCK)); + TEST_CHECK(B.nvals == A.nvals); + } + + { + Matrix A = make_block_vector(20, 20, VEC_VERT); + Matrix B = CFL_matrix_create(20, 20 * 20); + + OK(CFL_dup(&B, &A, OPT_BLOCK)); + TEST_CHECK(B.nvals == A.nvals); + } + + teardown(); +#endif +} + +static void test_CFL_block_wise(void) { +#if LAGRAPH_SUITESPARSE + setup(); + + { + Matrix A = make_block_vector(20, 20, VEC_HORIZ); + Matrix B = make_block_vector(20, 20, VEC_HORIZ); + Matrix C = make_block_vector(20, 20, VEC_HORIZ); + + TEST_CHECK(CFL_wise(&C, &A, &B, false, OPT_BLOCK) == GrB_INVALID_VALUE); + + free_matrix(&A); + free_matrix(&B); + free_matrix(&C); + } + + for (size_t is_accum = 0; is_accum < 2; is_accum++) { + for (size_t is_reverse = 0; is_reverse < 2; is_reverse++) { + for (size_t first_format = 0; first_format < 3; first_format++) { + for (size_t second_format = 0; second_format < 3; second_format++) { + Matrix A = make_block_vector(20, 20, first_format); + Matrix B = make_block_vector(20, 20, second_format); + + OK(CFL_wise(&A, &A, &B, is_accum, OPT_BLOCK)); + + free_matrix(&A); + free_matrix(&B); + } + } + } + } + + teardown(); +#endif +} + +static void test_CFL_block_rsub(void) { +#if LAGRAPH_SUITESPARSE + setup(); + + for (size_t is_accum = 0; is_accum < 2; is_accum++) { + for (size_t is_reverse = 0; is_reverse < 2; is_reverse++) { + for (size_t first_format = 0; first_format < 3; first_format++) { + for (size_t second_format = 0; second_format < 3; second_format++) { + Matrix A = make_block_vector(20, 20, first_format); + Matrix B = make_block_vector(20, 20, second_format); + + if ((first_format != CELL && second_format == CELL) || + (first_format == CELL && second_format != CELL)) { + TEST_CHECK(CFL_rsub(&A, &B, OPT_BLOCK) == GrB_INVALID_VALUE); + } else { + OK(CFL_rsub(&A, &B, OPT_BLOCK)); + } + + free_matrix(&A); + free_matrix(&B); + } + } + } + } + + teardown(); +#endif +} + +static void test_CFL_block_hyper_rotate(void) { +#if LAGRAPH_SUITESPARSE + setup(); + + // lazy + { + GrB_Matrix _A; + GrB_Matrix_new(&_A, GrB_BOOL, 20 * 20, 20); + Matrix A = CFL_matrix_from_base_lazy(_A); + + GrB_Matrix _A0; + GrB_Matrix_new(&_A0, GrB_BOOL, 20 * 20, 20); + Matrix A0 = CFL_matrix_from_base(_A0); + GrB_Matrix _A1; + GrB_Matrix_new(&_A1, GrB_BOOL, 20 * 20, 20); + Matrix A1 = CFL_matrix_from_base(_A0); + GrB_Matrix _A2; + GrB_Matrix_new(&_A2, GrB_BOOL, 20 * 20, 20); + Matrix A2 = CFL_matrix_from_base(_A0); + + A.base_matrices[0] = A0; + A.base_matrices[1] = A1; + A.base_matrices[2] = A2; + A.base_matrices_count = 3; + + OK(block_matrix_hyper_rotate_i(&A, VEC_HORIZ)); + TEST_CHECK(A.nrows == 20); + TEST_CHECK(A.ncols == 20 * 20); + + free_matrix(&A); + free_matrix(&A0); + free_matrix(&A1); + free_matrix(&A2); + } + + // cell + { + Matrix A = CFL_matrix_create(5, 5); + + OK(block_matrix_hyper_rotate_i(&A, VEC_HORIZ)); + + free_matrix(&A); + } + + // VERT + { + Matrix A = make_block_vector(5, 5, VEC_VERT); + TEST_CHECK(A.nvals != 0); + TEST_CHECK(A.is_lazy != true); + + OK(block_matrix_hyper_rotate_i(&A, VEC_HORIZ)); + + free_matrix(&A); + } + + teardown(); +#endif +} + +static void test_CFL_block_to_diag(void) { +#if LAGRAPH_SUITESPARSE + setup(); + + Matrix A = CFL_matrix_create(5, 5); + Matrix B = CFL_matrix_create(5, 5); + + GrB_Index nvals_before; + GrB_Matrix_nvals(&nvals_before, A.base); + block_matrix_to_diag(&A, &B); + GrB_Index nvals_after; + GrB_Matrix_nvals(&nvals_after, A.base); + + // A didn't change + TEST_CHECK(nvals_after == nvals_before); + + free_matrix(&A); + free_matrix(&B); + + teardown(); +#endif +} + +static void test_CFL_block_to_reduce(void) { +#if LAGRAPH_SUITESPARSE + setup(); + + Matrix A = CFL_matrix_create(5, 5); + Matrix B = make_ones_matrix(5); + + // cell matrix cause just dup + block_matrix_reduce(&A, &B, OPT_BLOCK); + TEST_CHECK(A.nvals == B.nvals); + + free_matrix(&A); + free_matrix(&B); + + teardown(); +#endif +} + //------------------------------------------------------------------------------ // TEST LIST //------------------------------------------------------------------------------ @@ -944,4 +1287,11 @@ TEST_LIST = { {"test_CFL_lazy_mxm", test_CFL_lazy_mxm}, {"test_CFL_lazy_wise", test_CFL_lazy_wise}, {"test_CFL_lazy_rsub", test_CFL_lazy_rsub}, + {"test_CFL_block_mxm", test_CFL_block_mxm}, + {"test_CFL_block_wise", test_CFL_block_wise}, + {"test_CFL_block_rsub", test_CFL_block_rsub}, + {"test_CFL_block_dup", test_CFL_block_dup}, + {"test_CFL_block_hyper_rotate", test_CFL_block_hyper_rotate}, + {"test_CFL_block_to_diag", test_CFL_block_to_diag}, + {"test_CFL_block_to_reduce", test_CFL_block_to_reduce}, {NULL, NULL}}; \ No newline at end of file From 29bfba9500a5f5523667712cb40309aa0591735c Mon Sep 17 00:00:00 2001 From: homka122 Date: Tue, 4 Nov 2025 05:59:05 +0300 Subject: [PATCH 116/122] Test: refactor tests for matrix_opt for coverage --- .../test/test_CFL_optimized_matrix_opt.c | 115 +++++------------- 1 file changed, 31 insertions(+), 84 deletions(-) diff --git a/experimental/test/test_CFL_optimized_matrix_opt.c b/experimental/test/test_CFL_optimized_matrix_opt.c index d89f741782..1b5d4ba008 100644 --- a/experimental/test/test_CFL_optimized_matrix_opt.c +++ b/experimental/test/test_CFL_optimized_matrix_opt.c @@ -128,15 +128,27 @@ static void test_compare_matrices_function(void) { #if LAGRAPH_SUITESPARSE setup(); - Matrix A = make_simple_matrix(5); - Matrix B = make_simple_matrix_inverted(5); + { + Matrix A = make_simple_matrix(5); + Matrix B = CFL_matrix_create(5, 5); - TEST_CHECK(!compare_matrices(A, B)); - TEST_CHECK(compare_matrices(A, A)); - TEST_CHECK(compare_matrices(B, B)); + TEST_CHECK(!compare_matrices(A, B)); - CFL_matrix_free(&A); - CFL_matrix_free(&B); + CFL_matrix_free(&A); + CFL_matrix_free(&B); + } + + { + Matrix A = make_simple_matrix(5); + Matrix B = make_simple_matrix_inverted(5); + + TEST_CHECK(!compare_matrices(A, B)); + TEST_CHECK(compare_matrices(A, A)); + TEST_CHECK(compare_matrices(B, B)); + + CFL_matrix_free(&A); + CFL_matrix_free(&B); + } teardown(); #endif @@ -439,36 +451,7 @@ static void test_CFL_format_dup_format(void) { TEST_CHECK(A.nvals == B.nvals); TEST_CHECK(A.base != B.base); - GrB_Index nvals_A = A.nvals; - GrB_Index nvals_B = B.nvals; - - GrB_Index *rows_A = malloc(nvals_A * sizeof(GrB_Index)); - GrB_Index *cols_A = malloc(nvals_A * sizeof(GrB_Index)); - bool *vals_A = malloc(nvals_A * sizeof(bool)); - - GrB_Index *rows_B = malloc(nvals_B * sizeof(GrB_Index)); - GrB_Index *cols_B = malloc(nvals_B * sizeof(GrB_Index)); - bool *vals_B = malloc(nvals_B * sizeof(bool)); - - GrB_Matrix_extractTuples_BOOL(rows_A, cols_A, vals_A, &nvals_A, A.base); - GrB_Matrix_extractTuples_BOOL(rows_B, cols_B, vals_B, &nvals_B, B.base); - - bool equal = true; - for (GrB_Index i = 0; i < nvals_A; i++) { - bool found = false; - for (GrB_Index j = 0; j < nvals_B; j++) { - if (rows_A[i] == rows_B[j] && cols_A[i] == cols_B[j] && - vals_A[i] == vals_B[j]) { - found = true; - break; - } - } - if (!found) { - equal = false; - break; - } - } - TEST_CHECK(equal); + TEST_CHECK(compare_matrices(A, B)); // NULL Matrix GrB_Matrix old_base = A.base; @@ -962,59 +945,23 @@ static Matrix make_block_vector(size_t n, size_t alpha, Matrix_block format) { return CFL_matrix_from_base(result); - case VEC_HORIZ: - GrB_Matrix_new(&result, GrB_BOOL, n, n * alpha); - for (size_t i = 0; i < n * alpha; i++) { - for (size_t j = 0; j < n; j++) { - bool value = j == (i + 5 % n) || j == ((i + 6) % n) ? true : false; - if (!value) - continue; - - GrB_Matrix_setElement_BOOL(result, value, i, j); - } - } - - return CFL_matrix_from_base(result); + default: + break; } -} -static Matrix make_lazy_block_matrix(size_t base_matrices_count) { - size_t n = 0; - Matrix base_matrices[base_matrices_count]; - // 1 -> 1, 2 -> 11, 3 -> 111, 4 -> 1111 - for (size_t i = 0; i < base_matrices_count; i++) { - n *= 10; - n++; - } + // VEC_HORIZ: + GrB_Matrix_new(&result, GrB_BOOL, n, n * alpha); + for (size_t i = 0; i < n * alpha; i++) { + for (size_t j = 0; j < n; j++) { + bool value = j == (i + 5 % n) || j == ((i + 6) % n) ? true : false; + if (!value) + continue; - size_t tmp_n = 0; - for (size_t i = 0; i < base_matrices_count; i++) { - tmp_n *= 10; - tmp_n++; - GrB_Matrix base_matrix; - GrB_Matrix_new(&base_matrix, GrB_BOOL, n, n); - for (size_t j = 0; j < tmp_n; j++) { - // i+1 for future testing of sorting matrices - GrB_Matrix_setElement_BOOL(base_matrix, true, (i + 1) % base_matrices_count, - j); + GrB_Matrix_setElement_BOOL(result, value, i, j); } - - base_matrices[(i + 1) % base_matrices_count] = CFL_matrix_from_base(base_matrix); - } - - GrB_Matrix _result; - GrB_Matrix_new(&_result, GrB_BOOL, n, n); - Matrix result = CFL_matrix_from_base_lazy(_result); - - result.is_lazy = true; - result.base_matrices_count = base_matrices_count; - for (size_t i = 0; i < base_matrices_count; i++) { - result.base_matrices[i] = base_matrices[i]; } - CFL_matrix_update(&result); - - return result; + return CFL_matrix_from_base(result); } // TODO: create equality check with basic mxm From cd90d5e773f917c47017857988d6a6ba8f6eff93 Mon Sep 17 00:00:00 2001 From: homka122 Date: Tue, 4 Nov 2025 21:07:27 +0300 Subject: [PATCH 117/122] Fix: memory leaks in matrix_opt and in tests for opts --- .../LAGraph_CFL_optimized_matrix_opt.c | 38 ++++++++++++-- .../test/test_CFL_optimized_matrix_opt.c | 51 ++++++++++++++++--- 2 files changed, 76 insertions(+), 13 deletions(-) diff --git a/experimental/algorithm/LAGraph_CFL_optimized_matrix_opt.c b/experimental/algorithm/LAGraph_CFL_optimized_matrix_opt.c index 4a5eb89e7c..1492038b28 100644 --- a/experimental/algorithm/LAGraph_CFL_optimized_matrix_opt.c +++ b/experimental/algorithm/LAGraph_CFL_optimized_matrix_opt.c @@ -346,6 +346,7 @@ void block_matrix_repeat_into_vector(Matrix *matrix, Matrix *input, GxB_Matrix_concat(matrix->base, tiles, block_count, 1, GrB_NULL); CFL_matrix_update(matrix); + free(tiles); } // lazy optimization specific methods @@ -384,6 +385,8 @@ Matrix CFL_matrix_to_base(Matrix *input, int8_t optimizations) { GrB_Matrix _matrix; GrB_Matrix_new(&_matrix, GrB_BOOL, input->nrows, input->ncols); Matrix matrix = CFL_matrix_from_base_lazy(_matrix); + GrB_free(&_matrix); + matrix.base = NULL; for (size_t i = 0; i < input->base_matrices_count; i++) { Matrix base = CFL_matrix_create(input->nrows, input->ncols); @@ -420,6 +423,7 @@ GrB_Info matrix_combine_lazy(Matrix *A, size_t threshold, int8_t optimizations) GrB_free(&A->base_matrices[i].base); } + free(A->base_matrices); A->base_matrices = new_matrices; A->base_matrices_count = new_size; CFL_matrix_update(A); @@ -506,8 +510,24 @@ Matrix CFL_matrix_create(GrB_Index nrows, GrB_Index ncols) { // TODO: free all base_matrices, free format matrices void CFL_matrix_free(Matrix *matrix) { - free(matrix->base_matrices); - GrB_free(&matrix->base); + if (matrix->is_lazy) { + for (size_t i = 0; i < matrix->base_matrices_count; i++) { + CFL_matrix_free(&matrix->base_matrices[i]); + } + + free(matrix->base_matrices); + matrix->base_matrices = NULL; + return; + } + + if (matrix->is_both) { + // matrix->base is base_row or base_col + GrB_Matrix_free(&matrix->base_row); + GrB_Matrix_free(&matrix->base_col); + return; + } + + GrB_Matrix_free(&matrix->base); } // mxm operations @@ -613,13 +633,18 @@ GrB_Info matrix_mxm_lazy(Matrix *output, Matrix *first, Matrix *second, bool acc optimizations); GrB_free(&acc_matrices[i].base); } + free(accs); + free(acc_matrices); if (accum) { - return matrix_wise_empty(output, output, &acc_matrix, false, optimizations); + GrB_Info result = + matrix_wise_empty(output, output, &acc_matrix, false, optimizations); + CFL_matrix_free(&acc_matrix); + return result; } GrB_Info result = matrix_dup_block(output, &acc_matrix, optimizations); - GrB_free(&acc_matrix.base); + CFL_matrix_free(&acc_matrix); return result; } @@ -675,7 +700,10 @@ GrB_Info matrix_mxm_block(Matrix *output, Matrix *first, Matrix *second, bool ac Matrix temp = CFL_matrix_create(first->nrows, diag.ncols); matrix_mxm_lazy(&temp, first, &diag, false, swap, optimizations); - return matrix_wise_block(output, output, &temp, false, optimizations); + GrB_Info result = matrix_wise_block(output, output, &temp, false, optimizations); + CFL_matrix_free(&temp); + CFL_matrix_free(&diag); + return result; } // wise operations diff --git a/experimental/test/test_CFL_optimized_matrix_opt.c b/experimental/test/test_CFL_optimized_matrix_opt.c index 1b5d4ba008..bad66e0640 100644 --- a/experimental/test/test_CFL_optimized_matrix_opt.c +++ b/experimental/test/test_CFL_optimized_matrix_opt.c @@ -423,14 +423,17 @@ static void test_CFL_format_clear_format(void) { // NULL Matrix GrB_Matrix old_base = A.base; - GrB_Matrix old_base_row = A.base; + GrB_Matrix old_base_row = A.base_row; + GrB_Matrix old_base_col = A.base_col; A.base = NULL; A.base_row = NULL; + A.base_col = NULL; GrB_Info result = matrix_clear_format(&A, OPT_FORMAT); OK(!result); A.base = old_base; A.base_row = old_base_row; + A.base_col = old_base_col; CFL_matrix_free(&A); teardown(); @@ -455,14 +458,17 @@ static void test_CFL_format_dup_format(void) { // NULL Matrix GrB_Matrix old_base = A.base; - GrB_Matrix old_base_row = A.base; + GrB_Matrix old_base_row = A.base_row; + GrB_Matrix old_base_col = A.base_col; A.base = NULL; A.base_row = NULL; + A.base_col = NULL; GrB_Info result = matrix_dup_format(&A, &B, OPT_FORMAT); OK(!result); A.base = old_base; A.base_row = old_base_row; + A.base_col = old_base_col; CFL_matrix_free(&A); CFL_matrix_free(&B); @@ -471,6 +477,8 @@ static void test_CFL_format_dup_format(void) { B = CFL_matrix_create(5, 5); OK(matrix_to_format(&A, GrB_COLMAJOR, true)); OK(matrix_dup_format(&A, &B, 0)); + CFL_matrix_free(&A); + CFL_matrix_free(&B); teardown(); #endif @@ -488,6 +496,10 @@ static void test_CFL_format_mxm_second_greather_then_k(void) { OK(CFL_mxm(&C, &A, &B, false, false, OPT_FORMAT)); TEST_CHECK(C.nvals == 0); + free_matrix(&A); + free_matrix(&B); + free_matrix(&C); + teardown(); #endif } @@ -505,12 +517,15 @@ static void test_CFL_format_wise_when_both(void) { // NULL Matrix GrB_Matrix old_base = A.base; - GrB_Matrix old_base_row = A.base; + GrB_Matrix old_base_row = A.base_row; + GrB_Matrix old_base_col = A.base_col; A.base = NULL; A.base_row = NULL; + A.base_col = NULL; GrB_Info result = CFL_wise(&A, &A, &B, false, OPT_FORMAT); A.base = old_base; A.base_row = old_base_row; + A.base_col = old_base_col; OK(!result); CFL_matrix_free(&A); @@ -680,6 +695,9 @@ static void test_CFL_empty_rsub_both_empty(void) { OK(CFL_rsub(&A, &B, OPT_EMPTY)); TEST_CHECK(A.nvals == 0); + free_matrix(&A); + free_matrix(&B); + teardown(); #endif } @@ -700,6 +718,8 @@ static void test_CFL_lazy_create(void) { TEST_CHECK(A.is_lazy == true); TEST_CHECK(A.nvals == 0); + free_matrix(&A); + teardown(); #endif } @@ -737,6 +757,8 @@ static Matrix make_lazy_matrix(size_t base_matrices_count) { GrB_Matrix _result; GrB_Matrix_new(&_result, GrB_BOOL, n, n); Matrix result = CFL_matrix_from_base_lazy(_result); + GrB_free(&_result); + result.base = NULL; result.is_lazy = true; result.base_matrices_count = base_matrices_count; @@ -1010,6 +1032,9 @@ static void test_CFL_block_dup(void) { OK(CFL_dup(&B, &A, OPT_BLOCK)); TEST_CHECK(B.nvals == A.nvals); + + free_matrix(&A); + free_matrix(&B); } { @@ -1018,6 +1043,9 @@ static void test_CFL_block_dup(void) { OK(CFL_dup(&B, &A, OPT_BLOCK)); TEST_CHECK(B.nvals == A.nvals); + + free_matrix(&A); + free_matrix(&B); } { @@ -1026,6 +1054,9 @@ static void test_CFL_block_dup(void) { OK(CFL_dup(&B, &A, OPT_BLOCK)); TEST_CHECK(B.nvals == A.nvals); + + free_matrix(&A); + free_matrix(&B); } { @@ -1034,6 +1065,9 @@ static void test_CFL_block_dup(void) { OK(CFL_dup(&B, &A, OPT_BLOCK)); TEST_CHECK(B.nvals == A.nvals); + + free_matrix(&A); + free_matrix(&B); } teardown(); @@ -1114,16 +1148,17 @@ static void test_CFL_block_hyper_rotate(void) { GrB_Matrix _A; GrB_Matrix_new(&_A, GrB_BOOL, 20 * 20, 20); Matrix A = CFL_matrix_from_base_lazy(_A); + GrB_free(&_A); GrB_Matrix _A0; GrB_Matrix_new(&_A0, GrB_BOOL, 20 * 20, 20); Matrix A0 = CFL_matrix_from_base(_A0); GrB_Matrix _A1; GrB_Matrix_new(&_A1, GrB_BOOL, 20 * 20, 20); - Matrix A1 = CFL_matrix_from_base(_A0); + Matrix A1 = CFL_matrix_from_base(_A1); GrB_Matrix _A2; GrB_Matrix_new(&_A2, GrB_BOOL, 20 * 20, 20); - Matrix A2 = CFL_matrix_from_base(_A0); + Matrix A2 = CFL_matrix_from_base(_A2); A.base_matrices[0] = A0; A.base_matrices[1] = A1; @@ -1135,9 +1170,9 @@ static void test_CFL_block_hyper_rotate(void) { TEST_CHECK(A.ncols == 20 * 20); free_matrix(&A); - free_matrix(&A0); - free_matrix(&A1); - free_matrix(&A2); + // free_matrix(&A0); + // free_matrix(&A1); + // free_matrix(&A2); } // cell From 2e48806d2a3519dfd1e74bdc4b4942d83847579f Mon Sep 17 00:00:00 2001 From: homka122 Date: Wed, 22 Oct 2025 03:47:17 +0300 Subject: [PATCH 118/122] Fix: algorithm change input adj_matrices --- .../LAGraph_CFL_reachability_advanced.c | 546 ++++++++++++++++++ 1 file changed, 546 insertions(+) create mode 100644 experimental/algorithm/LAGraph_CFL_reachability_advanced.c diff --git a/experimental/algorithm/LAGraph_CFL_reachability_advanced.c b/experimental/algorithm/LAGraph_CFL_reachability_advanced.c new file mode 100644 index 0000000000..6e48f0c95e --- /dev/null +++ b/experimental/algorithm/LAGraph_CFL_reachability_advanced.c @@ -0,0 +1,546 @@ +//------------------------------------------------------------------------------ +// LAGraph_CFL_reachability.c: Context-Free Language Reachability Matrix-Based +// Algorithm +// ------------------------------------------------------------------------------ +// +// LAGraph, (c) 2019-2024 by The LAGraph Contributors, All Rights Reserved. +// SPDX-License-Identifier: BSD-2-Clause + +// Contributed by Ilhom Kombaev, Semyon Grigoriev, St. Petersburg State University. + +//------------------------------------------------------------------------------ + +// Code is based on the "A matrix-based CFPQ algorithm" described in the +// following paper: * Rustam Azimov, Semyon Grigorev, "Context-Free Path +// Querying Using Linear Algebra", URL: +// https://disser.spbu.ru/files/2022/disser_azimov.pdf + +#define LG_FREE_WORK \ + { \ + GrB_free(&identity_matrix); \ + } + +#define LG_FREE_ALL \ + { \ + for (size_t i = 0; i < symbols_amount; i++) { \ + /* TODO: delete it and free actual matrices */ \ + /* GrB_free(&T[i]); */ \ + } \ + \ + LG_FREE_WORK; \ + } + +#include "LG_internal.h" +#include + +#define ERROR_RULE(msg) \ + { \ + LG_ASSERT_MSGF(false, GrB_INVALID_VALUE, "Rule with index %ld is invalid. " msg, \ + i); \ + } + +#define ADD_TO_MSG(...) \ + { \ + if (msg_len == 0) { \ + msg_len += \ + snprintf(msg, LAGRAPH_MSG_LEN, \ + "LAGraph failure (file %s, line %d): ", __FILE__, __LINE__); \ + } \ + if (msg_len < LAGRAPH_MSG_LEN) { \ + msg_len += snprintf(msg + msg_len, LAGRAPH_MSG_LEN - msg_len, __VA_ARGS__); \ + } \ + } + +#define ADD_INDEX_TO_ERROR_RULE(rule, i) \ + { \ + rule.len_indexes_str += snprintf(rule.indexes_str + rule.len_indexes_str, \ + LAGRAPH_MSG_LEN - rule.len_indexes_str, \ + rule.count == 0 ? "%ld" : ", %ld", i); \ + rule.count++; \ + } + +// clang-format off +#if BENCH_CFL_REACHBILITY + #define IS_ISO(matrix, str) \ + { \ + bool iso_flag; \ + GrB_Index nnz; \ + GxB_Matrix_iso(&iso_flag, matrix); \ + GrB_Matrix_nvals(&nnz, matrix); \ + if (!iso_flag && nnz) { \ + printf("-----ISO ALERT----- (%s)\n", str); \ + GxB_print(matrix, 1); \ + printf("-------------------\n"); \ + } \ + } + + #define TIMER_START() \ + { \ + start_time = LAGraph_WallClockTime(); \ + } + + #define TIMER_STOP(label, accumulator) \ + { \ + end_time = LAGraph_WallClockTime(); \ + printf("%s %.3fs\n", label, end_time - start_time); \ + if (accumulator != NULL) { \ + *(accumulator) += (end_time - start_time); \ + } \ + } + + #define IS_ROW(matrix, str) \ + { \ + int32_t orientation; \ + GrB_get(matrix, &orientation, GrB_STORAGE_ORIENTATION_HINT); \ + if (orientation != GrB_ROWMAJOR) { \ + printf("-----NOT A ROW----- (%s)\n", str); \ + GxB_print(matrix, 1); \ + printf("-------------------\n"); \ + } \ + } + + #define IS_COL(matrix, str) \ + { \ + int32_t orientation; \ + GrB_get(matrix, &orientation, GrB_STORAGE_ORIENTATION_HINT); \ + if (orientation != GrB_COLMAJOR) { \ + printf("-----NOT A COL----- (%s)\n", str); \ + GxB_print(matrix, 1); \ + printf("-------------------\n"); \ + } \ + } +#else + #define IS_ISO(matrix, str) + #define TIMER_START() + #define TIMER_STOP(label, accumulator) + #define IS_ROW(matrix, str) + #define IS_COL(matrix, str) +#endif +// clang-format on + +#define OPT_EMPTY (1 << 0) +#define OPT_FORMAT (1 << 1) +#define OPT_LAZY (1 << 2) +#define OPT_BLOCK (1 << 3) + +#define TRY(GrB_method) \ + { \ + GrB_Info LG_GrB_Info = GrB_method; \ + if (LG_GrB_Info < GrB_SUCCESS) { \ + fprintf(stderr, "LAGraph failure (file %s, line %d): ", __FILE__, __LINE__); \ + exit(LG_GrB_Info); \ + } \ + } + +// LAGraph_CFL_reachability: Context-Free Language Reachability Matrix-Based Algorithm +// +// This function determines the set of vertex pairs (u, v) in a graph (represented by +// adjacency matrices) such that there is a path from u to v, where the edge labels +// form a word from the language generated by the context-free grammar (represented by +// `rules`). +// +// Terminals and non-terminals are enumerated by integers starting from zero. +// The start non-terminal is the non-terminal with index 0. +// +// Example: +// +// Graph: +// ┌───┐ ┌───┐ ┌───┐ ┌───┐ ┌───┐ +// │ 0 ├───► 1 ├───► 2 ├───► 3 ├───► 4 │ +// └───┘ a └─┬─┘ a └─▲─┘ b └───┘ b └───┘ +// │ │ +// │ ┌───┐ │ +// a└─► 5 ├─┘b +// └───┘ +// +// Grammar: S -> aSb | ab +// +// There are paths from node [1] to node [3] and from node [1] to node [2] that form +// the word "ab" ([1]-a->[2]-b->[3] and [1]-a->[5]-b->[2]). The word "ab" is in the +// language generated by our context-free grammar, so the pairs (1, 3) and (1, 2) will +// be included in the result. +// +// Note: It doesn't matter how many paths exist from node [A] to node [B] that form a +// word in the language. If at least one path exists, the pair ([A], [B]) will be +// included in the result. +// +// In contrast, the path from node [1] to node [4] forms the word "abb" +// ([1]-a->[2]-b->[3]-b->[4]) and the word "abbb" ([1]-a->[5]-b->[2]-b->[3]-b->[4]). +// The words "aab" and "abbb" are not in the language, so the pair (1, 4) will not be +// included in the result. +// +// With this graph and grammar, we obtain the following results: +// (0, 4) - because there exists a path (0-1-2-3-4) that forms the word "aabb" +// (1, 3) - because there exists a path (1-2-3) that forms "ab" +// (1, 2) - because there exists a path (1-5-2) that forms the word "ab" +// (0, 3) - because there exists a path (0-1-5-2-3) that forms the word "aabb" +GrB_Info LAGraph_CFL_reachability_adv( + // Output + GrB_Matrix *outputs, // Array of matrices containing results. + // The size of the array must be equal to nonterms_count. + // + // outputs[k]: (i, j) = true if and only if there is a path + // from node i to node j whose edge labels form a word + // derivable from the non-terminal 'k' of the specified CFG. + // Input + const GrB_Matrix *adj_matrices, // Array of adjacency matrices representing the graph. + // The length of this array is equal to the count of + // terminals (terms_count). + // + // adj_matrices[t]: (i, j) == 1 if and only if there + // is an edge between nodes i and j with the label of + // the terminal corresponding to index 't' (where t is + // in the range [0, terms_count - 1]). + size_t symbols_amount, + const LAGraph_rule_WCNF *rules, // The rules of the CFG. + size_t rules_count, // The total number of rules in the CFG. + char *msg, // Message string for error reporting. + int8_t optimizations // Optimizations flags +) { + // Declare workspace and clear the msg string, if not NULL + CFL_Matrix *delta_matrices, *matrices, *temp_matrices; + CFL_Matrix iden; + GrB_Matrix identity_matrix = NULL; + LG_CLEAR_MSG; + size_t msg_len = 0; // For error formatting + + LG_TRY(LAGraph_Calloc((void **)&delta_matrices, symbols_amount, sizeof(CFL_Matrix), + msg)); + LG_TRY(LAGraph_Calloc((void **)&matrices, symbols_amount, sizeof(CFL_Matrix), msg)); + LG_TRY( + LAGraph_Calloc((void **)&temp_matrices, symbols_amount, sizeof(CFL_Matrix), msg)); + + LG_ASSERT_MSG(symbols_amount > 0, GrB_INVALID_VALUE, + "The number of symbols must be greater than zero."); + LG_ASSERT_MSG(rules_count > 0, GrB_INVALID_VALUE, + "The number of rules must be greater than zero."); + LG_ASSERT_MSG(outputs != NULL, GrB_NULL_POINTER, "The outputs array cannot be null."); + LG_ASSERT_MSG(rules != NULL, GrB_NULL_POINTER, "The rules array cannot be null."); + LG_ASSERT_MSG(adj_matrices != NULL, GrB_NULL_POINTER, + "The adjacency matrices array cannot be null."); + + // Find null adjacency matrices + bool found_null = false; + for (size_t i = 0; i < symbols_amount; i++) { + if (adj_matrices[i] != NULL) + continue; + + if (!found_null) { + ADD_TO_MSG("Adjacency matrices with these indexes are null: "); + ADD_TO_MSG("%ld", i); + } else { + ADD_TO_MSG(", %ld", i); + } + + found_null = true; + } + + if (found_null) { + LG_FREE_ALL; + return GrB_NULL_POINTER; + } + + GrB_Index n; + GRB_TRY(GrB_Matrix_ncols(&n, adj_matrices[0])); + + // Create nonterms matrices + for (size_t i = 0; i < symbols_amount; i++) { + GrB_Matrix matrix; + + GrB_Index nrows; + GrB_Matrix_nrows(&nrows, adj_matrices[i]); + GrB_Index ncols; + GrB_Matrix_ncols(&ncols, adj_matrices[i]); + + GrB_Matrix new_adj_matrix; + GrB_Matrix_dup(&new_adj_matrix, adj_matrices[i]); + delta_matrices[i] = CFL_matrix_from_base(new_adj_matrix); + + GRB_TRY(GrB_Matrix_new(&matrix, GrB_BOOL, nrows, ncols)); + matrices[i] = ((optimizations & OPT_LAZY) || (optimizations & OPT_BLOCK)) + ? CFL_matrix_from_base_lazy(matrix) + : CFL_matrix_from_base(matrix); + + GRB_TRY(GrB_Matrix_new(&matrix, GrB_BOOL, nrows, ncols)); + temp_matrices[i] = CFL_matrix_from_base(matrix); + } + + // Arrays for processing rules + size_t eps_rules[rules_count], eps_rules_count = 0; // [Variable -> eps] + size_t term_rules[rules_count], term_rules_count = 0; // [Variable -> term] + size_t bin_rules[rules_count], bin_rules_count = 0; // [Variable -> AB] + + // Process rules + typedef struct { + size_t count; + size_t len_indexes_str; + char indexes_str[LAGRAPH_MSG_LEN]; + } rule_error_s; + rule_error_s term_err = {0}; + rule_error_s nonterm_err = {0}; + rule_error_s invalid_err = {0}; + for (size_t i = 0; i < rules_count; i++) { + LAGraph_rule_WCNF rule = rules[i]; + + bool is_rule_eps = rule.prod_A == -1 && rule.prod_B == -1; + bool is_rule_term = rule.prod_A != -1 && rule.prod_B == -1; + bool is_rule_bin = rule.prod_A != -1 && rule.prod_B != -1; + + // Check that all rules are well-formed + if (rule.nonterm < 0 || (size_t)rule.nonterm >= symbols_amount) { + ADD_INDEX_TO_ERROR_RULE(nonterm_err, i); + } + + // [Variable -> eps] + if (is_rule_eps) { + eps_rules[eps_rules_count++] = i; + + continue; + } + + // [Variable -> term] + if (is_rule_term) { + term_rules[term_rules_count++] = i; + + if (rule.prod_A < -1 || (size_t)rule.prod_A >= symbols_amount) { + ADD_INDEX_TO_ERROR_RULE(term_err, i); + } + + continue; + } + + // [Variable -> A B] + if (is_rule_bin) { + bin_rules[bin_rules_count++] = i; + + if (rule.prod_A < -1 || (size_t)rule.prod_A >= symbols_amount || + rule.prod_B < -1 || (size_t)rule.prod_B >= symbols_amount) { + ADD_INDEX_TO_ERROR_RULE(nonterm_err, i); + } + + continue; + } + + // [Variable -> _ B] + ADD_INDEX_TO_ERROR_RULE(invalid_err, i); + } + + if (term_err.count + nonterm_err.count + invalid_err.count > 0) { + ADD_TO_MSG("Count of invalid rules: %ld.\n", + term_err.count + nonterm_err.count + invalid_err.count); + + if (nonterm_err.count > 0) { + ADD_TO_MSG("Non-terminals must be in range [0, nonterms_count). "); + ADD_TO_MSG("Indexes of invalid rules: %s\n", nonterm_err.indexes_str) + } + if (term_err.count > 0) { + ADD_TO_MSG("Terminals must be in range [-1, nonterms_count). "); + ADD_TO_MSG("Indexes of invalid rules: %s\n", term_err.indexes_str) + } + if (invalid_err.count > 0) { + ADD_TO_MSG("[Variable -> _ B] type of rule is not acceptable. "); + ADD_TO_MSG("Indexes of invalid rules: %.120s\n", invalid_err.indexes_str) + } + + LG_FREE_ALL; + return GrB_INVALID_VALUE; + } + + // Rule [Variable -> term] + for (size_t i = 0; i < term_rules_count; i++) { + LAGraph_rule_WCNF term_rule = rules[term_rules[i]]; + CFL_Matrix *nonterm_matrix = &delta_matrices[term_rule.nonterm]; + CFL_Matrix *term_matrix = &delta_matrices[term_rule.prod_A]; + + GRB_TRY( + CFL_wise(nonterm_matrix, nonterm_matrix, term_matrix, true, optimizations)); + +#ifdef DEBUG_CFL_REACHBILITY + // GxB_Matrix_iso(&iso_flag, T[term_rule.nonterm]); + printf("[TERM] eWiseUnion: NONTERM: %d (ISO: %d)\n", term_rule.nonterm, iso_flag); +#endif + } + + GrB_Vector v_diag; + GRB_TRY(GrB_Vector_new(&v_diag, GrB_BOOL, n)); + GRB_TRY(GrB_Vector_assign_BOOL(v_diag, GrB_NULL, GrB_NULL, true, GrB_ALL, n, NULL)); + GRB_TRY(GrB_Matrix_diag(&identity_matrix, v_diag, 0)); + GRB_TRY(GrB_free(&v_diag)); + iden = CFL_matrix_from_base(identity_matrix); + + // Rule [Variable -> eps] + for (size_t i = 0; i < eps_rules_count; i++) { + LAGraph_rule_WCNF eps_rule = rules[eps_rules[i]]; + + CFL_Matrix *nonterm_matrix = &delta_matrices[eps_rule.nonterm]; + + CFL_wise(nonterm_matrix, nonterm_matrix, &iden, true, optimizations); + +#ifdef DEBUG_CFL_REACHBILITY + // GxB_Matrix_iso(&iso_flag, T[eps_rule.nonterm]); + printf("[EPS] eWiseUnion: NONTERM: %d (ISO: %d)\n", eps_rule.nonterm, iso_flag); +#endif + } + + // Rule [Variable -> Variable1 Variable2] + double start_time, end_time; + bool changed = true; + size_t iteration = 0; + double mxm1 = 0.0; + double wise1 = 0.0; + double mxm2 = 0.0; + double wise2 = 0.0; + double rsubt = 0.0; + // print_graph_info(matrices, symbols_amount); + // print_graph_info(delta_matrices, symbols_amount); + // print_graph_info(temp_matrices, symbols_amount); + while (changed) { + iteration++; + changed = false; + +#if BENCH_CFL_REACHBILITY + printf("\n--- ITERATARION %ld ---\n", iteration); +#endif + + for (size_t i = 0; i < symbols_amount; i++) { + GRB_TRY(CFL_clear(&temp_matrices[i], optimizations)); + } + + TIMER_START(); + for (size_t i = 0; i < bin_rules_count; i++) { + LAGraph_rule_WCNF bin_rule = rules[bin_rules[i]]; + CFL_Matrix *A = &matrices[bin_rule.prod_A]; + CFL_Matrix *B = &delta_matrices[bin_rule.prod_B]; + CFL_Matrix *C = &temp_matrices[bin_rule.nonterm]; + + // printf("MXM 1 iteration: %ld i: %ld\n", iteration, i); + // matrix_print_lazy(A); + // matrix_print_lazy(B); + // matrix_print_lazy(C); + CFL_mxm(C, A, B, true, false, optimizations); + // matrix_print_lazy(C); + } + TIMER_STOP("MXM 1", &mxm1); + // print_graph_info(matrices, symbols_amount); + // print_graph_info(delta_matrices, symbols_amount); + // print_graph_info(temp_matrices, symbols_amount); + + TIMER_START() + for (size_t i = 0; i < symbols_amount; i++) { + CFL_Matrix *A = &delta_matrices[i]; + CFL_Matrix *C = &matrices[i]; + + // printf("WISE 1 iteration: %ld i: %ld\n", iteration, i); + // matrix_print_lazy(A); + // matrix_print_lazy(C); + CFL_wise(C, C, A, false, optimizations); + // matrix_print_lazy(C); + } + TIMER_STOP("WISE 1", &wise1); + // print_graph_info(matrices, symbols_amount); + // print_graph_info(delta_matrices, symbols_amount); + // print_graph_info(temp_matrices, symbols_amount); + + TIMER_START() + for (size_t i = 0; i < bin_rules_count; i++) { + LAGraph_rule_WCNF bin_rule = rules[bin_rules[i]]; + CFL_Matrix *A = &matrices[bin_rule.prod_B]; + CFL_Matrix *B = &delta_matrices[bin_rule.prod_A]; + CFL_Matrix *C = &temp_matrices[bin_rule.nonterm]; + + // printf("MXM 2 iteration: %ld i: %ld\n", iteration, i); + // matrix_print_lazy(A); + // matrix_print_lazy(B); + // matrix_print_lazy(C); + CFL_mxm(C, A, B, true, true, optimizations); + // matrix_print_lazy(C); + } + TIMER_STOP("MXM 2", &mxm2); + // print_graph_info(matrices, symbols_amount); + // print_graph_info(delta_matrices, symbols_amount); + // print_graph_info(temp_matrices, symbols_amount); + + // Rule [Variable -> term] + for (size_t i = 0; i < term_rules_count; i++) { + LAGraph_rule_WCNF term_rule = rules[term_rules[i]]; + CFL_Matrix *A = &temp_matrices[term_rule.nonterm]; + CFL_Matrix *B = &delta_matrices[term_rule.prod_A]; + + // printf("Simple rules iteration: %ld i: %ld\n", iteration, i); + // matrix_print_lazy(A); + // matrix_print_lazy(B); + CFL_wise(A, A, B, true, optimizations); + // matrix_print_lazy(A); + } + // printf("Simple rules\n"); + // print_graph_info(matrices, symbols_amount); + // print_graph_info(delta_matrices, symbols_amount); + // print_graph_info(temp_matrices, symbols_amount); + + TIMER_START(); + for (size_t i = 0; i < symbols_amount; i++) { + CFL_dup(&delta_matrices[i], &temp_matrices[i], optimizations); + } + TIMER_STOP("WISE 2 (copy)", &wise2); + // print_graph_info(matrices, symbols_amount); + // print_graph_info(delta_matrices, symbols_amount); + // print_graph_info(temp_matrices, symbols_amount); + + TIMER_START(); + for (size_t i = 0; i < symbols_amount; i++) { + CFL_Matrix *A = &matrices[i]; + CFL_Matrix *C = &delta_matrices[i]; + + // printf("RSUB iteration: %ld i: %ld\n", iteration, i); + // matrix_print_lazy(A); + // matrix_print_lazy(C); + TRY(CFL_rsub(C, A, optimizations)); + // matrix_print_lazy(C); + } + TIMER_STOP("WISE 3 (MASK)", &rsubt); + // print_graph_info(matrices, symbols_amount); + // print_graph_info(delta_matrices, symbols_amount); + // print_graph_info(temp_matrices, symbols_amount); + + size_t new_nnz = 0; + for (size_t i = 0; i < symbols_amount; i++) { + CFL_matrix_update(&delta_matrices[i]); + new_nnz += delta_matrices[i].nvals; + } + + if (new_nnz != 0) { + changed = true; + } + +#ifdef DEBUG_CFL_REACHBILITY + // GxB_Matrix_iso(&iso_flag, T[bin_rule.nonterm]); + printf("[TERM1 TERM2] MULTIPLY, S: %d, A: %d, B: %d, " + "I: %ld (ISO: %d)\n", + bin_rule.nonterm, bin_rule.prod_A, bin_rule.prod_B, i, iso_flag); +#endif + } + +#if BENCH_CFL_REACHBILITY + printf("MXM1: %.3f, wise1: %.3f, MXM2: %.3f, wise2: %.3f, rsub: %.3f", mxm1, wise1, + mxm2, wise2, rsubt); +#endif + +#ifdef DEBUG_CFL_REACHBILITY + for (int32_t i = 0; i < nonterms_count; i++) { + printf("MATRIX WITH INDEX %d:\n", i); + // GxB_print(T[i], GxB_SUMMARY); + } +#endif + + for (size_t i = 0; i < symbols_amount; i++) { + if (matrices[i].base_matrices_count == 0) { + outputs[i] = matrices[i].base; + } else { + outputs[i] = CFL_matrix_lazy_to_base(&matrices[i], optimizations); + } + // outputs[i] = matrices[i].base; + } + + LG_FREE_WORK; + return GrB_SUCCESS; +} From 91e83ac002e3de3f06265450ffe5190668940c7b Mon Sep 17 00:00:00 2001 From: homka122 Date: Sat, 1 Nov 2025 21:56:48 +0300 Subject: [PATCH 119/122] Refactor: apply clang-format to code --- .../LAGraph_CFL_reachability_advanced.c | 91 +++++++++---------- 1 file changed, 45 insertions(+), 46 deletions(-) diff --git a/experimental/algorithm/LAGraph_CFL_reachability_advanced.c b/experimental/algorithm/LAGraph_CFL_reachability_advanced.c index 6e48f0c95e..883bf10be5 100644 --- a/experimental/algorithm/LAGraph_CFL_reachability_advanced.c +++ b/experimental/algorithm/LAGraph_CFL_reachability_advanced.c @@ -59,56 +59,55 @@ rule.count++; \ } -// clang-format off #if BENCH_CFL_REACHBILITY - #define IS_ISO(matrix, str) \ - { \ - bool iso_flag; \ - GrB_Index nnz; \ - GxB_Matrix_iso(&iso_flag, matrix); \ - GrB_Matrix_nvals(&nnz, matrix); \ - if (!iso_flag && nnz) { \ - printf("-----ISO ALERT----- (%s)\n", str); \ - GxB_print(matrix, 1); \ - printf("-------------------\n"); \ - } \ - } + #define IS_ISO(matrix, str) \ + { \ + bool iso_flag; \ + GrB_Index nnz; \ + GxB_Matrix_iso(&iso_flag, matrix); \ + GrB_Matrix_nvals(&nnz, matrix); \ + if (!iso_flag && nnz) { \ + printf("-----ISO ALERT----- (%s)\n", str); \ + GxB_print(matrix, 1); \ + printf("-------------------\n"); \ + } \ + } - #define TIMER_START() \ - { \ - start_time = LAGraph_WallClockTime(); \ - } + #define TIMER_START() \ + { \ + start_time = LAGraph_WallClockTime(); \ + } - #define TIMER_STOP(label, accumulator) \ - { \ - end_time = LAGraph_WallClockTime(); \ - printf("%s %.3fs\n", label, end_time - start_time); \ - if (accumulator != NULL) { \ - *(accumulator) += (end_time - start_time); \ - } \ - } + #define TIMER_STOP(label, accumulator) \ + { \ + end_time = LAGraph_WallClockTime(); \ + printf("%s %.3fs\n", label, end_time - start_time); \ + if (accumulator != NULL) { \ + *(accumulator) += (end_time - start_time); \ + } \ + } - #define IS_ROW(matrix, str) \ - { \ - int32_t orientation; \ - GrB_get(matrix, &orientation, GrB_STORAGE_ORIENTATION_HINT); \ - if (orientation != GrB_ROWMAJOR) { \ - printf("-----NOT A ROW----- (%s)\n", str); \ - GxB_print(matrix, 1); \ - printf("-------------------\n"); \ - } \ - } + #define IS_ROW(matrix, str) \ + { \ + int32_t orientation; \ + GrB_get(matrix, &orientation, GrB_STORAGE_ORIENTATION_HINT); \ + if (orientation != GrB_ROWMAJOR) { \ + printf("-----NOT A ROW----- (%s)\n", str); \ + GxB_print(matrix, 1); \ + printf("-------------------\n"); \ + } \ + } - #define IS_COL(matrix, str) \ - { \ - int32_t orientation; \ - GrB_get(matrix, &orientation, GrB_STORAGE_ORIENTATION_HINT); \ - if (orientation != GrB_COLMAJOR) { \ - printf("-----NOT A COL----- (%s)\n", str); \ - GxB_print(matrix, 1); \ - printf("-------------------\n"); \ - } \ - } + #define IS_COL(matrix, str) \ + { \ + int32_t orientation; \ + GrB_get(matrix, &orientation, GrB_STORAGE_ORIENTATION_HINT); \ + if (orientation != GrB_COLMAJOR) { \ + printf("-----NOT A COL----- (%s)\n", str); \ + GxB_print(matrix, 1); \ + printf("-------------------\n"); \ + } \ + } #else #define IS_ISO(matrix, str) #define TIMER_START() @@ -245,7 +244,6 @@ GrB_Info LAGraph_CFL_reachability_adv( // Create nonterms matrices for (size_t i = 0; i < symbols_amount; i++) { - GrB_Matrix matrix; GrB_Index nrows; GrB_Matrix_nrows(&nrows, adj_matrices[i]); @@ -256,6 +254,7 @@ GrB_Info LAGraph_CFL_reachability_adv( GrB_Matrix_dup(&new_adj_matrix, adj_matrices[i]); delta_matrices[i] = CFL_matrix_from_base(new_adj_matrix); + GrB_Matrix matrix; GRB_TRY(GrB_Matrix_new(&matrix, GrB_BOOL, nrows, ncols)); matrices[i] = ((optimizations & OPT_LAZY) || (optimizations & OPT_BLOCK)) ? CFL_matrix_from_base_lazy(matrix) From 5abeb7242dfc811279516c2228249db35b7ff6d5 Mon Sep 17 00:00:00 2001 From: homka122 Date: Tue, 4 Nov 2025 21:06:44 +0300 Subject: [PATCH 120/122] Fix: change matrix_to_base function --- experimental/algorithm/LAGraph_CFL_reachability_advanced.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/experimental/algorithm/LAGraph_CFL_reachability_advanced.c b/experimental/algorithm/LAGraph_CFL_reachability_advanced.c index 883bf10be5..714793f50f 100644 --- a/experimental/algorithm/LAGraph_CFL_reachability_advanced.c +++ b/experimental/algorithm/LAGraph_CFL_reachability_advanced.c @@ -535,7 +535,8 @@ GrB_Info LAGraph_CFL_reachability_adv( if (matrices[i].base_matrices_count == 0) { outputs[i] = matrices[i].base; } else { - outputs[i] = CFL_matrix_lazy_to_base(&matrices[i], optimizations); + CFL_Matrix result = CFL_matrix_to_base(&matrices[i], optimizations); + outputs[i] = result.base; } // outputs[i] = matrices[i].base; } From 56d0fa2fecbe4aae7552920e4c9dcdec3ca1be6a Mon Sep 17 00:00:00 2001 From: homka122 Date: Tue, 4 Nov 2025 21:12:45 +0300 Subject: [PATCH 121/122] Fix: add adv algorithm signature to LAGraphX.h --- include/LAGraphX.h | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/include/LAGraphX.h b/include/LAGraphX.h index 368261cfec..2eb44a7be0 100644 --- a/include/LAGraphX.h +++ b/include/LAGraphX.h @@ -1150,6 +1150,33 @@ CFL_Matrix CFL_matrix_to_base GrB_Info CFL_clear(CFL_Matrix *A, int8_t optimizations); +GrB_Info LAGraph_CFL_reachability_adv +( + // Output + GrB_Matrix *outputs, // Array of matrices containing results. + // The size of the array must be equal to nonterms_count. + // + // outputs[k]: (i, j) = true if and only if there is a path + // from node i to node j whose edge labels form a word + // derivable from the non-terminal 'k' of the specified CFG. + // Input + const GrB_Matrix *adj_matrices, // Array of adjacency matrices representing the graph. + // The length of this array is equal to the count of + // terminals (terms_count). + // + // adj_matrices[t]: (i, j) == 1 if and only if there + // is an edge between nodes i and j with the label of + // the terminal corresponding to index 't' (where t is + // in the range [0, terms_count - 1]). + size_t symbols_amount, + const LAGraph_rule_WCNF *rules, // The rules of the CFG. + size_t rules_count, // The total number of rules in the CFG. + char *msg, // Message string for error reporting. + int8_t optimizations // Optimizations flags +); + + + //------------------------------------------------------------------------------ // a simple example of an algorithm //------------------------------------------------------------------------------ From b13a24412d5356e61714db40f59538296c5bef93 Mon Sep 17 00:00:00 2001 From: homka122 Date: Wed, 5 Nov 2025 01:10:24 +0300 Subject: [PATCH 122/122] Test: add tests for adv CFL reachability algorithm --- .../LAGraph_CFL_reachability_advanced.c | 5 +- experimental/test/test_CFL_reachability_adv.c | 757 ++++++++++++++++++ 2 files changed, 759 insertions(+), 3 deletions(-) create mode 100644 experimental/test/test_CFL_reachability_adv.c diff --git a/experimental/algorithm/LAGraph_CFL_reachability_advanced.c b/experimental/algorithm/LAGraph_CFL_reachability_advanced.c index 714793f50f..194d719574 100644 --- a/experimental/algorithm/LAGraph_CFL_reachability_advanced.c +++ b/experimental/algorithm/LAGraph_CFL_reachability_advanced.c @@ -256,9 +256,8 @@ GrB_Info LAGraph_CFL_reachability_adv( GrB_Matrix matrix; GRB_TRY(GrB_Matrix_new(&matrix, GrB_BOOL, nrows, ncols)); - matrices[i] = ((optimizations & OPT_LAZY) || (optimizations & OPT_BLOCK)) - ? CFL_matrix_from_base_lazy(matrix) - : CFL_matrix_from_base(matrix); + matrices[i] = ((optimizations & OPT_LAZY)) ? CFL_matrix_from_base_lazy(matrix) + : CFL_matrix_from_base(matrix); GRB_TRY(GrB_Matrix_new(&matrix, GrB_BOOL, nrows, ncols)); temp_matrices[i] = CFL_matrix_from_base(matrix); diff --git a/experimental/test/test_CFL_reachability_adv.c b/experimental/test/test_CFL_reachability_adv.c new file mode 100644 index 0000000000..00035c1101 --- /dev/null +++ b/experimental/test/test_CFL_reachability_adv.c @@ -0,0 +1,757 @@ +//------------------------------------------------------------------------------ +// LAGraph/experimental/test/LAGraph_CFL_reachability.c: test cases for Context-Free +// Language Reachability Matrix-Based Algorithm +//------------------------------------------------------------------------------ +// +// LAGraph, (c) 2019-2024 by The LAGraph Contributors, All Rights Reserved. +// SPDX-License-Identifier: BSD-2-Clause + +// Contributed by Ilhom Kombaev, Semyon Grigoriev, St. Petersburg State University. + +//------------------------------------------------------------------------------ + +#include +#include +#include +#include +#include +#include + +#define run_algorithm(mask) \ + LAGraph_CFL_reachability_adv(outputs, adj_matrices, \ + grammar.terms_count + grammar.nonterms_count, \ + grammar.rules, grammar.rules_count, msg, mask) + +#define check_error(error, mask) \ + { \ + retval = run_algorithm(mask); \ + TEST_CHECK(retval == error); \ + TEST_MSG("retval = %d (%s)", retval, msg); \ + } + +#define check_result(result) \ + { \ + char *expected = output_to_str(0); \ + TEST_CHECK(strcmp(result, expected) == 0); \ + TEST_MSG("Wrong result. Mask: %x. Actual: %s", mask, expected); \ + LAGraph_Free((void **)&expected, msg); \ + } + +typedef struct { + size_t nonterms_count; + size_t terms_count; + size_t rules_count; + LAGraph_rule_WCNF *rules; +} grammar_t; + +GrB_Matrix *adj_matrices = NULL; +int n_adj_matrices = 0; +GrB_Matrix *outputs = NULL; +grammar_t grammar = {0, 0, 0, NULL}; +char msg[LAGRAPH_MSG_LEN]; + +void setup() { LAGraph_Init(msg); } + +void teardown(void) { LAGraph_Finalize(msg); } + +void init_outputs() { + LAGraph_Calloc((void **)&outputs, grammar.nonterms_count + grammar.terms_count, + sizeof(GrB_Matrix), msg); +} + +char *output_to_str(size_t nonterm) { + GrB_Index nnz = 0; + OK(GrB_Matrix_nvals(&nnz, outputs[nonterm])); + GrB_Index *row = NULL; + GrB_Index *col = NULL; + bool *val = NULL; + LAGraph_Malloc((void **)&row, nnz, sizeof(GrB_Index), msg); + LAGraph_Malloc((void **)&col, nnz, sizeof(GrB_Index), msg); + LAGraph_Malloc((void **)&val, nnz, sizeof(GrB_Index), msg); + + GrB_set(outputs[nonterm], GrB_ROWMAJOR, GrB_STORAGE_ORIENTATION_HINT); + OK(GrB_Matrix_extractTuples(row, col, val, &nnz, outputs[nonterm])); + + // 11 - size of " (%ld, %ld)" + char *result_str = NULL; + LAGraph_Malloc((void **)&result_str, 11 * nnz, sizeof(char), msg); + + result_str[0] = '\0'; + for (size_t i = 0; i < nnz; i++) { + sprintf(result_str + strlen(result_str), + i == 0 ? "(%" PRIu64 ", %" PRIu64 ")" : " (%" PRIu64 ", %" PRIu64 ")", + row[i], col[i]); + } + + LAGraph_Free((void **)&row, msg); + LAGraph_Free((void **)&col, msg); + LAGraph_Free((void **)&val, msg); + + return result_str; +} + +void free_workspace() { + + if (adj_matrices != NULL) { + for (size_t i = 0; i < n_adj_matrices; i++) { + GrB_free(&adj_matrices[i]); + } + } + LAGraph_Free((void **)&adj_matrices, msg); + + if (outputs != NULL) { + for (size_t i = 0; i < grammar.nonterms_count; i++) { + GrB_free(&outputs[i]); + } + } + LAGraph_Free((void **)&outputs, msg); + + LAGraph_Free((void **)&grammar.rules, msg); + grammar = (grammar_t){0, 0, 0, NULL}; +} + +//==================== +// Grammars +//==================== + +// S -> aSb | ab in WCNF +// +// Terms: [4 a] [5 b] +// Nonterms: [0 S] [1 A] [2 B] [3 C] +// S -> AB [0 1 2 0] +// S -> AC [0 1 3 0] +// C -> SB [3 0 2 0] +// A -> a [1 4 -1 0] +// B -> b [2 5 -1 0] +void init_grammar_aSb() { + LAGraph_rule_WCNF *rules = NULL; + LAGraph_Calloc((void **)&rules, 5, sizeof(LAGraph_rule_WCNF), msg); + + rules[0] = (LAGraph_rule_WCNF){0, 1, 2, 0}; + rules[1] = (LAGraph_rule_WCNF){0, 1, 3, 0}; + rules[2] = (LAGraph_rule_WCNF){3, 0, 2, 0}; + rules[3] = (LAGraph_rule_WCNF){1, 4, -1, 0}; + rules[4] = (LAGraph_rule_WCNF){2, 5, -1, 0}; + + grammar = (grammar_t){ + .nonterms_count = 4, .terms_count = 2, .rules_count = 5, .rules = rules}; +} + +// S -> aS | a | eps in WCNF +// +// Terms: [1 a] +// Nonterms: [0 S] +// S -> SS [0 0 0 0] +// S -> a [0 1 -1 0] +// S -> eps [0 -1 -1 0] +void init_grammar_aS() { + LAGraph_rule_WCNF *rules = NULL; + LAGraph_Calloc((void **)&rules, 3, sizeof(LAGraph_rule_WCNF), msg); + + rules[0] = (LAGraph_rule_WCNF){0, 0, 0, 0}; + rules[1] = (LAGraph_rule_WCNF){0, 1, -1, 0}; + rules[2] = (LAGraph_rule_WCNF){0, -1, -1, 0}; + + grammar = (grammar_t){ + .nonterms_count = 1, .terms_count = 1, .rules_count = 3, .rules = rules}; +} + +// Complex grammar +// aaaabbbb or aaabbb +// +// Terms: [25 a] [26 b] +// Nonterms: [0 S] [n Sn] +// S -> S1 S2 [0 1 2 0] +// S -> S15 S16 [0 15 16 0] +// S1 -> S3 S4 [1 3 4 0] +// S2 -> S5 S6 [2 5 6 0] +// S3 -> S7 S8 [3 7 8 0] +// S4 -> S9 S10 [4 9 10 0] +// S5 -> S11 S12 [5 11 12 0] +// S6 -> S13 S14 [6 13 14 0] +// S16 -> S17 S18 [16 17 18 0] +// S17 -> S19 S20 [17 19 20 0] +// S18 -> S21 S22 [18 21 22 0] +// S22 -> S23 S24 [22 23 24 0] +// S7 -> a [7 25 -1 0] +// S8 -> a [8 25 -1 0] +// S9 -> a [9 25 -1 0] +// S10 -> a [10 25 -1 0] +// S11 -> b [11 26 -1 0] +// S12 -> b [12 26 -1 0] +// S13 -> b [13 26 -1 0] +// S14 -> b [14 26 -1 0] +// S15 -> a [15 25 -1 0] +// S19 -> a [19 25 -1 0] +// S20 -> a [20 25 -1 0] +// S21 -> b [21 26 -1 0] +// S23 -> b [23 26 -1 0] +// S24 -> b [24 26 -1 0] +void init_grammar_complex() { + LAGraph_rule_WCNF *rules = NULL; + LAGraph_Calloc((void **)&rules, 26, sizeof(LAGraph_rule_WCNF), msg); + + rules[0] = (LAGraph_rule_WCNF){0, 1, 2, 0}; + rules[1] = (LAGraph_rule_WCNF){0, 15, 16, 0}; + rules[2] = (LAGraph_rule_WCNF){1, 3, 4, 0}; + rules[3] = (LAGraph_rule_WCNF){2, 5, 6, 0}; + rules[4] = (LAGraph_rule_WCNF){3, 7, 8, 0}; + rules[5] = (LAGraph_rule_WCNF){4, 9, 10, 0}; + rules[6] = (LAGraph_rule_WCNF){5, 11, 12, 0}; + rules[7] = (LAGraph_rule_WCNF){6, 13, 14, 0}; + rules[8] = (LAGraph_rule_WCNF){16, 17, 18, 0}; + rules[9] = (LAGraph_rule_WCNF){17, 19, 20, 0}; + rules[10] = (LAGraph_rule_WCNF){18, 21, 22, 0}; + rules[11] = (LAGraph_rule_WCNF){22, 23, 24, 0}; + rules[12] = (LAGraph_rule_WCNF){7, 25, -1, 0}; + rules[13] = (LAGraph_rule_WCNF){8, 25, -1, 0}; + rules[14] = (LAGraph_rule_WCNF){9, 25, -1, 0}; + rules[15] = (LAGraph_rule_WCNF){10, 25, -1, 0}; + rules[16] = (LAGraph_rule_WCNF){11, 26, -1, 0}; + rules[17] = (LAGraph_rule_WCNF){12, 26, -1, 0}; + rules[18] = (LAGraph_rule_WCNF){13, 26, -1, 0}; + rules[19] = (LAGraph_rule_WCNF){14, 26, -1, 0}; + rules[20] = (LAGraph_rule_WCNF){15, 25, -1, 0}; + rules[21] = (LAGraph_rule_WCNF){19, 25, -1, 0}; + rules[22] = (LAGraph_rule_WCNF){20, 25, -1, 0}; + rules[23] = (LAGraph_rule_WCNF){21, 26, -1, 0}; + rules[24] = (LAGraph_rule_WCNF){23, 26, -1, 0}; + rules[25] = (LAGraph_rule_WCNF){24, 26, -1, 0}; + + grammar = (grammar_t){ + .nonterms_count = 25, .terms_count = 2, .rules_count = 26, .rules = rules}; +} + +//==================== +// Graphs +//==================== + +// Graph: +// +// 0 -a-> 1 +// 1 -a-> 2 +// 2 -a-> 0 +// 0 -b-> 3 +// 3 -b-> 0 +void init_graph_double_cycle() { + n_adj_matrices = grammar.nonterms_count + grammar.terms_count; + LAGraph_Calloc((void **)&adj_matrices, n_adj_matrices, sizeof(GrB_Matrix), msg); + size_t N = 4; + + GrB_Matrix adj_matrix_a, adj_matrix_b; + OK(GrB_Matrix_new(&adj_matrix_a, GrB_BOOL, N, N)); + OK(GrB_Matrix_new(&adj_matrix_b, GrB_BOOL, N, N)); + + OK(GrB_Matrix_setElement(adj_matrix_a, true, 0, 1)); + OK(GrB_Matrix_setElement(adj_matrix_a, true, 1, 2)); + OK(GrB_Matrix_setElement(adj_matrix_a, true, 2, 0)); + + OK(GrB_Matrix_setElement(adj_matrix_b, true, 0, 3)); + OK(GrB_Matrix_setElement(adj_matrix_b, true, 3, 0)); + + adj_matrices[grammar.nonterms_count + 0] = adj_matrix_a; + adj_matrices[grammar.nonterms_count + 1] = adj_matrix_b; + + for (size_t i = 0; i < grammar.nonterms_count; i++) { + GrB_Matrix_new(&adj_matrices[i], GrB_BOOL, N, N); + } +} + +// Graph: +// +// 0 -a-> 1 +// 1 -a-> 2 +// 2 -a-> 3 +// 3 -a-> 4 +// 3 -b-> 5 +// 4 -b-> 3 +// 5 -b-> 6 +// 6 -b-> 7 +void init_graph_1() { + n_adj_matrices = grammar.nonterms_count + grammar.terms_count; + LAGraph_Calloc((void **)&adj_matrices, n_adj_matrices, sizeof(GrB_Matrix), msg); + size_t N = 8; + + GrB_Matrix adj_matrix_a, adj_matrix_b; + OK(GrB_Matrix_new(&adj_matrix_a, GrB_BOOL, N, N)); + OK(GrB_Matrix_new(&adj_matrix_b, GrB_BOOL, N, N)); + + OK(GrB_Matrix_setElement(adj_matrix_a, true, 0, 1)); + OK(GrB_Matrix_setElement(adj_matrix_a, true, 1, 2)); + OK(GrB_Matrix_setElement(adj_matrix_a, true, 2, 3)); + OK(GrB_Matrix_setElement(adj_matrix_a, true, 3, 4)); + + OK(GrB_Matrix_setElement(adj_matrix_b, true, 3, 5)); + OK(GrB_Matrix_setElement(adj_matrix_b, true, 4, 3)); + OK(GrB_Matrix_setElement(adj_matrix_b, true, 5, 6)); + OK(GrB_Matrix_setElement(adj_matrix_b, true, 6, 7)); + + adj_matrices[grammar.nonterms_count + 0] = adj_matrix_a; + adj_matrices[grammar.nonterms_count + 1] = adj_matrix_b; + + for (size_t i = 0; i < grammar.nonterms_count; i++) { + GrB_Matrix_new(&adj_matrices[i], GrB_BOOL, N, N); + } +} + +// Graph: +// +// 0 -a-> 2 +// 1 -a-> 2 +// 3 -a-> 5 +// 4 -a-> 5 +// 2 -a-> 6 +// 5 -a-> 6 +// 2 -b-> 0 +// 2 -b-> 1 +// 5 -b-> 3 +// 5 -b-> 4 +// 6 -b-> 2 +// 6 -b-> 5 +void init_graph_tree() { + n_adj_matrices = grammar.nonterms_count + grammar.terms_count; + LAGraph_Calloc((void **)&adj_matrices, n_adj_matrices, sizeof(GrB_Matrix), msg); + size_t N = 7; + + GrB_Matrix adj_matrix_a, adj_matrix_b; + OK(GrB_Matrix_new(&adj_matrix_a, GrB_BOOL, N, N)); + OK(GrB_Matrix_new(&adj_matrix_b, GrB_BOOL, N, N)); + + OK(GrB_Matrix_setElement(adj_matrix_a, true, 0, 2)); + OK(GrB_Matrix_setElement(adj_matrix_a, true, 1, 2)); + OK(GrB_Matrix_setElement(adj_matrix_a, true, 3, 5)); + OK(GrB_Matrix_setElement(adj_matrix_a, true, 4, 5)); + OK(GrB_Matrix_setElement(adj_matrix_a, true, 2, 6)); + OK(GrB_Matrix_setElement(adj_matrix_a, true, 5, 6)); + + OK(GrB_Matrix_setElement(adj_matrix_b, true, 2, 0)); + OK(GrB_Matrix_setElement(adj_matrix_b, true, 2, 1)); + OK(GrB_Matrix_setElement(adj_matrix_b, true, 5, 3)); + OK(GrB_Matrix_setElement(adj_matrix_b, true, 5, 4)); + OK(GrB_Matrix_setElement(adj_matrix_b, true, 6, 2)); + OK(GrB_Matrix_setElement(adj_matrix_b, true, 6, 5)); + + adj_matrices[grammar.nonterms_count + 0] = adj_matrix_a; + adj_matrices[grammar.nonterms_count + 1] = adj_matrix_b; + + for (size_t i = 0; i < grammar.nonterms_count; i++) { + GrB_Matrix_new(&adj_matrices[i], GrB_BOOL, N, N); + } +} + +// Graph: +// +// 0 -a-> 1 +// 1 -a-> 2 +// 2 -a-> 0 +void init_graph_one_cycle() { + n_adj_matrices = grammar.nonterms_count + grammar.terms_count; + LAGraph_Calloc((void **)&adj_matrices, n_adj_matrices, sizeof(GrB_Matrix), msg); + size_t N = 3; + + GrB_Matrix adj_matrix_a; + GrB_Matrix_new(&adj_matrix_a, GrB_BOOL, N, N); + + OK(GrB_Matrix_setElement(adj_matrix_a, true, 0, 1)); + OK(GrB_Matrix_setElement(adj_matrix_a, true, 1, 2)); + OK(GrB_Matrix_setElement(adj_matrix_a, true, 2, 0)); + + adj_matrices[grammar.nonterms_count + 0] = adj_matrix_a; + + for (size_t i = 0; i < grammar.nonterms_count; i++) { + GrB_Matrix_new(&adj_matrices[i], GrB_BOOL, N, N); + } +} + +// Graph: + +// 0 -a-> 1 +// 1 -a-> 2 +// 2 -b-> 3 +// 3 -b-> 4 +void init_graph_line() { + n_adj_matrices = grammar.nonterms_count + grammar.terms_count; + LAGraph_Calloc((void **)&adj_matrices, n_adj_matrices, sizeof(GrB_Matrix), msg); + size_t N = 5; + + GrB_Matrix adj_matrix_a, adj_matrix_b; + GrB_Matrix_new(&adj_matrix_a, GrB_BOOL, N, N); + GrB_Matrix_new(&adj_matrix_b, GrB_BOOL, N, N); + + OK(GrB_Matrix_setElement(adj_matrix_a, true, 0, 1)); + OK(GrB_Matrix_setElement(adj_matrix_a, true, 1, 2)); + + OK(GrB_Matrix_setElement(adj_matrix_b, true, 2, 3)); + OK(GrB_Matrix_setElement(adj_matrix_b, true, 3, 4)); + + adj_matrices[grammar.nonterms_count + 0] = adj_matrix_a; + adj_matrices[grammar.nonterms_count + 1] = adj_matrix_b; + + for (size_t i = 0; i < grammar.nonterms_count; i++) { + GrB_Matrix_new(&adj_matrices[i], GrB_BOOL, N, N); + } +} + +// Graph: + +// 0 -a-> 0 +// 0 -b-> 1 +// 1 -c-> 2 +void init_graph_2() { + n_adj_matrices = grammar.nonterms_count + grammar.terms_count; + LAGraph_Calloc((void **)&adj_matrices, n_adj_matrices, sizeof(GrB_Matrix), msg); + size_t N = 3; + + GrB_Matrix adj_matrix_a, adj_matrix_b, adj_matrix_c; + GrB_Matrix_new(&adj_matrix_a, GrB_BOOL, N, N); + GrB_Matrix_new(&adj_matrix_b, GrB_BOOL, N, N); + GrB_Matrix_new(&adj_matrix_c, GrB_BOOL, N, N); + + OK(GrB_Matrix_setElement(adj_matrix_a, true, 0, 0)); + OK(GrB_Matrix_setElement(adj_matrix_b, true, 0, 1)); + OK(GrB_Matrix_setElement(adj_matrix_c, true, 1, 2)); + + adj_matrices[grammar.nonterms_count + 0] = adj_matrix_a; + adj_matrices[grammar.nonterms_count + 1] = adj_matrix_b; + adj_matrices[grammar.nonterms_count + 2] = adj_matrix_c; + + for (size_t i = 0; i < grammar.nonterms_count; i++) { + GrB_Matrix_new(&adj_matrices[i], GrB_BOOL, N, N); + } +} + +// Graph: + +// 0 -a-> 1 +// 1 -a-> 0 +// 0 -b-> 0 +void init_graph_3() { + n_adj_matrices = grammar.nonterms_count + grammar.terms_count; + LAGraph_Calloc((void **)&adj_matrices, n_adj_matrices, sizeof(GrB_Matrix), msg); + size_t N = 2; + + GrB_Matrix adj_matrix_a, adj_matrix_b; + GrB_Matrix_new(&adj_matrix_a, GrB_BOOL, N, N); + GrB_Matrix_new(&adj_matrix_b, GrB_BOOL, N, N); + + OK(GrB_Matrix_setElement(adj_matrix_a, true, 0, 1)); + OK(GrB_Matrix_setElement(adj_matrix_a, true, 1, 0)); + OK(GrB_Matrix_setElement(adj_matrix_b, true, 0, 0)); + + adj_matrices[grammar.nonterms_count + 0] = adj_matrix_a; + adj_matrices[grammar.nonterms_count + 1] = adj_matrix_b; + + for (size_t i = 0; i < grammar.nonterms_count; i++) { + GrB_Matrix_new(&adj_matrices[i], GrB_BOOL, N, N); + } +} + +// Graph: + +// 0 -b-> 1 +// 1 -b-> 0 +void init_graph_4() { + n_adj_matrices = grammar.nonterms_count + grammar.terms_count; + LAGraph_Calloc((void **)&adj_matrices, n_adj_matrices, sizeof(GrB_Matrix), msg); + size_t N = 2; + + GrB_Matrix adj_matrix_a, adj_matrix_b; + GrB_Matrix_new(&adj_matrix_a, GrB_BOOL, N, N); + GrB_Matrix_new(&adj_matrix_b, GrB_BOOL, N, N); + + OK(GrB_Matrix_setElement(adj_matrix_b, true, 0, 1)); + OK(GrB_Matrix_setElement(adj_matrix_b, true, 1, 0)); + + adj_matrices[grammar.nonterms_count + 0] = adj_matrix_a; + adj_matrices[grammar.nonterms_count + 1] = adj_matrix_b; + + for (size_t i = 0; i < grammar.nonterms_count; i++) { + GrB_Matrix_new(&adj_matrices[i], GrB_BOOL, N, N); + } +} + +//==================== +// Tests with valid result +//==================== + +void test_CFL_reachability_cycle(void) { +#if LAGRAPH_SUITESPARSE + setup(); + + for (size_t mask = 0; mask < 16; mask++) { + GrB_Info retval; + + init_grammar_aS(); + init_graph_one_cycle(); + init_outputs(); + + OK(run_algorithm(mask)); + TEST_MSG("MASK: %x, ERROR: %s\n", mask, msg); + check_result("(0, 0) (0, 1) (0, 2) (1, 0) (1, 1) (1, 2) (2, 0) (2, 1) (2, 2)"); + + free_workspace(); + } + + teardown(); +#endif +} + +void test_CFL_reachability_two_cycle(void) { +#if LAGRAPH_SUITESPARSE + setup(); + + for (size_t mask = 0; mask < 16; mask++) { + GrB_Info retval; + + init_grammar_aSb(); + init_graph_double_cycle(); + init_outputs(); + + OK(run_algorithm(mask)); + check_result("(0, 0) (0, 3) (1, 0) (1, 3) (2, 0) (2, 3)"); + + free_workspace(); + } + + teardown(); +#endif +} + +void test_CFL_reachability_labels_more_than_nonterms(void) { +#if LAGRAPH_SUITESPARSE + setup(); + + for (size_t mask = 0; mask < 16; mask++) { + GrB_Info retval; + + init_grammar_aSb(); + init_graph_2(); + init_outputs(); + + OK(run_algorithm(mask)); + check_result("(0, 1)"); + + free_workspace(); + } + + teardown(); +#endif +} + +void test_CFL_reachability_complex_grammar(void) { +#if LAGRAPH_SUITESPARSE + setup(); + + for (size_t mask = 0; mask < 16; mask++) { + GrB_Info retval; + + init_grammar_complex(); + init_graph_1(); + init_outputs(); + + OK(run_algorithm(mask)); + check_result("(0, 7) (1, 6)"); + + free_workspace(); + } + + teardown(); +#endif +} + +void test_CFL_reachability_tree(void) { +#if LAGRAPH_SUITESPARSE + setup(); + + for (size_t mask = 0; mask < 16; mask++) { + GrB_Info retval; + + init_grammar_aSb(); + init_graph_tree(); + init_outputs(); + + OK(run_algorithm(mask)); + check_result( + "(0, 0) (0, 1) (0, 3) (0, 4) (1, 0) (1, 1) (1, 3) (1, 4) (2, 2) (2, 5) " + "(3, 0) (3, 1) (3, 3) (3, 4) (4, 0) (4, 1) (4, 3) (4, 4) (5, 2) (5, 5)"); + + free_workspace(); + } + + teardown(); +#endif +} + +void test_CFL_reachability_line(void) { +#if LAGRAPH_SUITESPARSE + setup(); + + for (size_t mask = 0; mask < 16; mask++) { + GrB_Info retval; + + init_grammar_aSb(); + init_graph_line(); + init_outputs(); + + OK(run_algorithm(mask)); + check_result("(0, 4) (1, 3)"); + + free_workspace(); + } + teardown(); +#endif +} + +void test_CFL_reachability_two_nodes_cycle(void) { +#if LAGRAPH_SUITESPARSE + setup(); + + for (size_t mask = 0; mask < 16; mask++) { + GrB_Info retval; + + init_grammar_aSb(); + init_graph_3(); + init_outputs(); + + OK(run_algorithm(mask)); + check_result("(0, 0) (1, 0)"); + + free_workspace(); + } + + teardown(); +#endif +} + +void test_CFL_reachability_with_empty_adj_matrix(void) { +#if LAGRAPH_SUITESPARSE + setup(); + + for (size_t mask = 0; mask < 16; mask++) { + GrB_Info retval; + + init_grammar_aS(); + init_graph_4(); + init_outputs(); + + OK(run_algorithm(mask)); + check_result("(0, 0) (1, 1)"); + + free_workspace(); + } + teardown(); +#endif +} + +//==================== +// Tests with invalid result +//==================== + +void test_CFL_reachability_invalid_rules(void) { +#if LAGRAPH_SUITESPARSE + setup(); + + for (size_t mask = 0; mask < 16; mask++) { + /* code */ + } + + GrB_Info retval; + + init_grammar_aSb(); + init_graph_double_cycle(); + init_outputs(); + + // Rule [Variable -> _ B] + grammar.rules[0] = + (LAGraph_rule_WCNF){.nonterm = 0, .prod_A = -1, .prod_B = 1, .index = 0}; + check_error(GrB_INVALID_VALUE, 0); + + // Rule [_ -> A B] + grammar.rules[0] = + (LAGraph_rule_WCNF){.nonterm = -1, .prod_A = 1, .prod_B = 2, .index = 0}; + check_error(GrB_INVALID_VALUE, 0); + + // Rule [C -> A B], where C >= nonterms_count + grammar.rules[0] = + (LAGraph_rule_WCNF){.nonterm = 10, .prod_A = 1, .prod_B = 2, .index = 0}; + check_error(GrB_INVALID_VALUE, 0); + + // Rule [S -> A B], where A >= nonterms_count + grammar.rules[0] = + (LAGraph_rule_WCNF){.nonterm = 0, .prod_A = 10, .prod_B = 2, .index = 0}; + check_error(GrB_INVALID_VALUE, 0); + + // Rule [C -> t], where t >= terms_count + grammar.rules[0] = + (LAGraph_rule_WCNF){.nonterm = 0, .prod_A = 10, .prod_B = -1, .index = 0}; + check_error(GrB_INVALID_VALUE, 0); + + free_workspace(); + teardown(); +#endif +} + +void test_CFL_reachability_null_pointers(void) { +#if LAGRAPH_SUITESPARSE + + setup(); + + for (size_t mask = 0; mask < 16; mask++) { + /* code */ + } + + GrB_Info retval; + + init_grammar_aSb(); + init_graph_double_cycle(); + init_outputs(); + + // adj_matrices[0] = NULL; + // adj_matrices[1] = NULL; + GrB_free(&adj_matrices[0]); + GrB_free(&adj_matrices[1]); + + check_error(GrB_NULL_POINTER, 0); + + // adj_matrices = NULL; + LAGraph_Free((void **)&adj_matrices, msg); + check_error(GrB_NULL_POINTER, 0); + + free_workspace(); + init_grammar_aSb(); + init_graph_double_cycle(); + init_outputs(); + + // outputs = NULL; + LAGraph_Free((void **)&outputs, msg); + check_error(GrB_NULL_POINTER, 0); + + free_workspace(); + init_grammar_aSb(); + init_graph_double_cycle(); + init_outputs(); + + // grammar.rules = NULL; + LAGraph_Free((void **)&grammar.rules, msg); + check_error(GrB_NULL_POINTER, 0); + + free_workspace(); + teardown(); +#endif +} + +TEST_LIST = {{"CFL_reachability_cycle", test_CFL_reachability_cycle}, + {"CFL_reachability_complex_grammar", test_CFL_reachability_complex_grammar}, + {"CFL_reachability_two_cycle", test_CFL_reachability_two_cycle}, + {"CFL_reachability_labels_more_than_nonterms", + test_CFL_reachability_labels_more_than_nonterms}, + {"CFL_reachability_tree", test_CFL_reachability_tree}, + {"CFL_reachability_line", test_CFL_reachability_line}, + {"CFL_reachability_two_nodes_cycle", test_CFL_reachability_two_nodes_cycle}, + {"CFG_reach_basic_invalid_rules", test_CFL_reachability_invalid_rules}, + {"test_CFL_reachability_with_empty_adj_matrix", + test_CFL_reachability_with_empty_adj_matrix}, +#if !defined(GRAPHBLAS_HAS_CUDA) + {"CFG_reachability_null_pointers", test_CFL_reachability_null_pointers}, +#endif + {NULL, NULL}};