Skip to content

Commit d578055

Browse files
Merge branch 'v1.3.x' into Louvain
2 parents c9c3a21 + f7e9404 commit d578055

87 files changed

Lines changed: 1490 additions & 39 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.gitignore

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,8 +43,6 @@ CMakeFiles*
4343
*~
4444
data/comments*.txt
4545
data/comments*.mtx
46-
47-
*/build/*
4846
**/.venv/*
4947

5048
# Do not ignore this file

Config/LAGraph.h.in

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2410,11 +2410,11 @@ int LAGr_SingleSourceShortestPath
24102410
) ;
24112411

24122412
//------------------------------------------------------------------------------
2413-
// LAGr_Betweenness: betweeness centrality metric
2413+
// LAGr_Betweenness: betweenness centrality metric
24142414
//------------------------------------------------------------------------------
24152415

2416-
/** LAGr_Betweenness: betweeness centrality metric. This methods computes an
2417-
* approximation of the betweeness-centrality metric of all nodes in the graph.
2416+
/** LAGr_Betweenness: betweenness centrality metric. This methods computes an
2417+
* approximation of the betweenness-centrality metric of all nodes in the graph.
24182418
* Only a few given source nodes are used for the approximation. This is an
24192419
* Advanced algorithm (G->AT is required).
24202420
*
@@ -2442,7 +2442,7 @@ LAGRAPH_PUBLIC
24422442
int LAGr_Betweenness
24432443
(
24442444
// output:
2445-
GrB_Vector *centrality, // centrality(i): betweeness centrality of i
2445+
GrB_Vector *centrality, // centrality(i): betweenness centrality of i
24462446
// input:
24472447
const LAGraph_Graph G, // input graph
24482448
const GrB_Index *sources, // source vertices to compute shortest paths

data/test_zero_cap.mtx

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
%%MatrixMarket matrix coordinate real general
2+
% Example weighted directed graph adjacency (1-indexed)
3+
% All weights are positive; some edges explicitly have zero weight
4+
5 5 9
5+
1 2 0.500000
6+
1 4 0.000000
7+
2 3 1.250000
8+
2 5 2.000000
9+
3 1 0.000000
10+
3 4 3.141590
11+
4 2 0.750000
12+
5 4 0.125000
13+
5 5 1.000000

experimental/algorithm/LAGr_BreadthFirstSearch_Extended.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@
2727

2828
#include "LG_alg_internal.h"
2929

30+
// FIXME: make src, max_level, dest, many_expected inputs GrB_Scalar
31+
3032
int LAGr_BreadthFirstSearch_Extended
3133
(
3234
// output:

experimental/algorithm/LAGr_EdgeBetweennessCentrality.c

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
// FIXED in v10.2 but may need more work in GraphBLAS.
2222

2323
// LAGr_EdgeBetweennessCentrality: Exact algorithm for computing
24-
// betweeness centrality.
24+
// betweenness centrality.
2525

2626
// This is an Advanced algorithm (no self edges allowed)
2727

@@ -91,12 +91,11 @@ void LG_EBC_add_one_divide_function (double *z, const double *x, const double *y
9191
int LAGr_EdgeBetweennessCentrality
9292
(
9393
// output:
94-
GrB_Matrix *centrality, // centrality(i): betweeness centrality of i
94+
GrB_Matrix *centrality, // centrality(i): betweenness centrality of i
9595
// input:
9696
LAGraph_Graph G, // input graph
9797
GrB_Vector sources, // source vertices to compute shortest paths
9898
// (if NULL or empty, use all vertices)
99-
10099
char *msg
101100
)
102101
{
Lines changed: 167 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,167 @@
1+
//------------------------------------------------------------------------------
2+
// LAGraph_Jaccard - parallel jaccard similarity
3+
//------------------------------------------------------------------------------
4+
5+
// LAGraph, (c) 2019-2025 by The LAGraph Contributors, All Rights Reserved.
6+
// SPDX-License-Identifier: BSD-2-Clause
7+
//
8+
// For additional details (including references to third party source code and
9+
// other files) see the LICENSE file or contact permission@sei.cmu.edu. See
10+
// Contributors.txt for a full list of contributors. Created, in part, with
11+
// funding and support from the U.S. Government (see Acknowledgments.txt file).
12+
// DM22-0790
13+
14+
// Contributed by Elaheh Hassani and Tim Davis, Texas A&M University
15+
16+
//------------------------------------------------------------------------------
17+
// LAGr_Jaccard: compute Jaccard similarity (weight) coefficients for an undirected graph.
18+
//
19+
// Inputs:
20+
// G - a valid LAGraph_Graph with:
21+
// * G->A structurally symmetric (undirected)
22+
// * no self-edges
23+
// * G->out_degree cached (no explicit zeros)
24+
// all_pairs - if true, compute Jaccard for all pairs of nodes in the graph;
25+
// if false, compute only for neighboring nodes (current edges).
26+
//
27+
// Output:
28+
// JC - an n-by-n matrix of Jaccard coefficients. JC is always
29+
// returned as an upper-triangular matrix. When all_pairs is
30+
// true, the diagonal entries are equal to 1. When all_pairs is
31+
// false, the diagonal is structurally empty.
32+
//
33+
// Jaccard similarity measures the overlap of neighbor sets.
34+
// For a pair of nodes i and j in the graph G:
35+
// JC(i,j) = |N(i) ∩ N(j)| / |N(i) ∪ N(j)|
36+
// where N(i) is the set of neighbors of i in G.
37+
//
38+
// The computation proceeds in two stages. First, an “intersection matrix” B
39+
// is formed where B(i,j) = |N(i) ∩ N(j)|.
40+
// Second, a degree-based denominator matrix R is formed where
41+
// R(i,j) = deg(i) + deg(j) − B(i,j).
42+
// Lastly, the output matrix JC is computed as the element-wise ratio
43+
// JC = B ./ R.
44+
//
45+
46+
//------------------------------------------------------------------------------
47+
// References:
48+
// (1) "Parallel Algorithms for Computing Jaccard Weights on Graphs using Linear Algebra,"
49+
// in Proc. IEEE High Performance Extreme Computing Conference (HPEC), 2023.
50+
// https://doi.org/10.1109/HPEC58863.2023.10363558
51+
//
52+
// (2) https://en.wikipedia.org/wiki/Jaccard_index
53+
54+
55+
#define LG_FREE_WORK \
56+
{ \
57+
GrB_free(&R); \
58+
GrB_free(&B); \
59+
GrB_free(&D); \
60+
GrB_free (&M) ; \
61+
}
62+
63+
#define LG_FREE_ALL \
64+
{ \
65+
LG_FREE_WORK ; \
66+
}
67+
68+
#include "LG_internal.h"
69+
70+
int LAGr_Jaccard
71+
(
72+
// output
73+
GrB_Matrix *JC,
74+
// input:
75+
LAGraph_Graph G,
76+
bool all_pairs,
77+
char *msg
78+
)
79+
{
80+
GrB_Matrix B = NULL, R = NULL, D = NULL, M = NULL ;
81+
GrB_Index n;
82+
83+
//--------------------------------------------------------------------------
84+
// check inputs
85+
//--------------------------------------------------------------------------
86+
LG_CLEAR_MSG ;
87+
// error if G is directed (OK if G is directed but G->A is symmetric in structure
88+
// error if G has self edges, or unknown
89+
LG_ASSERT (JC != NULL, GrB_NULL_POINTER) ;
90+
(*JC) = NULL ;
91+
LG_TRY (LAGraph_CheckGraph (G, msg)) ;
92+
LG_ASSERT_MSG (G->nself_edges == 0, LAGRAPH_NO_SELF_EDGES_ALLOWED, "G->nself_edges must be zero") ;
93+
LG_ASSERT_MSG ((G->kind == LAGraph_ADJACENCY_UNDIRECTED || (G->kind == LAGraph_ADJACENCY_DIRECTED &&
94+
G->is_symmetric_structure == LAGraph_TRUE)),
95+
LAGRAPH_SYMMETRIC_STRUCTURE_REQUIRED,
96+
"G->A must be known to be symmetric") ;
97+
//--------------------------------------------------------------------------
98+
// degree vector deg
99+
//--------------------------------------------------------------------------
100+
GrB_Vector deg = G->out_degree ;
101+
LG_ASSERT_MSG (deg != NULL, LAGRAPH_NOT_CACHED, "G->out_degree is required") ;
102+
GrB_Matrix A = G->A ;
103+
GRB_TRY( GrB_Matrix_nrows (&n, A) );
104+
GrB_Type int_type = (n > INT32_MAX) ? GrB_INT64 : GrB_INT32 ;
105+
106+
//--------------------------------------------------------------------------
107+
// B is intersection matrix
108+
//--------------------------------------------------------------------------
109+
110+
// B(i,j) is the size of the intersection of the pattern of A(i,:) and
111+
// A(:,j). If all_pairs is true, B is computed for all entries in A^2.
112+
// Otherwise, it is computed just for entries in triu(A).
113+
114+
// The final output matrix (B) is always upper triangular, in both cases.
115+
116+
GRB_TRY(GrB_Matrix_new(&B, GrB_FP64, n, n));
117+
118+
if (all_pairs)
119+
{
120+
// B = triu (A*A)
121+
GRB_TRY(GrB_mxm(B, NULL, NULL, LAGraph_plus_one_fp64, A, A, NULL));
122+
GRB_TRY( GrB_select(B, NULL, NULL, GrB_TRIU, B, (int64_t)0, NULL));
123+
}
124+
else
125+
{
126+
// B<triu(A)> = A*A'
127+
GRB_TRY(GrB_Matrix_new(&M, GrB_BOOL, n, n));
128+
GRB_TRY( GrB_select(M, NULL, NULL, GrB_TRIU, A, (int64_t)0, NULL));
129+
GRB_TRY(GrB_mxm(B, M, NULL, LAGraph_plus_one_fp64, A, A, GrB_DESC_ST1));
130+
GrB_free (&M) ;
131+
}
132+
133+
//--------------------------------------------------------------------------
134+
// R has summation of degree of corresponding nodes
135+
// B is jaccard index B <- B / (R-B)
136+
//--------------------------------------------------------------------------
137+
138+
// If deg vectors is sparse, make it dense
139+
GrB_Index deg_nnz = 0;
140+
GrB_Vector d = NULL;
141+
GRB_TRY(GrB_Vector_nvals(&deg_nnz, deg));
142+
if (deg_nnz < n ) {
143+
GrB_Vector t = NULL;
144+
GRB_TRY (GrB_Vector_dup(&t, deg));
145+
GRB_TRY (GrB_assign (t, t, NULL, 0, GrB_ALL, n, GrB_DESC_SC)) ;
146+
GRB_TRY (GrB_Vector_dup(&d, t));
147+
}
148+
else {
149+
GRB_TRY (GrB_Vector_dup(&d, deg));
150+
}
151+
152+
// D is degree matrix
153+
GRB_TRY(GrB_Matrix_diag(&D, d, 0)); // use d here
154+
GrB_Matrix_new(&R, int_type, n, n);
155+
156+
// R = B*D -> R_ij = deg_j - b_ij
157+
GRB_TRY(GrB_mxm(R, NULL, NULL, (int_type == GrB_INT64) ? GxB_PLUS_RMINUS_INT64 : GxB_PLUS_RMINUS_INT32, B, D, GrB_DESC_S));
158+
// R = D*R -> R_ij = deg_i + r_ij
159+
GRB_TRY(GrB_mxm(R, NULL, NULL, (int_type == GrB_INT64) ? GxB_PLUS_PLUS_INT64 : GxB_PLUS_PLUS_INT32, D, R, GrB_DESC_S));
160+
161+
GRB_TRY( GrB_eWiseMult(B, NULL, NULL, GrB_DIV_FP64, B, R, NULL) );
162+
(*JC) = B;
163+
B = NULL;
164+
LG_FREE_WORK;
165+
166+
return (GrB_SUCCESS) ;
167+
}

experimental/algorithm/LAGr_MarkovClustering.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,9 @@
4040
#include "LG_internal.h"
4141
#include <LAGraphX.h>
4242

43+
// FIXME: make inputs e, i, pruning_threshold, convergence_threshold GrB_Scalar
44+
// and rename these parameters
45+
4346
int LAGr_MarkovClustering(
4447
// output:
4548
GrB_Vector *c_f, // output cluster vector

experimental/algorithm/LAGr_MaxFlow.c

Lines changed: 52 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
// LAGr_MaxFlow: max flow
33
//------------------------------------------------------------------------------
44

5-
// LAGraph, (c) 2019-2022 by The LAGraph Contributors, All Rights Reserved.
5+
// LAGraph, (c) 2019-2026 by The LAGraph Contributors, All Rights Reserved.
66
// SPDX-License-Identifier: BSD-2-Clause
77
//
88
// For additional details (including references to third party source code and
@@ -26,6 +26,27 @@
2626
// [2] D. Peries and T. Davis, "A parallel push-relabel maximum flow algorithm
2727
// in LAGraph and GraphBLAS", IEEE HPEC'25, Sept 2025.
2828

29+
// FIXME: add something like the following:
30+
31+
// LAGr_MaxFlow computes the maximum flow from the src to sink nodes, returning
32+
// the total maximum flow result as a single double scalar (f). It can
33+
// optionally return the flows on each each, as the flow_mtx parameter. This
34+
// matrix has no pre-flows left in it (which appear during the computation of a
35+
// push/relabel maxflow method). However, computing the flow_mtx is very
36+
// expensive. If not needed, pass in NULL instead of &flow_mtx (say), so it is
37+
// not computed.
38+
39+
// FIXME ... ditto describe: res_mtx
40+
41+
// G can be directed or undirected. It must have edge weights of type
42+
// GrB_FP64, or types that can be typecasting to FP64. This includes all
43+
// built-in types of GraphBLAS. All computations are done in FP64.
44+
45+
// FIXME: say something about convergence failure
46+
47+
// See also LAGraph_MinCut to compute the minimum cut, using the results
48+
// from this method.
49+
2950
// TODO: return the (optional) flow matrix can be costly in terms of run time.
3051
// The HPEC'25 results only benchmark the computation of the max flow, f.
3152
// Future work: we plan on revising how the flow matrix is constructed.
@@ -607,11 +628,15 @@ void print_compareVec(const GrB_Vector vec) {
607628
// LAGraph_MaxFlow
608629
//------------------------------------------------------------------------------
609630

631+
// FIXME: make output f a GrB_Scalar
632+
// FIXME: make input src,sink GrB_Scalar
633+
610634
int LAGr_MaxFlow
611635
(
612636
// output:
613637
double *f, // max flow from src node to sink node
614638
GrB_Matrix *flow_mtx, // optional output flow matrix
639+
GrB_Matrix *res_mtx, // optional output for the residual matrix. Used in the min-cut
615640
// input:
616641
LAGraph_Graph G, // graph to compute maxflow on
617642
GrB_Index src, // source node
@@ -711,6 +736,10 @@ int LAGr_MaxFlow
711736
{
712737
(*flow_mtx) = NULL ;
713738
}
739+
if (res_mtx != NULL)
740+
{
741+
(*res_mtx) = NULL ;
742+
}
714743
LG_TRY(LAGraph_CheckGraph(G, msg));
715744
LG_ASSERT (f != NULL, GrB_NULL_POINTER) ;
716745
(*f) = 0;
@@ -720,6 +749,7 @@ int LAGr_MaxFlow
720749
LG_ASSERT_MSG(nrows == n, GrB_INVALID_VALUE, "Matrix must be square");
721750
LG_ASSERT_MSG(src < n && src >= 0 && sink < n && sink >= 0,
722751
GrB_INVALID_VALUE, "src and sink must be a value between [0, n)");
752+
LG_ASSERT(G->emin_state != LAGraph_BOOLEAN_UNKNOWN, GrB_UNINITIALIZED_OBJECT) ;
723753
LG_ASSERT_MSG(G->emin > 0, GrB_INVALID_VALUE,
724754
"the edge weights (capacities) must be greater than 0");
725755

@@ -1016,9 +1046,23 @@ int LAGr_MaxFlow
10161046

10171047
for (int64_t iter = 0 ; n_active > 0 ; iter++)
10181048
{
1049+
1050+
//--------------------------------------------------------------------------
1051+
// check for convergence failure
1052+
//--------------------------------------------------------------------------
1053+
1054+
// FIXME: test this case, and check if 2n is correct
1055+
1056+
// If the edge weights are vastly different in magnitude, it might be
1057+
// possible for this method to get stuck in an infinite loop. The maximum
1058+
// number of iterations in theory is 2*n, so check if this is exceeded with
1059+
// 3*n as the upper bound just for good measure.
1060+
10191061
#ifdef DBG
10201062
printf ("iter: %ld, n_active %ld\n", iter, n_active) ;
10211063
#endif
1064+
LG_ASSERT (iter < 3*n, LAGRAPH_CONVERGENCE_FAILURE) ;
1065+
10221066
//--------------------------------------------------------------------------
10231067
// Part 1: global relabeling
10241068
//--------------------------------------------------------------------------
@@ -1160,6 +1204,13 @@ int LAGr_MaxFlow
11601204
GRB_TRY(GrB_select(*flow_mtx, NULL, NULL, GrB_VALUEGT_FP64, *flow_mtx, 0, NULL));
11611205
}
11621206

1207+
if(res_mtx != NULL){
1208+
GRB_TRY(GrB_Matrix_new(res_mtx, GrB_FP64, n, n));
1209+
GRB_TRY(GrB_apply(*res_mtx, NULL, NULL, GetResidual, R, NULL)) ;
1210+
// prune zeros and negative entries from R_hat
1211+
GRB_TRY(GrB_select(*res_mtx, NULL, NULL, GrB_VALUEGT_FP64, *res_mtx, 0, NULL)) ;
1212+
}
1213+
11631214
//----------------------------------------------------------------------------
11641215
// for test coverage only
11651216
//----------------------------------------------------------------------------

experimental/algorithm/LAGr_MaximumMatching.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -476,6 +476,9 @@ invert_2(GrB_Vector out, // input/output
476476
GrB_free(&mateC); \
477477
}
478478

479+
// FIXME: make col_init a GrB_Scalar?
480+
// FIXME need a bipartite LAGraph_Graph
481+
479482
int LAGr_MaximumMatching(
480483
// outputs:
481484
GrB_Vector

experimental/algorithm/LAGr_Modularity.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,9 @@
6060
#include "LG_internal.h"
6161
#include <LAGraphX.h>
6262

63+
// FIXME: output modularity a GrB_Scalar
64+
// FIXME: input resolution a GrB_Scalar
65+
6366
int LAGr_Modularity(
6467
// Outputs
6568
double *mod_handle, // output modularity

0 commit comments

Comments
 (0)