diff --git a/experimental/algorithm/LAGraph_MinCut.c b/experimental/algorithm/LAGraph_MinCut.c index 7c3572f1c1..d4e9829fbe 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 ) { @@ -79,29 +87,34 @@ 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) ; 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; - + + // 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 - LG_TRY(LAGr_BreadthFirstSearch(&S_bfs, NULL, G, s, msg)); + // 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 1ea1fad389..6a275b67c2 100644 --- a/experimental/test/test_MinCut.c +++ b/experimental/test/test_MinCut.c @@ -1,3 +1,21 @@ +//------------------------------------------------------------------------------ +// experimental/test/test_MinCut: tests for LAGraph_MinCut +//------------------------------------------------------------------------------ + +// 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 @@ -67,7 +85,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)); @@ -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); 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 ); diff --git a/src/utility/LAGraph_DMRead.c b/src/utility/LAGraph_DMRead.c new file mode 100644 index 0000000000..d29f976828 --- /dev/null +++ b/src/utility/LAGraph_DMRead.c @@ -0,0 +1,78 @@ +#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 LAGraph_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 = (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') + { + GrB_Index value = 0 ; + char which = ' '; + ASSERT(scanf(buff, "n %d, %c", value, which) != 2) ; + + switch (which) { + case 's': + *s = value ; + break ; + case 't': + *t = value ; + break; + default: + break; + } + } + + 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) ; +}