Skip to content

Commit be17313

Browse files
performance bug fix for HPEC25 paper on maxflow
1 parent 50cd0c8 commit be17313

File tree

5 files changed

+144
-24
lines changed

5 files changed

+144
-24
lines changed

ChangeLog

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
Sept 1, 2025: version 1.2.1
2+
3+
* MaxFlow: performance bug fix for results in HPEC'25 paper.
4+
15
July 25, 2025: version 1.2.0
26

37
* v2.1 C API: using the new GrB_get/set methods in the C API;

experimental/algorithm/LAGr_MaxFlow.c

Lines changed: 79 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515

1616
//------------------------------------------------------------------------------
1717

18+
// TODO: work in progress (flow_matrix and global relabel)
19+
1820
// LAGr_MaxFlow is a GraphBLAS implementation of the push-relabel algorithm
1921
// of Baumstark et al. [1]
2022
//
@@ -27,6 +29,7 @@
2729
#include "LG_internal.h"
2830
#include <LAGraph.h>
2931

32+
//#define DBG
3033
#if LG_SUITESPARSE_GRAPHBLAS_V10
3134

3235
//------------------------------------------------------------------------------
@@ -90,6 +93,8 @@ static GrB_Info LG_global_relabel
9093
GrB_Index sink, // sink node
9194
GrB_Vector src_and_sink, // mask vector, with just [src sink]
9295
GrB_UnaryOp GetResidual, // unary op to compute resid=capacity-flow
96+
GrB_BinaryOp global_relabel_accum, // accum for the disconnected assign
97+
GrB_Index relabel_value, // value to relabel the disconnected nodes
9398
// input/output:
9499
GrB_Vector d, // d(i) = height/label of node i
95100
// outputs:
@@ -116,10 +121,10 @@ static GrB_Info LG_global_relabel
116121
LG_TRY(LAGraph_Cached_OutDegree(G2, msg));
117122
// compute lvl using bfs on G2, starting at sink node
118123
LG_TRY(LAGr_BreadthFirstSearch(lvl, NULL, G2, sink, msg));
119-
// d<!struct([src,sink])> = lvl
120-
GRB_TRY(GrB_assign(d, src_and_sink, NULL, *lvl, GrB_ALL, n, GrB_DESC_SC));
121-
// d<!struct(lvl)> = n
122-
GRB_TRY(GrB_assign(d, *lvl, NULL, n, GrB_ALL, n, GrB_DESC_SC));
124+
// d<!struct([src,sink])> = max(d(i), lvl)
125+
GRB_TRY(GrB_assign(d, src_and_sink, global_relabel_accum, *lvl, GrB_ALL, n, GrB_DESC_SC));
126+
// d<!struct(lvl)> = max(d(i), relabel_value)
127+
GRB_TRY(GrB_assign(d, *lvl, global_relabel_accum, relabel_value, GrB_ALL, n, GrB_DESC_SC));
123128
LG_FREE_WORK ;
124129
return (GrB_SUCCESS) ;
125130
}
@@ -459,7 +464,7 @@ JIT_STR(void LG_MF_MxeMult32(LG_MF_resultTuple32 * z,
459464
bool j_active = ((*y) > 0) ;
460465
if ((x->di < x->dj-1) /* case a */
461466
|| (x->di == x->dj-1 && !j_active) /* case b */
462-
|| (x->di == x->dj && (!j_active || (j_active && (i < j)))) /* case c */
467+
|| (x->di == x->dj && (!j_active || (j_active && (i < j)))) /* case c */
463468
|| (x->di == x->dj+1)) /* case d */
464469
{
465470
z->residual = x->residual;
@@ -564,6 +569,28 @@ JIT_STR(void LG_MF_ExtractMatrixFlow(double* flow, const LG_MF_flowEdge* edge){*
564569

565570
#endif
566571

572+
#ifdef DBG
573+
void print_compareVec(const GrB_Vector vec) {
574+
GxB_Iterator iter;
575+
GxB_Iterator_new(&iter);
576+
GrB_Info info = GxB_Vector_Iterator_attach(iter, vec, NULL);
577+
if(info < 0){
578+
printf("error with matrix passed in");
579+
}
580+
info = GxB_Vector_Iterator_seek(iter, 0);
581+
while(info != GxB_EXHAUSTED){
582+
GrB_Index i;
583+
i = GxB_Vector_Iterator_getIndex(iter);
584+
LG_MF_compareTuple32 e;
585+
GxB_Iterator_get_UDT(iter, &e);
586+
printf("(%ld, 0) (di: %d, dj: %d, J: %d, residual: %lf) \n", i, e.di, e.dj, e.j, e.residual);
587+
info = GxB_Vector_Iterator_next(iter);
588+
}
589+
GrB_free(&iter);
590+
}
591+
#endif
592+
593+
567594
//------------------------------------------------------------------------------
568595
// LAGraph_MaxFlow
569596
//------------------------------------------------------------------------------
@@ -766,6 +793,9 @@ int LAGr_MaxFlow
766793

767794
GrB_Type Integer_Type = NULL ;
768795

796+
//accum operator for the global relabel
797+
GrB_BinaryOp global_relabel_accum = NULL ;
798+
769799
#ifdef COVERAGE
770800
// Just for test coverage, use 64-bit ints for n > 100. Do not use this
771801
// rule in production!
@@ -782,6 +812,9 @@ int LAGr_MaxFlow
782812

783813
Integer_Type = GrB_INT64 ;
784814

815+
// use the 64 bit max operator
816+
global_relabel_accum = GrB_MAX_INT64 ;
817+
785818
// create types for computation
786819
GRB_TRY(GxB_Type_new(&ResultTuple, sizeof(LG_MF_resultTuple64),
787820
"LG_MF_resultTuple64", RESULTTUPLE_STR64));
@@ -852,6 +885,9 @@ int LAGr_MaxFlow
852885

853886
Integer_Type = GrB_INT32 ;
854887

888+
// use 32 bit max op
889+
global_relabel_accum = GrB_MAX_INT32 ;
890+
855891
// create types for computation
856892
GRB_TRY(GxB_Type_new(&ResultTuple, sizeof(LG_MF_resultTuple32),
857893
"LG_MF_resultTuple32", RESULTTUPLE_STR32));
@@ -943,8 +979,14 @@ int LAGr_MaxFlow
943979
GRB_TRY(GrB_apply(R, A, NULL, ResidualBackward, AT, GrB_DESC_SC));
944980

945981
// initial global relabeling
946-
LG_TRY (LG_global_relabel (R, sink, src_and_sink, GetResidual, d, &lvl, msg)) ;
947-
982+
// relabel to 2*n to prevent any flow from going to the
983+
// disconnected nodes.
984+
GrB_Index relabel_value = 2*n ;
985+
LG_TRY (LG_global_relabel (R, sink, src_and_sink, GetResidual, global_relabel_accum, relabel_value, d, &lvl, msg)) ;
986+
987+
// reset to n
988+
relabel_value = n ;
989+
948990
// create excess vector e and initial flows from the src to its neighbors
949991
// e<struct(lvl)> = A (src,:)
950992
GRB_TRY(GrB_Vector_new(&e, GrB_FP64, n));
@@ -968,20 +1010,27 @@ int LAGr_MaxFlow
9681010

9691011
for (int64_t iter = 0 ; n_active > 0 ; iter++)
9701012
{
971-
1013+
#ifdef DBG
1014+
printf ("iter: %ld, n_active %ld\n", iter, n_active) ;
1015+
#endif
9721016
//--------------------------------------------------------------------------
9731017
// Part 1: global relabeling
9741018
//--------------------------------------------------------------------------
9751019

976-
if ((iter > 0) && (flow_mtx != NULL) && (iter % 12 == 0))
1020+
if ((iter > 0) && (iter % 12 == 0))
9771021
{
978-
LG_TRY (LG_global_relabel (R, sink, src_and_sink, GetResidual, d, &lvl, msg)) ;
979-
// delete nodes in e that cannot be reached from the sink
980-
// e<!struct(lvl)> = empty scalar
981-
GrB_assign (e, lvl, NULL, empty, GrB_ALL, n, GrB_DESC_SC) ;
1022+
#ifdef DBG
1023+
printf ("relabel at : %ld\n", iter) ;
1024+
#endif
1025+
LG_TRY (LG_global_relabel (R, sink, src_and_sink, GetResidual, global_relabel_accum, relabel_value, d, &lvl, msg)) ;
1026+
if(flow_mtx == NULL){
1027+
// delete nodes in e that cannot be reached from the sink
1028+
// e<!struct(lvl)> = empty scalar
1029+
GrB_assign (e, lvl, NULL, empty, GrB_ALL, n, GrB_DESC_SC) ;
1030+
GRB_TRY(GrB_Vector_nvals(&n_active, e));
1031+
if(n_active == 0) break;
1032+
}
9821033
GrB_free(&lvl);
983-
GRB_TRY(GrB_Vector_nvals(&n_active, e));
984-
if(n_active == 0) break;
9851034
}
9861035

9871036
//--------------------------------------------------------------------------
@@ -1001,6 +1050,14 @@ int LAGr_MaxFlow
10011050
// create Map matrix from pattern and values of yd
10021051
// yd = CreateCompareVec (y,d) using eWiseMult
10031052
GRB_TRY(GrB_eWiseMult(yd, NULL, NULL, CreateCompareVec, y, d, NULL));
1053+
1054+
#ifdef DBG
1055+
print_compareVec(yd);
1056+
GxB_print(d, 3);
1057+
GxB_print(e, 3);
1058+
#endif
1059+
1060+
10041061
// Jvec = ExtractJ (yd), where Jvec(i) = yd(i)->j
10051062
GRB_TRY(GrB_apply(Jvec, NULL, NULL, ExtractJ, yd, NULL));
10061063
GRB_TRY(GrB_Matrix_clear(Map));
@@ -1043,7 +1100,12 @@ int LAGr_MaxFlow
10431100
// create the Delta matrix from delta_vec and y
10441101
// note that delta_vec has the same structure as y
10451102
// Jvec = ExtractYJ (y), where Jvec(i) = y(i)->j
1103+
// if Jvec has no values, then there is no possible
1104+
// candidates to push to, so the algorithm terminates
10461105
GRB_TRY(GrB_apply(Jvec, NULL, NULL, ExtractYJ, y, NULL));
1106+
GrB_Index J_n;
1107+
GRB_TRY(GrB_Vector_nvals(&J_n, Jvec));
1108+
if(J_n == 0) break;
10471109
GRB_TRY(GrB_Matrix_clear(Delta));
10481110
GRB_TRY(GrB_Matrix_build(Delta, delta_vec, Jvec, delta_vec, GxB_IGNORE_DUP, desc));
10491111

@@ -1057,14 +1119,15 @@ int LAGr_MaxFlow
10571119

10581120
// reduce Delta to delta_vec
10591121
// delta_vec = sum (Delta), summing up each row of Delta
1060-
GRB_TRY(GrB_reduce(delta_vec, NULL, NULL, GrB_PLUS_FP64, Delta, GrB_DESC_T0));
1122+
GRB_TRY(GrB_reduce(delta_vec, NULL, NULL, GrB_PLUS_MONOID_FP64, Delta, GrB_DESC_T0));
10611123

10621124
// add delta_vec to e
10631125
// e<struct(delta_vec)> += delta_vec
10641126
GRB_TRY(GrB_assign(e, delta_vec, GrB_PLUS_FP64, delta_vec, GrB_ALL, n, GrB_DESC_S));
10651127

10661128
// augment maxflow for all active nodes
10671129
LG_TRY (LG_augment_maxflow (f, e, sink, src_and_sink, &n_active, msg)) ;
1130+
10681131
}
10691132

10701133
//----------------------------------------------------------------------------

experimental/benchmark/do_maxflow

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
#!/bin/bash
2+
3+
4+
MTX="/home/davis/matrices"
5+
GAP="/home/davis/GAP"
6+
7+
../../build/experimental/benchmark/maxflow_demo $MTX/com-Youtube.mtx 4 275
8+
../../build/experimental/benchmark/maxflow_demo $MTX/com-LiveJournal.mtx 2 88
9+
../../build/experimental/benchmark/maxflow_demo $MTX/com-Orkut.mtx 43 75
10+
11+
../../build/experimental/benchmark/maxflow_demo $GAP/GAP-web/GAP-web.grb 64712 500
12+
../../build/experimental/benchmark/maxflow_demo $GAP/GAP-road/GAP-road.grb 4 1075
13+
../../build/experimental/benchmark/maxflow_demo $GAP/GAP-twitter/GAP-twitter.grb 13 17
14+

experimental/benchmark/maxflow_demo.c

Lines changed: 29 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
#define LAGRAPH_CATCH(info) \
99
{ \
10+
printf ("result: %d %s\n", info, msg) ; \
1011
LAGraph_Delete(&G, msg); \
1112
return (info); \
1213
}
@@ -19,37 +20,58 @@ int main (int argc, char ** argv){
1920

2021
char msg[LAGRAPH_MSG_LEN];
2122
LAGraph_Graph G = NULL;
22-
23+
2324
double flow = 0;
24-
GrB_Index T=0, S=0;
25+
GrB_Index T=0, S=0, nflow ;
26+
GrB_Matrix flow_matrix = NULL ;
2527

2628
LAGRAPH_TRY(LAGraph_Init(msg));
27-
29+
2830
//read in graph
2931
LAGRAPH_TRY(readproblem(&G, NULL, false, true, false, NULL, true, argc, argv));
32+
printf ("read in the problem\n") ;
33+
double t1 = LAGraph_WallClockTime();
3034
LAGRAPH_TRY(LAGraph_Cached_AT(G, msg));
35+
t1 = LAGraph_WallClockTime() - t1 ;
36+
printf ("cached AT, time %g\n", t1) ;
37+
t1 = LAGraph_WallClockTime();
3138
LAGRAPH_TRY(LAGraph_Cached_EMin(G, msg));
39+
t1 = LAGraph_WallClockTime() - t1 ;
40+
printf ("cached EMin, time %g\n", t1) ;
3241

3342
char* end1, *end2;
3443
S = strtoul(argv[2], &end1, 10);
3544
T = strtoul(argv[3], &end2, 10);
3645
if(argc > 4){
3746
int num_threads = atoi(argv[4]);
38-
LAGRAPH_TRY(LAGraph_SetNumThreads(1, num_threads, msg));
47+
LAGRAPH_TRY(LAGraph_SetNumThreads(1, num_threads, msg));
3948
}
4049

50+
int nthreads_outer, nthreads_inner ;
51+
LAGRAPH_TRY(LAGraph_GetNumThreads(&nthreads_outer, &nthreads_inner, msg));
52+
printf ("nthreads: %d %d\n", nthreads_outer, nthreads_inner) ;
53+
4154
if(end1 == 0 || end2 == 0){
4255
printf("values for source and sink are incorrect.\n");
4356
}
44-
printf("Starting max flow from %ld to %ld", S, T);
57+
printf("Starting max flow from %ld to %ld\n", S, T);
4558

46-
//LG_SET_BURBLE(1);
59+
// LG_SET_BURBLE(1);
4760
double time = LAGraph_WallClockTime();
4861
LAGRAPH_TRY(LAGr_MaxFlow(&flow, NULL, G, S, T, msg));
4962
time = LAGraph_WallClockTime() - time;
5063
printf("Time for LAGraph_MaxFlow: %g sec\n", time);
5164
printf("Max Flow is: %lf\n", flow);
52-
65+
66+
/* printf("Starting max flow from %ld to %ld, with flow_matrix returned\n", S, T); */
67+
/* time = LAGraph_WallClockTime(); */
68+
/* LAGRAPH_TRY(LAGr_MaxFlow(&flow, &flow_matrix, G, S, T, msg)); */
69+
/* time = LAGraph_WallClockTime() - time; */
70+
/* printf("Time for LAGraph_MaxFlow with flow matrix: %g sec\n", time); */
71+
/* printf("Max Flow is: %lf\n", flow); */
72+
/* GRB_TRY (GrB_Matrix_nvals (&nflow, flow_matrix)) ; */
73+
/* printf("# of entries in flow matrix: %lu\n", nflow); */
74+
5375
LAGraph_Delete(&G, msg);
5476
LAGRAPH_TRY(LAGraph_Finalize(msg));
5577

experimental/test/test_MaxFlow.c

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ test_info tests[] = {
5353
void test_MaxFlow(void) {
5454
#if LG_SUITESPARSE_GRAPHBLAS_V10
5555
LAGraph_Init(msg);
56-
//OK(LG_SET_BURBLE(1));
56+
//OK(LG_SET_BURBLE(1));
5757
OK(LG_SET_BURBLE(0));
5858
for(uint8_t test = 0; test < NTESTS; test++){
5959
GrB_Matrix A=NULL;
@@ -87,6 +87,23 @@ void test_MaxFlow(void) {
8787
TEST_CHECK(flow == tests[test].F);
8888
OK(GxB_Global_Option_set(GxB_JIT_C_CONTROL, GxB_JIT_ON));
8989

90+
// test all source/destination pairs for small problems
91+
GrB_Index n ;
92+
OK (GrB_Matrix_nrows (&n, G->A)) ;
93+
printf ("n: %ld\n", (int64_t) n) ;
94+
if (n < 100)
95+
{
96+
for (GrB_Index src = 0 ; src < n ; src++)
97+
{
98+
for (GrB_Index dest = 0 ; dest < n ; dest++)
99+
{
100+
printf("src: %ld, dest: %ld\n", src, dest);
101+
if (src == dest) continue ;
102+
OK(LAGr_MaxFlow(&flow, NULL, G, src, dest, msg));
103+
}
104+
}
105+
}
106+
90107
//free work
91108
OK(LAGraph_Delete(&G, msg));
92109
}

0 commit comments

Comments
 (0)