From 70f37f5dfe774818d79b014f4eefb124e474e13b Mon Sep 17 00:00:00 2001 From: dperry17 Date: Mon, 19 Jan 2026 15:55:02 -0600 Subject: [PATCH 1/9] made initial algorithm for the min cut --- experimental/algorithm/LAGraph_MinCut.c | 49 +++++++++++++++++++++++++ include/LAGraphX.h | 11 ++++++ 2 files changed, 60 insertions(+) create mode 100644 experimental/algorithm/LAGraph_MinCut.c diff --git a/experimental/algorithm/LAGraph_MinCut.c b/experimental/algorithm/LAGraph_MinCut.c new file mode 100644 index 0000000000..1f02f8276f --- /dev/null +++ b/experimental/algorithm/LAGraph_MinCut.c @@ -0,0 +1,49 @@ +#include +#include "LG_internal.h" +#include + +#undef LG_FREE_ALL +#undef LG_FREE_WORK + +#define LG_FREE_WORK \ +{ \ + GrB_free(&frontier); \ +} + +#define LG_FREE_ALL \ + LG_FREE_WORK + +int LAGraph_MinCut +( + // outputs + GrB_Vector S, + GrB_Vector S_bar, + // inputs + GrB_Matrix R, + GrB_Index s, + GrB_Index t, + char *msg +) +{ + //do a bfs from the source to the sink, stop if the frontier is empty + //assign the frontier to S + GrB_Vector frontier = NULL; + GrB_Index n = 0, n_frontier = 1; + + GRB_TRY(GrB_Matrix_nrows(&n, R)); + GRB_TRY(GrB_Vector_new(&frontier, GrB_INT64, n)); + GRB_TRY(GrB_Vector_setElement(frontier, 1, s)); + + //initial assign to S + GRB_TRY(GrB_assign(S, NULL, NULL, frontier, GrB_ALL, NULL)); + while(n_frontier > 0){ + GRB_TRY(GrB_mxv(frontier, NULL, NULL, GxB_ANY_PAIR_INT64, R, frontier, GrB_DESC_R)); + GRB_TRY(GrB_assign(S, S, NULL, frontier, GrB_ALL, GrB_DESC_SC)); + GRB_TRY(GrB_Vector_nvals(&n_frontier, frontier)); + } + + GRB_TRY(GrB_assign(S_bar, S, NULL, 1, GrB_ALL, n, GrB_DESC_SC)); + + LG_FREE_ALL; + return (GrB_SUCCESS); +} diff --git a/include/LAGraphX.h b/include/LAGraphX.h index 3355addb2e..50d44f89d2 100644 --- a/include/LAGraphX.h +++ b/include/LAGraphX.h @@ -1515,6 +1515,17 @@ int LAGr_MaxFlow( char* msg ); +LAGRAPHX_PUBLIC +int LAGraph_MinCut( + //outputs + GrB_Vector S, + GrB_Vector S_bar, + // inputs + GrB_Matrix R, //residual graph + GrB_Index s, //source node index + GrB_Index t, //sink node index + char *msg +); #if defined ( __cplusplus ) } From 14ee7fb07b526fb53d097210706ab15017e84285 Mon Sep 17 00:00:00 2001 From: dperry17 Date: Mon, 19 Jan 2026 15:57:17 -0600 Subject: [PATCH 2/9] fixed assign bugs --- experimental/algorithm/LAGraph_MinCut.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/experimental/algorithm/LAGraph_MinCut.c b/experimental/algorithm/LAGraph_MinCut.c index 1f02f8276f..07da177a74 100644 --- a/experimental/algorithm/LAGraph_MinCut.c +++ b/experimental/algorithm/LAGraph_MinCut.c @@ -35,10 +35,10 @@ int LAGraph_MinCut GRB_TRY(GrB_Vector_setElement(frontier, 1, s)); //initial assign to S - GRB_TRY(GrB_assign(S, NULL, NULL, frontier, GrB_ALL, NULL)); + GRB_TRY(GrB_assign(S, NULL, NULL, frontier, GrB_ALL, n, NULL)); while(n_frontier > 0){ GRB_TRY(GrB_mxv(frontier, NULL, NULL, GxB_ANY_PAIR_INT64, R, frontier, GrB_DESC_R)); - GRB_TRY(GrB_assign(S, S, NULL, frontier, GrB_ALL, GrB_DESC_SC)); + GRB_TRY(GrB_assign(S, S, NULL, frontier, GrB_ALL, n, GrB_DESC_SC)); GRB_TRY(GrB_Vector_nvals(&n_frontier, frontier)); } From 0c8371eb3469da3c6eb293e3152b0981fa387154 Mon Sep 17 00:00:00 2001 From: dperry17 Date: Wed, 21 Jan 2026 12:48:42 -0600 Subject: [PATCH 3/9] added test case for the min cut and altered the max flow api --- experimental/algorithm/LAGr_MaxFlow.c | 7 ++ experimental/algorithm/LAGraph_MinCut.c | 40 +++-------- experimental/benchmark/maxflow_demo.c | 4 +- experimental/test/test_MaxFlow.c | 10 +-- experimental/test/test_MinCut.c | 90 +++++++++++++++++++++++++ include/LAGraphX.h | 5 +- 6 files changed, 118 insertions(+), 38 deletions(-) create mode 100644 experimental/test/test_MinCut.c diff --git a/experimental/algorithm/LAGr_MaxFlow.c b/experimental/algorithm/LAGr_MaxFlow.c index 87cc1533b9..add27f0ed9 100644 --- a/experimental/algorithm/LAGr_MaxFlow.c +++ b/experimental/algorithm/LAGr_MaxFlow.c @@ -612,6 +612,7 @@ int LAGr_MaxFlow // output: double *f, // max flow from src node to sink node GrB_Matrix *flow_mtx, // optional output flow matrix + GrB_Matrix *res_mtx, // optional output for min cut // input: LAGraph_Graph G, // graph to compute maxflow on GrB_Index src, // source node @@ -1160,6 +1161,12 @@ int LAGr_MaxFlow GRB_TRY(GrB_select(*flow_mtx, NULL, NULL, GrB_VALUEGT_FP64, *flow_mtx, 0, NULL)); } + if(res_mtx != NULL){ + GRB_TRY(GrB_apply(*res_mtx, NULL, NULL, GetResidual, R, NULL)) ; + // prune zeros and negative entries from R_hat + GRB_TRY(GrB_select(*res_mtx, NULL, NULL, GrB_VALUEGT_FP64, *res_mtx, 0, NULL)) ; + } + //---------------------------------------------------------------------------- // for test coverage only //---------------------------------------------------------------------------- diff --git a/experimental/algorithm/LAGraph_MinCut.c b/experimental/algorithm/LAGraph_MinCut.c index 07da177a74..93019593e5 100644 --- a/experimental/algorithm/LAGraph_MinCut.c +++ b/experimental/algorithm/LAGraph_MinCut.c @@ -2,22 +2,11 @@ #include "LG_internal.h" #include -#undef LG_FREE_ALL -#undef LG_FREE_WORK - -#define LG_FREE_WORK \ -{ \ - GrB_free(&frontier); \ -} - -#define LG_FREE_ALL \ - LG_FREE_WORK - int LAGraph_MinCut ( // outputs - GrB_Vector S, - GrB_Vector S_bar, + GrB_Vector* S, + GrB_Vector* S_bar, // inputs GrB_Matrix R, GrB_Index s, @@ -26,24 +15,17 @@ int LAGraph_MinCut ) { //do a bfs from the source to the sink, stop if the frontier is empty - //assign the frontier to S - GrB_Vector frontier = NULL; - GrB_Index n = 0, n_frontier = 1; - - GRB_TRY(GrB_Matrix_nrows(&n, R)); - GRB_TRY(GrB_Vector_new(&frontier, GrB_INT64, n)); - GRB_TRY(GrB_Vector_setElement(frontier, 1, s)); - //initial assign to S - GRB_TRY(GrB_assign(S, NULL, NULL, frontier, GrB_ALL, n, NULL)); - while(n_frontier > 0){ - GRB_TRY(GrB_mxv(frontier, NULL, NULL, GxB_ANY_PAIR_INT64, R, frontier, GrB_DESC_R)); - GRB_TRY(GrB_assign(S, S, NULL, frontier, GrB_ALL, n, GrB_DESC_SC)); - GRB_TRY(GrB_Vector_nvals(&n_frontier, frontier)); - } + LAGraph_Graph G = NULL; + GrB_Index n = 0; + GrB_Matrix_nrows(&n, R); + + LG_TRY(LAGraph_New(&G, &R, LAGraph_ADJACENCY_DIRECTED, msg)); + LG_TRY(LAGr_BreadthFirstSearch(S, NULL, G, s, msg)); - GRB_TRY(GrB_assign(S_bar, S, NULL, 1, GrB_ALL, n, GrB_DESC_SC)); + LG_TRY(GrB_assign(*S_bar, *S, NULL, 1, GrB_ALL, n, GrB_DESC_SC)); + LG_TRY(GrB_assign(*S, *S, NULL, 1, GrB_ALL, n, GrB_DESC_S)); - LG_FREE_ALL; + LAGraph_Delete(&G, msg); return (GrB_SUCCESS); } diff --git a/experimental/benchmark/maxflow_demo.c b/experimental/benchmark/maxflow_demo.c index 75fb56905c..53e6d04106 100644 --- a/experimental/benchmark/maxflow_demo.c +++ b/experimental/benchmark/maxflow_demo.c @@ -58,7 +58,7 @@ int main (int argc, char ** argv){ // LG_SET_BURBLE(1); double time = LAGraph_WallClockTime(); - LAGRAPH_TRY(LAGr_MaxFlow(&flow, NULL, G, S, T, msg)); + LAGRAPH_TRY(LAGr_MaxFlow(&flow, NULL, NULL, G, S, T, msg)); time = LAGraph_WallClockTime() - time; printf("Time for LAGraph_MaxFlow: %g sec\n", time); printf("Max Flow is: %lf\n", flow); @@ -66,7 +66,7 @@ int main (int argc, char ** argv){ printf("Starting max flow from %" PRIu64 " to %" PRIu64 ", with flow_matrix returned\n", S, T); time = LAGraph_WallClockTime(); - LAGRAPH_TRY(LAGr_MaxFlow(&flow, &flow_matrix, G, S, T, msg)); + LAGRAPH_TRY(LAGr_MaxFlow(&flow, &flow_matrix, NULL, G, S, T, msg)); time = LAGraph_WallClockTime() - time; printf("Time for LAGraph_MaxFlow with flow matrix: %g sec\n", time); printf("Max Flow is: %lf\n", flow); diff --git a/experimental/test/test_MaxFlow.c b/experimental/test/test_MaxFlow.c index 902e605ad4..71515e48ea 100644 --- a/experimental/test/test_MaxFlow.c +++ b/experimental/test/test_MaxFlow.c @@ -84,14 +84,14 @@ void test_MaxFlow(void) { // test with JIT OK(GxB_Global_Option_set(GxB_JIT_C_CONTROL, GxB_JIT_ON)); double flow = 0; - OK(LAGr_MaxFlow(&flow, NULL, G, tests[test].S, tests[test].T, msg)); + OK(LAGr_MaxFlow(&flow, NULL, NULL, G, tests[test].S, tests[test].T, msg)); printf("%s\n", msg); printf("flow is: %lf\n", flow); TEST_CHECK(flow == tests[test].F); // test without JIT OK(GxB_Global_Option_set(GxB_JIT_C_CONTROL, GxB_JIT_OFF)); - OK(LAGr_MaxFlow(&flow, NULL, G, tests[test].S, tests[test].T, msg)); + OK(LAGr_MaxFlow(&flow, NULL, NULL, G, tests[test].S, tests[test].T, msg)); TEST_CHECK(flow == tests[test].F); OK(GxB_Global_Option_set(GxB_JIT_C_CONTROL, GxB_JIT_ON)); @@ -107,7 +107,7 @@ void test_MaxFlow(void) { { printf("src: %d, dest: %d\n", (int) src, (int) dest); if (src == dest) continue ; - OK(LAGr_MaxFlow(&flow, NULL, G, src, dest, msg)); + OK(LAGr_MaxFlow(&flow, NULL, NULL, G, src, dest, msg)); } } } @@ -152,7 +152,7 @@ void test_MaxFlowMtx(void) { // test with JIT OK(GxB_Global_Option_set(GxB_JIT_C_CONTROL, GxB_JIT_ON)); double flow = 0; - OK(LAGr_MaxFlow(&flow, &flow_mtx, G, tests[test].S, tests[test].T, msg)); + OK(LAGr_MaxFlow(&flow, &flow_mtx, NULL, G, tests[test].S, tests[test].T, msg)); TEST_CHECK (flow_mtx != NULL) ; GxB_print (flow_mtx, 2) ; int status = LG_check_flow(flow_mtx, msg); @@ -165,7 +165,7 @@ void test_MaxFlowMtx(void) { // test without JIT OK(GxB_Global_Option_set(GxB_JIT_C_CONTROL, GxB_JIT_OFF)); - OK(LAGr_MaxFlow(&flow, &flow_mtx, G, tests[test].S, tests[test].T, msg)); + OK(LAGr_MaxFlow(&flow, &flow_mtx, NULL, G, tests[test].S, tests[test].T, msg)); TEST_CHECK (flow_mtx != NULL) ; status = LG_check_flow(flow_mtx, msg); TEST_CHECK (status == GrB_SUCCESS) ; diff --git a/experimental/test/test_MinCut.c b/experimental/test/test_MinCut.c new file mode 100644 index 0000000000..3b2d9fe38b --- /dev/null +++ b/experimental/test/test_MinCut.c @@ -0,0 +1,90 @@ +#include +#include +#include +#include +#include + + +char msg[LAGRAPH_MSG_LEN]; +LAGraph_Graph G = NULL; +GrB_Matrix A = NULL; +#define LEN 512 +#define NTESTS 4 +char filename[LEN + 1]; + + +typedef struct { + char* filename; + GrB_Index s; + GrB_Index t; + LAGraph_Kind kind; +} test_case; + +test_case tests[] = { + {"wiki.mtx", 0, 5, LAGraph_ADJACENCY_DIRECTED}, + {"matrix_random_flow.mtx", 0,9, LAGraph_ADJACENCY_DIRECTED}, + {"rand.mtx", 0, 19, LAGraph_ADJACENCY_DIRECTED}, + {"mcl.mtx", 0, 9, LAGraph_ADJACENCY_DIRECTED}, + {"cycle_flow.mtx", 0, 89, LAGraph_ADJACENCY_DIRECTED}, + {"random_weighted_general2.mtx", 0, 299, LAGraph_ADJACENCY_UNDIRECTED}, + {"random_weighted_general1.mtx", 0, 499, LAGraph_ADJACENCY_UNDIRECTED} +}; + + +void test_MinCut() { + + LAGraph_Init(msg); + //OK(LG_SET_BURBLE(1)); + OK(LG_SET_BURBLE(0)); + + for(uint8_t test = 0; test < NTESTS; test++){ + GrB_Matrix A=NULL, R=NULL; + GrB_Vector S=NULL, S_bar=NULL; + GrB_Index n = 0; + printf ("\nMatrix: %s\n", tests[test].filename); + TEST_CASE(tests[test].filename); + + snprintf(filename, LEN, LG_DATA_DIR "%s", tests[test].filename); + FILE* f = fopen(filename, "r"); + TEST_CHECK(f != NULL); + + OK(LAGraph_MMRead(&A, f, msg)); + OK(GrB_Matrix_nrows(&n, A)); + OK(GrB_Matrix_new(&R, GrB_INT64, n, n)); + + OK(GrB_Vector_new(&S, GrB_INT64, n)); + OK(GrB_Vector_new(&S_bar, GrB_INT64, n)); + + OK(fclose(f)); + LAGraph_Kind kind = tests [test].kind ; + OK(LAGraph_New(&G, &A, kind, msg)); + if (kind == LAGraph_ADJACENCY_DIRECTED) + { + OK(LAGraph_Cached_AT(G, msg)); + } + + OK(LAGraph_Cached_EMin(G, msg)); + + // test with JIT + OK(GxB_Global_Option_set(GxB_JIT_C_CONTROL, GxB_JIT_ON)); + double flow = 0; + OK(LAGr_MaxFlow(&flow, NULL, &R, G, tests[test].s, tests[test].t, msg)); + printf("%s\n", msg); + printf("flow is: %lf\n", flow); + + OK(LAGraph_MinCut(&S, &S_bar, R, tests[test].s, tests[test].t, msg)); + + GxB_print(S, 5); + GxB_print(S_bar, 5); + + GrB_free(&A); + GrB_free(&R); + GrB_free(&S); + GrB_free(&S_bar); + } + + LAGraph_Finalize(msg); + +} + +TEST_LIST = {{"MinCut", test_MinCut}, {NULL, NULL}}; diff --git a/include/LAGraphX.h b/include/LAGraphX.h index 50d44f89d2..6f53d4ebb7 100644 --- a/include/LAGraphX.h +++ b/include/LAGraphX.h @@ -1507,6 +1507,7 @@ int LAGr_MaxFlow( //outputs double* f, GrB_Matrix* flow_mtx, + GrB_Matrix* res_mtx, //inputs LAGraph_Graph G, GrB_Index src, //source node index @@ -1518,8 +1519,8 @@ int LAGr_MaxFlow( LAGRAPHX_PUBLIC int LAGraph_MinCut( //outputs - GrB_Vector S, - GrB_Vector S_bar, + GrB_Vector* S, + GrB_Vector* S_bar, // inputs GrB_Matrix R, //residual graph GrB_Index s, //source node index From b1c7493a0efe0a085bd739b3879e2299e2a0999b Mon Sep 17 00:00:00 2001 From: dperry17 Date: Tue, 27 Jan 2026 11:31:02 -0600 Subject: [PATCH 4/9] added the cut edges as a return value. --- experimental/algorithm/LAGraph_MinCut.c | 34 ++++++++++++++++++++++++- experimental/test/test_MinCut.c | 15 +++++++---- include/LAGraphX.h | 2 ++ 3 files changed, 45 insertions(+), 6 deletions(-) diff --git a/experimental/algorithm/LAGraph_MinCut.c b/experimental/algorithm/LAGraph_MinCut.c index 93019593e5..c23df491e4 100644 --- a/experimental/algorithm/LAGraph_MinCut.c +++ b/experimental/algorithm/LAGraph_MinCut.c @@ -2,12 +2,27 @@ #include "LG_internal.h" #include +#undef LG_FREE_ALL +#undef LG_FREE_WORK + +#define LG_FREE_WORK \ +{ \ + GrB_free(&S_diag); \ + GrB_free(&S_bar_diag); \ + LAGraph_Delete(&G, msg); \ +} + +#define LG_FREE_ALL \ + { LG_FREE_WORK } + int LAGraph_MinCut ( // outputs GrB_Vector* S, GrB_Vector* S_bar, + GrB_Matrix* cut_set, // inputs + LAGraph_Graph G_origin, GrB_Matrix R, GrB_Index s, GrB_Index t, @@ -17,15 +32,32 @@ int LAGraph_MinCut //do a bfs from the source to the sink, stop if the frontier is empty LAGraph_Graph G = NULL; + GrB_Matrix S_diag=NULL, S_bar_diag=NULL, A = G_origin->A; GrB_Index n = 0; GrB_Matrix_nrows(&n, R); + if(cut_set == NULL){ + GRB_TRY(GrB_Matrix_new(cut_set, GrB_INT64, n, n)); + } LG_TRY(LAGraph_New(&G, &R, LAGraph_ADJACENCY_DIRECTED, msg)); LG_TRY(LAGr_BreadthFirstSearch(S, NULL, G, s, msg)); + //restore the saturated edges capacities to get the set of cut edges + //LG_TRY(GrB_assign(R, R, NULL, A, GrB_ALL, n, GrB_ALL, n, GrB_DESC_SC)); //also fails + LG_TRY(GrB_assign(*S_bar, *S, NULL, 1, GrB_ALL, n, GrB_DESC_SC)); LG_TRY(GrB_assign(*S, *S, NULL, 1, GrB_ALL, n, GrB_DESC_S)); - LAGraph_Delete(&G, msg); + //GxB_print(G_origin->A, 5); + GRB_TRY(GrB_Matrix_diag(&S_diag, *S, 0)); + GRB_TRY(GrB_Matrix_diag(&S_bar_diag, *S_bar, 0)); + + + GRB_TRY(GrB_mxm(*cut_set, NULL, NULL, GxB_PLUS_TIMES_INT64, G_origin->A, S_bar_diag, NULL)); + //GxB_print(*cut_set, 5); + GRB_TRY(GrB_mxm(*cut_set, NULL, NULL, GxB_PLUS_TIMES_INT64, S_diag, *cut_set, NULL)); + + + LG_FREE_ALL; return (GrB_SUCCESS); } diff --git a/experimental/test/test_MinCut.c b/experimental/test/test_MinCut.c index 3b2d9fe38b..67bb38313f 100644 --- a/experimental/test/test_MinCut.c +++ b/experimental/test/test_MinCut.c @@ -9,7 +9,7 @@ char msg[LAGRAPH_MSG_LEN]; LAGraph_Graph G = NULL; GrB_Matrix A = NULL; #define LEN 512 -#define NTESTS 4 +#define NTESTS 5 char filename[LEN + 1]; @@ -38,7 +38,7 @@ void test_MinCut() { OK(LG_SET_BURBLE(0)); for(uint8_t test = 0; test < NTESTS; test++){ - GrB_Matrix A=NULL, R=NULL; + GrB_Matrix A=NULL, R=NULL, cut_set=NULL; GrB_Vector S=NULL, S_bar=NULL; GrB_Index n = 0; printf ("\nMatrix: %s\n", tests[test].filename); @@ -51,7 +51,8 @@ void test_MinCut() { OK(LAGraph_MMRead(&A, f, msg)); OK(GrB_Matrix_nrows(&n, A)); OK(GrB_Matrix_new(&R, GrB_INT64, n, n)); - + OK(GrB_Matrix_new(&cut_set, GrB_INT64, n, n)); + OK(GrB_Vector_new(&S, GrB_INT64, n)); OK(GrB_Vector_new(&S_bar, GrB_INT64, n)); @@ -72,15 +73,19 @@ void test_MinCut() { printf("%s\n", msg); printf("flow is: %lf\n", flow); - OK(LAGraph_MinCut(&S, &S_bar, R, tests[test].s, tests[test].t, msg)); - + OK(LAGraph_MinCut(&S, &S_bar, &cut_set, G, R, tests[test].s, tests[test].t, msg)); + printf("%s\n", msg); + GxB_print(S, 5); GxB_print(S_bar, 5); + GxB_print(cut_set, 5); GrB_free(&A); GrB_free(&R); GrB_free(&S); GrB_free(&S_bar); + GrB_free(&cut_set); + LAGraph_Delete(&G, msg); } LAGraph_Finalize(msg); diff --git a/include/LAGraphX.h b/include/LAGraphX.h index 6f53d4ebb7..6182f54805 100644 --- a/include/LAGraphX.h +++ b/include/LAGraphX.h @@ -1521,7 +1521,9 @@ int LAGraph_MinCut( //outputs GrB_Vector* S, 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 From 186c322240c662315243bd96c7f738d705ec06be Mon Sep 17 00:00:00 2001 From: dperry17 Date: Wed, 28 Jan 2026 11:54:05 -0600 Subject: [PATCH 5/9] made final prototype changes for the min cut --- experimental/test/test_MinCut.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/experimental/test/test_MinCut.c b/experimental/test/test_MinCut.c index 67bb38313f..ee32d98051 100644 --- a/experimental/test/test_MinCut.c +++ b/experimental/test/test_MinCut.c @@ -9,7 +9,7 @@ char msg[LAGRAPH_MSG_LEN]; LAGraph_Graph G = NULL; GrB_Matrix A = NULL; #define LEN 512 -#define NTESTS 5 +#define NTESTS 7 char filename[LEN + 1]; @@ -40,6 +40,7 @@ void test_MinCut() { for(uint8_t test = 0; test < NTESTS; test++){ GrB_Matrix A=NULL, R=NULL, cut_set=NULL; GrB_Vector S=NULL, S_bar=NULL; + double min_cut = 0; GrB_Index n = 0; printf ("\nMatrix: %s\n", tests[test].filename); TEST_CASE(tests[test].filename); @@ -76,9 +77,14 @@ void test_MinCut() { OK(LAGraph_MinCut(&S, &S_bar, &cut_set, G, R, tests[test].s, tests[test].t, msg)); printf("%s\n", msg); - GxB_print(S, 5); - GxB_print(S_bar, 5); - GxB_print(cut_set, 5); + //GxB_print(S, 5); + //GxB_print(S_bar, 5); + //GxB_print(cut_set, 5); + + OK(GrB_reduce(&min_cut, NULL, GrB_PLUS_MONOID_INT64, cut_set, NULL)); + + TEST_CHECK(flow == min_cut); + printf("The min cut: %lf\n", min_cut); GrB_free(&A); GrB_free(&R); From 352d73cead26f74b86858ead952212f7fe2d4c9e Mon Sep 17 00:00:00 2001 From: dperry17 Date: Fri, 30 Jan 2026 11:45:38 -0600 Subject: [PATCH 6/9] added preliminary api changes --- experimental/algorithm/LAGr_MaxFlow.c | 7 ++++++- experimental/algorithm/LAGraph_MinCut.c | 26 +++++++++++++++---------- experimental/test/test_MinCut.c | 18 +++++------------ 3 files changed, 27 insertions(+), 24 deletions(-) diff --git a/experimental/algorithm/LAGr_MaxFlow.c b/experimental/algorithm/LAGr_MaxFlow.c index add27f0ed9..7a0966248f 100644 --- a/experimental/algorithm/LAGr_MaxFlow.c +++ b/experimental/algorithm/LAGr_MaxFlow.c @@ -612,7 +612,7 @@ int LAGr_MaxFlow // output: double *f, // max flow from src node to sink node GrB_Matrix *flow_mtx, // optional output flow matrix - GrB_Matrix *res_mtx, // optional output for min cut + GrB_Matrix *res_mtx, // optional output for the residual matrix. Used in the min-cut // input: LAGraph_Graph G, // graph to compute maxflow on GrB_Index src, // source node @@ -712,6 +712,10 @@ int LAGr_MaxFlow { (*flow_mtx) = NULL ; } + if (res_mtx != NULL) + { + (*res_mtx) = NULL ; + } LG_TRY(LAGraph_CheckGraph(G, msg)); LG_ASSERT (f != NULL, GrB_NULL_POINTER) ; (*f) = 0; @@ -1162,6 +1166,7 @@ int LAGr_MaxFlow } if(res_mtx != NULL){ + GRB_TRY(GrB_Matrix_new(res_mtx, GrB_FP64, n, n)); GRB_TRY(GrB_apply(*res_mtx, NULL, NULL, GetResidual, R, NULL)) ; // prune zeros and negative entries from R_hat GRB_TRY(GrB_select(*res_mtx, NULL, NULL, GrB_VALUEGT_FP64, *res_mtx, 0, NULL)) ; diff --git a/experimental/algorithm/LAGraph_MinCut.c b/experimental/algorithm/LAGraph_MinCut.c index c23df491e4..30b09d0218 100644 --- a/experimental/algorithm/LAGraph_MinCut.c +++ b/experimental/algorithm/LAGraph_MinCut.c @@ -29,32 +29,38 @@ int LAGraph_MinCut char *msg ) { - //do a bfs from the source to the sink, stop if the frontier is empty + //do a bfs from the source to the sink, stop if the frontier is empty LAGraph_Graph G = NULL; - GrB_Matrix S_diag=NULL, S_bar_diag=NULL, A = G_origin->A; + GrB_Matrix S_diag=NULL, S_bar_diag=NULL; GrB_Index n = 0; GrB_Matrix_nrows(&n, R); - if(cut_set == NULL){ - GRB_TRY(GrB_Matrix_new(cut_set, GrB_INT64, n, n)); - } + + 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 >= 0 && t >= 0, GrB_INVALID_VALUE) ; + + // printf("hit\n"); + GrB_Matrix A = G_origin->A; + + LG_TRY(GrB_Matrix_new(cut_set, GrB_FP64, n, n)); + LG_TRY(GrB_Vector_new(S_bar, GrB_INT64, n)); + LG_TRY(GrB_Vector_new(S, GrB_INT64, n)); LG_TRY(LAGraph_New(&G, &R, LAGraph_ADJACENCY_DIRECTED, msg)); LG_TRY(LAGr_BreadthFirstSearch(S, NULL, G, s, msg)); - //restore the saturated edges capacities to get the set of cut edges - //LG_TRY(GrB_assign(R, R, NULL, A, GrB_ALL, n, GrB_ALL, n, GrB_DESC_SC)); //also fails LG_TRY(GrB_assign(*S_bar, *S, NULL, 1, GrB_ALL, n, GrB_DESC_SC)); LG_TRY(GrB_assign(*S, *S, NULL, 1, GrB_ALL, n, GrB_DESC_S)); - //GxB_print(G_origin->A, 5); GRB_TRY(GrB_Matrix_diag(&S_diag, *S, 0)); GRB_TRY(GrB_Matrix_diag(&S_bar_diag, *S_bar, 0)); - GRB_TRY(GrB_mxm(*cut_set, NULL, NULL, GxB_PLUS_TIMES_INT64, G_origin->A, S_bar_diag, NULL)); - //GxB_print(*cut_set, 5); + GRB_TRY(GrB_mxm(*cut_set, NULL, NULL, GxB_PLUS_TIMES_INT64, A, S_bar_diag, NULL)); GRB_TRY(GrB_mxm(*cut_set, NULL, NULL, GxB_PLUS_TIMES_INT64, S_diag, *cut_set, NULL)); diff --git a/experimental/test/test_MinCut.c b/experimental/test/test_MinCut.c index ee32d98051..1ea1fad389 100644 --- a/experimental/test/test_MinCut.c +++ b/experimental/test/test_MinCut.c @@ -34,9 +34,8 @@ test_case tests[] = { void test_MinCut() { LAGraph_Init(msg); - //OK(LG_SET_BURBLE(1)); +#if LG_SUITESPARSE_GRAPHBLAS_V10 OK(LG_SET_BURBLE(0)); - for(uint8_t test = 0; test < NTESTS; test++){ GrB_Matrix A=NULL, R=NULL, cut_set=NULL; GrB_Vector S=NULL, S_bar=NULL; @@ -50,12 +49,6 @@ void test_MinCut() { TEST_CHECK(f != NULL); OK(LAGraph_MMRead(&A, f, msg)); - OK(GrB_Matrix_nrows(&n, A)); - OK(GrB_Matrix_new(&R, GrB_INT64, n, n)); - OK(GrB_Matrix_new(&cut_set, GrB_INT64, n, n)); - - OK(GrB_Vector_new(&S, GrB_INT64, n)); - OK(GrB_Vector_new(&S_bar, GrB_INT64, n)); OK(fclose(f)); LAGraph_Kind kind = tests [test].kind ; @@ -76,12 +69,8 @@ void test_MinCut() { OK(LAGraph_MinCut(&S, &S_bar, &cut_set, G, R, tests[test].s, tests[test].t, msg)); printf("%s\n", msg); - - //GxB_print(S, 5); - //GxB_print(S_bar, 5); - //GxB_print(cut_set, 5); - OK(GrB_reduce(&min_cut, NULL, GrB_PLUS_MONOID_INT64, cut_set, NULL)); + OK(GrB_reduce(&min_cut, NULL, GrB_PLUS_MONOID_FP64, cut_set, NULL)); TEST_CHECK(flow == min_cut); printf("The min cut: %lf\n", min_cut); @@ -94,6 +83,9 @@ void test_MinCut() { LAGraph_Delete(&G, msg); } +#endif + + LAGraph_Finalize(msg); } From 02e13b255c167ec359251fe4cb4cf2b5a04ae5c3 Mon Sep 17 00:00:00 2001 From: dperry17 Date: Fri, 30 Jan 2026 12:02:30 -0600 Subject: [PATCH 7/9] fixed memory issues --- experimental/algorithm/LAGraph_MinCut.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/experimental/algorithm/LAGraph_MinCut.c b/experimental/algorithm/LAGraph_MinCut.c index 30b09d0218..bc60f8de0d 100644 --- a/experimental/algorithm/LAGraph_MinCut.c +++ b/experimental/algorithm/LAGraph_MinCut.c @@ -47,7 +47,7 @@ int LAGraph_MinCut LG_TRY(GrB_Matrix_new(cut_set, GrB_FP64, n, n)); LG_TRY(GrB_Vector_new(S_bar, GrB_INT64, n)); - LG_TRY(GrB_Vector_new(S, GrB_INT64, n)); + //S is allocated during the bfs LG_TRY(LAGraph_New(&G, &R, LAGraph_ADJACENCY_DIRECTED, msg)); LG_TRY(LAGr_BreadthFirstSearch(S, NULL, G, s, msg)); From 55f5dfcded96f3efc68b85119ac26549ec4a8f09 Mon Sep 17 00:00:00 2001 From: dperry17 Date: Wed, 4 Feb 2026 12:13:18 -0600 Subject: [PATCH 8/9] added new test and input check for max flow --- data/test_zero_cap.mtx | 13 +++++++++++++ experimental/algorithm/LAGr_MaxFlow.c | 1 + experimental/test/test_MaxFlow.c | 3 ++- 3 files changed, 16 insertions(+), 1 deletion(-) create mode 100644 data/test_zero_cap.mtx diff --git a/data/test_zero_cap.mtx b/data/test_zero_cap.mtx new file mode 100644 index 0000000000..8137244111 --- /dev/null +++ b/data/test_zero_cap.mtx @@ -0,0 +1,13 @@ +%%MatrixMarket matrix coordinate real general +% Example weighted directed graph adjacency (1-indexed) +% All weights are positive; some edges explicitly have zero weight +5 5 9 +1 2 0.500000 +1 4 0.000000 +2 3 1.250000 +2 5 2.000000 +3 1 0.000000 +3 4 3.141590 +4 2 0.750000 +5 4 0.125000 +5 5 1.000000 diff --git a/experimental/algorithm/LAGr_MaxFlow.c b/experimental/algorithm/LAGr_MaxFlow.c index 7a0966248f..02c420957a 100644 --- a/experimental/algorithm/LAGr_MaxFlow.c +++ b/experimental/algorithm/LAGr_MaxFlow.c @@ -727,6 +727,7 @@ int LAGr_MaxFlow GrB_INVALID_VALUE, "src and sink must be a value between [0, n)"); LG_ASSERT_MSG(G->emin > 0, GrB_INVALID_VALUE, "the edge weights (capacities) must be greater than 0"); + LG_ASSERT(G->emin_state != LAGraph_BOOLEAN_UNKNOWN, GrB_UNINITIALIZED_OBJECT) ; //get adjacency matrix and its transpose GrB_Matrix A = G->A; diff --git a/experimental/test/test_MaxFlow.c b/experimental/test/test_MaxFlow.c index 71515e48ea..e8c56c2384 100644 --- a/experimental/test/test_MaxFlow.c +++ b/experimental/test/test_MaxFlow.c @@ -30,7 +30,7 @@ GrB_Matrix A = NULL; #ifdef GRAPHBLAS_HAS_CUDA #define NTESTS 4 #else -#define NTESTS 7 +#define NTESTS 8 #endif char filename[LEN + 1]; @@ -47,6 +47,7 @@ test_info tests[] = { {"matrix_random_flow.mtx", 0,9, 22, LAGraph_ADJACENCY_DIRECTED}, {"rand.mtx", 0, 19, 37, LAGraph_ADJACENCY_DIRECTED}, {"mcl.mtx", 0, 9, 0, LAGraph_ADJACENCY_DIRECTED}, + {"test_zero_cap.mtx", 0, 4, 0.5, LAGraph_ADJACENCY_DIRECTED}, #ifndef GRAPHBLAS_HAS_CUDA // FIXME: the CUDA cases are currently very slow for these matrices, // when the GPU is hacked to always be used regardless of problem size: From 7cd79f420111373cf30abde6fd2ecd7372616f8a Mon Sep 17 00:00:00 2001 From: dperry17 Date: Wed, 4 Feb 2026 12:43:33 -0600 Subject: [PATCH 9/9] fixed assert location --- experimental/algorithm/LAGr_MaxFlow.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/experimental/algorithm/LAGr_MaxFlow.c b/experimental/algorithm/LAGr_MaxFlow.c index 02c420957a..12deb4b517 100644 --- a/experimental/algorithm/LAGr_MaxFlow.c +++ b/experimental/algorithm/LAGr_MaxFlow.c @@ -725,9 +725,9 @@ int LAGr_MaxFlow LG_ASSERT_MSG(nrows == n, GrB_INVALID_VALUE, "Matrix must be square"); LG_ASSERT_MSG(src < n && src >= 0 && sink < n && sink >= 0, GrB_INVALID_VALUE, "src and sink must be a value between [0, n)"); + LG_ASSERT(G->emin_state != LAGraph_BOOLEAN_UNKNOWN, GrB_UNINITIALIZED_OBJECT) ; LG_ASSERT_MSG(G->emin > 0, GrB_INVALID_VALUE, "the edge weights (capacities) must be greater than 0"); - LG_ASSERT(G->emin_state != LAGraph_BOOLEAN_UNKNOWN, GrB_UNINITIALIZED_OBJECT) ; //get adjacency matrix and its transpose GrB_Matrix A = G->A;