From c9263e7091d844b07e1ed06fef6cf207bdce323d Mon Sep 17 00:00:00 2001 From: dperry17 Date: Tue, 10 Feb 2026 17:04:08 -0600 Subject: [PATCH 1/7] added comments and documentation to the min cut algo --- experimental/algorithm/LAGraph_MinCut.c | 30 ++++++++++++++++--------- experimental/test/test_MinCut.c | 2 +- include/LAGraphX.h | 5 ++--- 3 files changed, 22 insertions(+), 15 deletions(-) diff --git a/experimental/algorithm/LAGraph_MinCut.c b/experimental/algorithm/LAGraph_MinCut.c index 7c3572f1c1..100ba52d43 100644 --- a/experimental/algorithm/LAGraph_MinCut.c +++ b/experimental/algorithm/LAGraph_MinCut.c @@ -26,10 +26,22 @@ // [2] D. Peries and T. Davis, "A parallel push-relabel maximum flow algorithm // in LAGraph and GraphBLAS", IEEE HPEC'25, Sept 2025. -// FIXME: add more discussion here. Something about the algorithm, and -// document inputs and outputs. +// [10] A. V. Goldberg and R. E. Tarjan, “A new approach to the maximum +// flow problem,” in Proc. 18th Annual ACM Symp. Theory of Computing, +// STOC ’86, p. 136–146, ACM, 1986. + +// The algorithm takes the residual graph produced by the max flow and runs a +// single breadth-first search from the original source node used in the +// Max Flow. The algorithm returns the set of nodes, S, which are reachable +// from the source, and the set of nodes, S_bar, that are not. Additionally +// The algorithm returns the set of weigthed edges that are included in cut. + + +// Example: First use the max flow algorithm on a weighted graph with no +// negative edge weights. The optional parameter to generate the R matrix must +// be set. Then take the original graph, the R matrix, and the original +// source node and input them into the parameters of the algorithm. -// Give example of use //------------------------------------------------------------------------------ @@ -61,13 +73,9 @@ int LAGraph_MinCut GrB_Vector* S_bar, GrB_Matrix* cut_set, // inputs - LAGraph_Graph G_origin, // swap G_origin and R GrB_Matrix R, - - // inputs (also to MaxFlow): - // G_origin - GrB_Index s, // src: FIXME - GrB_Index t, // sink: FIXME delete me! + LAGraph_Graph G_origin, // swap G_origin and R + GrB_Index src, // src: FIXME char *msg ) { @@ -83,7 +91,7 @@ int LAGraph_MinCut LG_ASSERT (S != NULL, GrB_NULL_POINTER) ; LG_ASSERT (S_bar != NULL, GrB_NULL_POINTER) ; LG_ASSERT (cut_set != NULL, GrB_NULL_POINTER) ; - LG_ASSERT (s < n && t < n, GrB_INVALID_VALUE) ; + LG_ASSERT (src < n, GrB_INVALID_VALUE) ; GrB_Matrix A = G_origin->A; @@ -94,7 +102,7 @@ int LAGraph_MinCut LG_TRY(LAGraph_New(&G, &R, LAGraph_ADJACENCY_DIRECTED, msg)); //S_bfs is allocated during the bfs - LG_TRY(LAGr_BreadthFirstSearch(&S_bfs, NULL, G, s, msg)); + LG_TRY(LAGr_BreadthFirstSearch(&S_bfs, NULL, G, src, msg)); LG_TRY(GrB_assign(*S_bar, S_bfs, NULL, 1, GrB_ALL, n, GrB_DESC_SC)); LG_TRY(GrB_assign(*S, S_bfs, NULL, 1, GrB_ALL, n, GrB_DESC_S)); diff --git a/experimental/test/test_MinCut.c b/experimental/test/test_MinCut.c index 1ea1fad389..80b1b20a2b 100644 --- a/experimental/test/test_MinCut.c +++ b/experimental/test/test_MinCut.c @@ -67,7 +67,7 @@ void test_MinCut() { printf("%s\n", msg); printf("flow is: %lf\n", flow); - OK(LAGraph_MinCut(&S, &S_bar, &cut_set, G, R, tests[test].s, tests[test].t, msg)); + OK(LAGraph_MinCut(&S, &S_bar, &cut_set, R, G, tests[test].s, msg)); printf("%s\n", msg); OK(GrB_reduce(&min_cut, NULL, GrB_PLUS_MONOID_FP64, cut_set, NULL)); diff --git a/include/LAGraphX.h b/include/LAGraphX.h index 6182f54805..0f3cd6e234 100644 --- a/include/LAGraphX.h +++ b/include/LAGraphX.h @@ -1523,10 +1523,9 @@ int LAGraph_MinCut( GrB_Vector* S_bar, GrB_Matrix* cut_set, // inputs - LAGraph_Graph G_origin, //original graph with capacities GrB_Matrix R, //residual graph - GrB_Index s, //source node index - GrB_Index t, //sink node index + LAGraph_Graph G_origin, //original graph with capacities + GrB_Index src, //source node index from max flow char *msg ); From 270e3d44374d1912e775da68c126151635bf3734 Mon Sep 17 00:00:00 2001 From: dperry17 Date: Tue, 10 Feb 2026 17:12:06 -0600 Subject: [PATCH 2/7] removed some an extra free and added more comments --- experimental/algorithm/LAGraph_MinCut.c | 9 +++++++-- experimental/test/test_MinCut.c | 19 ++++++++++++++++++- 2 files changed, 25 insertions(+), 3 deletions(-) diff --git a/experimental/algorithm/LAGraph_MinCut.c b/experimental/algorithm/LAGraph_MinCut.c index 100ba52d43..d4e9829fbe 100644 --- a/experimental/algorithm/LAGraph_MinCut.c +++ b/experimental/algorithm/LAGraph_MinCut.c @@ -87,6 +87,7 @@ int LAGraph_MinCut GrB_Index n = 0; GrB_Matrix_nrows(&n, R); + // Input checks LG_TRY(LAGraph_CheckGraph(G_origin, msg)); LG_ASSERT (S != NULL, GrB_NULL_POINTER) ; LG_ASSERT (S_bar != NULL, GrB_NULL_POINTER) ; @@ -94,22 +95,26 @@ int LAGraph_MinCut LG_ASSERT (src < n, GrB_INVALID_VALUE) ; GrB_Matrix A = G_origin->A; - + + // construct the outputs LG_TRY(GrB_Matrix_new(cut_set, GrB_FP64, n, n)); LG_TRY(GrB_Vector_new(S_bar, GrB_FP64, n)); LG_TRY(GrB_Vector_new(S, GrB_FP64, n)); + // create graph from R for the BFS LG_TRY(LAGraph_New(&G, &R, LAGraph_ADJACENCY_DIRECTED, msg)); - //S_bfs is allocated during the bfs + // S_bfs is allocated during the bfs LG_TRY(LAGr_BreadthFirstSearch(&S_bfs, NULL, G, src, msg)); LG_TRY(GrB_assign(*S_bar, S_bfs, NULL, 1, GrB_ALL, n, GrB_DESC_SC)); + // set compliment for unreachable nodes. LG_TRY(GrB_assign(*S, S_bfs, NULL, 1, GrB_ALL, n, GrB_DESC_S)); GRB_TRY(GrB_Matrix_diag(&S_diag, *S, 0)); GRB_TRY(GrB_Matrix_diag(&S_bar_diag, *S_bar, 0)); + // used to compute the set of cut edges. GRB_TRY(GrB_mxm(*cut_set, NULL, NULL, GrB_PLUS_TIMES_SEMIRING_FP64, A, S_bar_diag, NULL)); GRB_TRY(GrB_mxm(*cut_set, NULL, NULL, GrB_PLUS_TIMES_SEMIRING_FP64, S_diag, *cut_set, NULL)); diff --git a/experimental/test/test_MinCut.c b/experimental/test/test_MinCut.c index 80b1b20a2b..d3ba627b0d 100644 --- a/experimental/test/test_MinCut.c +++ b/experimental/test/test_MinCut.c @@ -1,3 +1,21 @@ +//------------------------------------------------------------------------------ +// experimental/test/test_MinCut: tests for LAGr_MaxFlow +//------------------------------------------------------------------------------ + +// LAGraph, (c) 2019-2022 by The LAGraph Contributors, All Rights Reserved. +// SPDX-License-Identifier: BSD-2-Clause +// +// For additional details (including references to third party source code and +// other files) see the LICENSE file or contact permission@sei.cmu.edu. See +// Contributors.txt for a full list of contributors. Created, in part, with +// funding and support from the U.S. Government (see Acknowledgments.txt file). +// DM22-0790 + +// Contributed by Darin Peries and Tim Davis, Texas A&M University + +//------------------------------------------------------------------------------ + + #include #include #include @@ -75,7 +93,6 @@ void test_MinCut() { TEST_CHECK(flow == min_cut); printf("The min cut: %lf\n", min_cut); - GrB_free(&A); GrB_free(&R); GrB_free(&S); GrB_free(&S_bar); From c5267138cb15d492735702040f0c8f21a9a55869 Mon Sep 17 00:00:00 2001 From: dperry17 Date: Tue, 10 Feb 2026 17:15:55 -0600 Subject: [PATCH 3/7] fixed typo --- experimental/test/test_MinCut.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/experimental/test/test_MinCut.c b/experimental/test/test_MinCut.c index d3ba627b0d..6a275b67c2 100644 --- a/experimental/test/test_MinCut.c +++ b/experimental/test/test_MinCut.c @@ -1,5 +1,5 @@ //------------------------------------------------------------------------------ -// experimental/test/test_MinCut: tests for LAGr_MaxFlow +// experimental/test/test_MinCut: tests for LAGraph_MinCut //------------------------------------------------------------------------------ // LAGraph, (c) 2019-2022 by The LAGraph Contributors, All Rights Reserved. From 43fa881f06ad2b83c83fb55906a1a19dbbea170c Mon Sep 17 00:00:00 2001 From: dperry17 Date: Wed, 11 Mar 2026 15:54:16 -0500 Subject: [PATCH 4/7] added prototype dimacs file reader --- src/utility/LAGraph_DMRead.c | 69 ++++++++++++++++++++++++++++++++++++ 1 file changed, 69 insertions(+) create mode 100644 src/utility/LAGraph_DMRead.c diff --git a/src/utility/LAGraph_DMRead.c b/src/utility/LAGraph_DMRead.c new file mode 100644 index 0000000000..4f22f44b40 --- /dev/null +++ b/src/utility/LAGraph_DMRead.c @@ -0,0 +1,69 @@ +#include "LG_internal.h" + +#define BUFF_SIZE 1024 + +#undef LG_FREE_ALL +#undef LG_FREE_WORK + +#define LG_FREE_WORK LG_FREE_ALL +#define LG_FREE_ALL \ +{ \ + free(rows) ; \ + free(cols) ; \ + free(weights); \ +} + +static int DMRead( + GrB_Matrix* A, + GrB_Index* s, + GrB_Index* t, + FILE* f, + char* msg + ) +{ + ASSERT(file != NULL) ; + + int32_t n_nodes = 0, n_edges = 0 ; + GrB_Index *rows = NULL, *cols = NULL, *weights = NULL ; //what data type whould the weights be?? Should this be in 32 or 64 bit? + + char buff[BUFF_SIZE]; + + int64_t line_count = 0 ; + + while (fgets(buff, BUFF_SIZE, f)) + { + if (buff[0] == 'c' || buff[0] == '\0' || buff[0] == '\n') continue; + + if (buff[0] == 'p') + { + ASSERT(scanf(buff, "p max %d %d", n_nodes, n_edges) != 2) ; + rows = (int32_t *) malloc(n_edges * sizeof(GrB_Index)) ; + cols = (int32_t *) malloc(n_edges * sizeof(GrB_Index)) ; + weights = (int32_t *) malloc(n_edges * sizeof(GrB_Index)) ; + } + + if (buff[0] == 'n') + { + if (buff[strlen(buff)-2] == 't') + ASSERT(scanf(buff, "n %d, t", *t) != 2) ; + + if (buff[strlen(buff)-2] == 's') + ASSERT(scanf(buff, "n %d, s", *s) != 2) ; + } + + if (buff[0] == 'a') + { + GrB_Index r = 0, c = 0, w = 0 ; + ASSERT(scanf(buff, "a %d %d %d", r, c, w) != 2) ; + rows[line_count] = r ; + cols[line_count] = c ; + weights[line_count] = w ; + line_count++ ; + } + } + + GRB_TRY(GrB_Matrix_build_INT64(*A, rows, cols, weights, n_edges, NULL)) ; + + LG_FREE_ALL ; + return (GrB_SUCCESS) ; +} From d8b17dc4e22420c2014a57282846b68367672d7d Mon Sep 17 00:00:00 2001 From: dperry17 Date: Wed, 11 Mar 2026 15:56:01 -0500 Subject: [PATCH 5/7] fixed small data type problem --- src/utility/LAGraph_DMRead.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/utility/LAGraph_DMRead.c b/src/utility/LAGraph_DMRead.c index 4f22f44b40..842ae27024 100644 --- a/src/utility/LAGraph_DMRead.c +++ b/src/utility/LAGraph_DMRead.c @@ -37,9 +37,9 @@ static int DMRead( if (buff[0] == 'p') { ASSERT(scanf(buff, "p max %d %d", n_nodes, n_edges) != 2) ; - rows = (int32_t *) malloc(n_edges * sizeof(GrB_Index)) ; - cols = (int32_t *) malloc(n_edges * sizeof(GrB_Index)) ; - weights = (int32_t *) malloc(n_edges * sizeof(GrB_Index)) ; + rows = (GrB_Index *) malloc(n_edges * sizeof(GrB_Index)) ; + cols = (GrB_Index *) malloc(n_edges * sizeof(GrB_Index)) ; + weights = (GrB_Index *) malloc(n_edges * sizeof(GrB_Index)) ; } if (buff[0] == 'n') From 588ffcffddb7c26594bcb9fc6908944217209a7c Mon Sep 17 00:00:00 2001 From: dperry17 Date: Wed, 11 Mar 2026 16:01:27 -0500 Subject: [PATCH 6/7] fixed node reading --- src/utility/LAGraph_DMRead.c | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/src/utility/LAGraph_DMRead.c b/src/utility/LAGraph_DMRead.c index 842ae27024..6283e8d678 100644 --- a/src/utility/LAGraph_DMRead.c +++ b/src/utility/LAGraph_DMRead.c @@ -44,11 +44,20 @@ static int DMRead( if (buff[0] == 'n') { - if (buff[strlen(buff)-2] == 't') - ASSERT(scanf(buff, "n %d, t", *t) != 2) ; + GrB_Index value = 0 ; + char which = ' '; + ASSERT(scanf(buff, "n %d, %c", value, which) != 2) ; - if (buff[strlen(buff)-2] == 's') - ASSERT(scanf(buff, "n %d, s", *s) != 2) ; + switch (which) { + case 's': + *s = value ; + break ; + case 't': + *t = value ; + break; + default: + break; + } } if (buff[0] == 'a') From 2d7ab6f655fae6c93af2b4c4309ac74697dc3131 Mon Sep 17 00:00:00 2001 From: dperry17 Date: Sat, 14 Mar 2026 23:07:07 -0500 Subject: [PATCH 7/7] changed function name --- src/utility/LAGraph_DMRead.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/utility/LAGraph_DMRead.c b/src/utility/LAGraph_DMRead.c index 6283e8d678..d29f976828 100644 --- a/src/utility/LAGraph_DMRead.c +++ b/src/utility/LAGraph_DMRead.c @@ -13,7 +13,7 @@ free(weights); \ } -static int DMRead( +static int LAGraph_DMRead( GrB_Matrix* A, GrB_Index* s, GrB_Index* t,