forked from GraphBLAS/LAGraph
-
Notifications
You must be signed in to change notification settings - Fork 2
Implement CFL single-path path-finding and extraction algorithm #8
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
b08lsoai
wants to merge
33
commits into
SparseLinearAlgebra:stable
Choose a base branch
from
b08lsoai:b08lsoai/single_path
base: stable
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
+3,172
−302
Open
Changes from 16 commits
Commits
Show all changes
33 commits
Select commit
Hold shift + click to select a range
9c6a947
feat: initial commit
b08lsoai 91070a5
test: add tests for the path extraction algorithm
b08lsoai 3b65b2b
test: add tests for the single path search algorithm
b08lsoai 23a6ca5
ref: make set_path_index callback type-safe
b08lsoai bac1db5
fix: fix output matrix corruption
b08lsoai b24bde1
ref: reduce code nesting
b08lsoai 8cecb2c
fix: add path freeing on errors
b08lsoai 2e10ed5
ref: reduce code nesting
b08lsoai 7cc849a
test: add extract_single_path tests
b08lsoai ed1d853
ref: require pre-initialization of matrices
b08lsoai 2fbdcb6
test: update tests
b08lsoai 48964e2
fix: correct the msg recording
b08lsoai 0db907c
docs: add comments to LAGraphX.h
b08lsoai 6c134b7
ref: introduce CFPQ_core algorithm
b08lsoai 85b9cf8
feat: change API LAGraph_CFL_extract_single_path
b08lsoai 44df6a4
style: format code
b08lsoai d63d9b4
ref: improve naming across CFL modules
b08lsoai 4262b85
docs: fix comments in path extraction
b08lsoai 7a91d36
docs: add header for LAGraph_CFL_extract_single_path
b08lsoai e663a0f
ref: add input validation macros for CFL algorithms
b08lsoai be094e8
test: update tests for new API
b08lsoai d4e2cec
fix: free allocated memory when no paths found
b08lsoai 7db3c27
docs: fix the header
b08lsoai 4d71c96
docs: add header for LAGraph_CFL_single_pats
b08lsoai 3092b0c
ref: extract rule classification into helper
b08lsoai 91e01af
ref: replace malloc with callock
b08lsoai 67dc5d6
ref: convert LG_CFL_CHECK_BASE_INPUTS macro to fun
b08lsoai 9bfefc9
ref: relocate ADD_TO_MSG macro to LAGraphX.h
b08lsoai 40e6cd0
ref: make ADD_TO_MSG macro parameters explicit
b08lsoai 3a536cd
docs: improve docs for base input check functions
b08lsoai 082d20b
feat: return type from LAGraph_CFL_single_path
b08lsoai 9b3cfb2
docs: improve error message
b08lsoai 3296ecd
build: add conditional compilation
b08lsoai File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
227 changes: 227 additions & 0 deletions
227
experimental/algorithm/LAGraph_CFL_extract_single_path.c
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,227 @@ | ||
| #define LG_FREE_ALL \ | ||
| { \ | ||
| LAGraph_Free((void **)&output->paths, NULL); \ | ||
| output->count = 0; \ | ||
| output->capacity = 0; \ | ||
| } | ||
|
|
||
| #include "LG_internal.h" | ||
| #include <LAGraphX.h> | ||
|
|
||
| #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 ? "%" PRId64 : ", %" PRId64, i); \ | ||
| rule.count++; \ | ||
| } | ||
|
|
||
| GrB_Info LAGraph_CFL_extract_single_path( | ||
| // Output | ||
| PathArray *output, | ||
| // Input | ||
| GrB_Index *start, | ||
| GrB_Index *end, | ||
| int32_t nonterm, | ||
| const GrB_Matrix *adj_matrices, | ||
| const GrB_Matrix *T, | ||
gsvgit marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| int64_t terms_count, // The total number of terminal symbols in the CFG. | ||
| int64_t nonterms_count, // The total number of non-terminal symbols in the CFG. | ||
| const LAGraph_rule_WCNF *rules, // The rules of the CFG. | ||
| int64_t rules_count, // The total number of rules in the CFG. | ||
| char *msg // Message string for error reporting. | ||
| ) | ||
| { | ||
| LG_CLEAR_MSG; | ||
| size_t msg_len = 0; // For error formatting | ||
| GrB_Info info; | ||
| output->count = 0; | ||
| output->paths = NULL; | ||
| // Initial capacity 1, since most often looking for exactly 1 path with a fixed start and end | ||
| output->capacity = 1; | ||
|
|
||
| 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(nonterm < nonterms_count, GrB_INVALID_VALUE, | ||
| "The start non-terminal must be no greater than the number of non-terminals."); | ||
| LG_ASSERT_MSG(T != NULL, GrB_NULL_POINTER, "The T array cannot be null."); | ||
gsvgit marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| 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 (int64_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(" %" PRId64, i); | ||
| found_null = true; | ||
| } | ||
|
|
||
| if (found_null) | ||
| { | ||
| LG_FREE_ALL; | ||
| return GrB_NULL_POINTER; | ||
| } | ||
|
|
||
| // Find null T matrices | ||
gsvgit marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| found_null = false; | ||
| for (int64_t i = 0; i < nonterms_count; i++) | ||
| { | ||
| if (T[i] != NULL) | ||
| continue; | ||
|
|
||
| if (!found_null) | ||
| { | ||
| ADD_TO_MSG("T matrices with these indexes are null:"); | ||
| } | ||
| ADD_TO_MSG(" %" PRId64, i); | ||
|
|
||
| found_null = true; | ||
| } | ||
| if (found_null) | ||
| { | ||
| LG_FREE_ALL; | ||
| return GrB_NULL_POINTER; | ||
| } | ||
|
|
||
| // Check the 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 (int64_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 -> term] | ||
| if (is_rule_term) | ||
| { | ||
| 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) | ||
| { | ||
| 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: %" PRId64 ".\n", | ||
| (int64_t)(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; | ||
| } | ||
|
|
||
| GrB_Index n; | ||
| GRB_TRY(GrB_Matrix_nrows(&n, adj_matrices[0])); | ||
|
|
||
| GrB_Index start_begin = (start == NULL) ? 0 : *start; | ||
| GrB_Index start_end = (start == NULL) ? n - 1 : *start; | ||
| GrB_Index end_begin = (end == NULL) ? 0 : *end; | ||
| GrB_Index end_end = (end == NULL) ? n - 1 : *end; | ||
|
|
||
| LG_TRY(LAGraph_Malloc((void **)&output->paths, output->capacity, sizeof(Path), msg)); | ||
|
|
||
| for (GrB_Index st = start_begin; st <= start_end; st++) | ||
| { | ||
| for (GrB_Index en = end_begin; en <= end_end; en++) | ||
| { | ||
| Path path; | ||
|
|
||
| // Function that extracts one path with fixed start and end | ||
| info = LAGraph_CFL_extract_single_path_internal(&path, st, en, nonterm, adj_matrices, T, terms_count, nonterms_count, rules, rules_count, msg); | ||
| if (info == GrB_SUCCESS) | ||
| { | ||
| if (output->count == output->capacity) | ||
| { | ||
| LG_TRY(LAGraph_Realloc((void **)&output->paths, output->capacity * 2, output->capacity, | ||
| sizeof(Path), msg)); | ||
| output->capacity *= 2; | ||
| } | ||
| output->paths[output->count++] = path; | ||
| } | ||
| else if (info != GrB_NO_VALUE) // GrB_NO_VALUE is the absence of a path, not an error | ||
| { | ||
| LG_FREE_ALL; | ||
| return info; | ||
| } | ||
| } | ||
| } | ||
|
|
||
| LG_FREE_WORK; | ||
| return GrB_SUCCESS; | ||
| } | ||
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.