#define LG_FREE_WORK \
{ \
GrB_free (&frontier) ; \
GrB_free (&paths) ; \
GrB_free (&bc_update) ; \
GrB_free (&W) ; \
if (S != NULL) \
{ \
for (int64_t i = 0 ; i < n ; i++) \
{ \
if (S [i] == NULL) break ; \
GrB_free (&(S [i])) ; \
} \
LAGraph_Free ((void **) &S, NULL) ; \
} \
}
#define LG_FREE_ALL \
{ \
LG_FREE_WORK ; \
GrB_free (centrality) ; \
}
#include "LG_internal.h"
int LAGr_Betweenness
(
GrB_Vector *centrality, LAGraph_Graph G, const GrB_Index *sources, int32_t ns, char *msg
)
{
LG_CLEAR_MSG ;
GrB_Matrix *S = NULL ;
GrB_Matrix frontier = NULL ;
GrB_Matrix paths = NULL ;
GrB_Matrix bc_update = NULL ;
GrB_Matrix W = NULL ;
GrB_Index n = 0 ;
LG_ASSERT (centrality != NULL && sources != NULL, GrB_NULL_POINTER) ;
(*centrality) = NULL ;
LG_TRY (LAGraph_CheckGraph (G, msg)) ;
GrB_Matrix A = G->A ;
GrB_Matrix AT ;
if (G->kind == LAGraph_ADJACENCY_UNDIRECTED ||
G->is_symmetric_structure == LAGraph_TRUE)
{
AT = A ;
}
else
{
AT = G->AT ;
LG_ASSERT_MSG (AT != NULL, LAGRAPH_NOT_CACHED, "G->AT is required") ;
}
GRB_TRY (GrB_Matrix_nrows (&n, A)) ;
GRB_TRY (GrB_Matrix_new (&paths, GrB_FP64, ns, n)) ;
GRB_TRY (GrB_Matrix_new (&frontier, GrB_FP64, ns, n)) ;
GRB_TRY (LG_SET_FORMAT_HINT (paths, LG_BITMAP + LG_FULL)) ;
for (GrB_Index i = 0 ; i < ns ; i++)
{
double one = 1 ;
GrB_Index src = sources [i] ;
LG_ASSERT_MSG (src < n, GrB_INVALID_INDEX, "invalid source node") ;
GRB_TRY (GrB_Matrix_setElement (paths, one, i, src)) ;
GRB_TRY (GrB_Matrix_setElement (frontier, one, i, src)) ;
}
GRB_TRY (GrB_mxm (frontier, paths, NULL, LAGraph_plus_first_fp64,
frontier, A, GrB_DESC_RSC)) ;
LG_TRY (LAGraph_Malloc ((void **) &S, n+1, sizeof (GrB_Matrix), msg)) ;
S [0] = NULL ;
bool last_was_pull = false ;
GrB_Index frontier_size, last_frontier_size = 0 ;
GRB_TRY (GrB_Matrix_nvals (&frontier_size, frontier)) ;
int64_t depth ;
for (depth = 0 ; frontier_size > 0 && depth < n ; depth++)
{
S [depth+1] = NULL ;
LG_TRY (LAGraph_Matrix_Structure (&(S [depth]), frontier, msg)) ;
GRB_TRY (GrB_assign (paths, NULL, GrB_PLUS_FP64, frontier, GrB_ALL, ns,
GrB_ALL, n, NULL)) ;
double frontier_density = ((double) frontier_size) / (double) (ns*n) ;
bool do_pull = frontier_density > (last_was_pull ? 0.06 : 0.10 ) ;
if (do_pull)
{
GRB_TRY (LG_SET_FORMAT_HINT (frontier, LG_BITMAP)) ;
GRB_TRY (GrB_mxm (frontier, paths, NULL, LAGraph_plus_first_fp64,
frontier, AT, GrB_DESC_RSCT1)) ;
}
else {
GRB_TRY (LG_SET_FORMAT_HINT (frontier, LG_SPARSE)) ;
GRB_TRY (GrB_mxm (frontier, paths, NULL, LAGraph_plus_first_fp64,
frontier, A, GrB_DESC_RSC)) ;
}
last_frontier_size = frontier_size ;
last_was_pull = do_pull ;
GRB_TRY (GrB_Matrix_nvals (&frontier_size, frontier)) ;
}
GRB_TRY (GrB_free (&frontier)) ;
GRB_TRY (GrB_Matrix_new (&bc_update, GrB_FP64, ns, n)) ;
GRB_TRY (GrB_assign (bc_update, NULL, NULL, 1, GrB_ALL, ns, GrB_ALL, n,
NULL)) ;
GRB_TRY (GrB_Matrix_new (&W, GrB_FP64, ns, n)) ;
for (int64_t i = depth-1 ; i > 0 ; i--)
{
GRB_TRY (GrB_eWiseMult (W, S [i], NULL, GrB_DIV_FP64, bc_update, paths,
GrB_DESC_RS)) ;
GrB_Index wsize, ssize ;
GrB_Matrix_nvals (&wsize, W) ;
GrB_Matrix_nvals (&ssize, S [i-1]) ;
double w_density = ((double) wsize) / ((double) (ns*n)) ;
double w_to_s_ratio = ((double) wsize) / ((double) ssize) ;
bool do_pull = (w_density > 0.1 && w_to_s_ratio > 1.) ||
(w_density > 0.01 && w_to_s_ratio > 10.) ;
if (do_pull)
{
GRB_TRY (LG_SET_FORMAT_HINT (W, LG_BITMAP)) ;
GRB_TRY (GrB_mxm (W, S [i-1], NULL, LAGraph_plus_first_fp64, W, A,
GrB_DESC_RST1)) ;
}
else {
GRB_TRY (LG_SET_FORMAT_HINT (W, LG_SPARSE)) ;
GRB_TRY (GrB_mxm (W, S [i-1], NULL, LAGraph_plus_first_fp64, W, AT,
GrB_DESC_RS)) ;
}
GRB_TRY (GrB_eWiseMult (bc_update, NULL, GrB_PLUS_FP64, GrB_TIMES_FP64,
W, paths, NULL)) ;
}
GRB_TRY (GrB_Vector_new (centrality, GrB_FP64, n)) ;
GRB_TRY (GrB_assign (*centrality, NULL, NULL, -ns, GrB_ALL, n, NULL)) ;
GRB_TRY (GrB_reduce (*centrality, NULL, GrB_PLUS_FP64, GrB_PLUS_MONOID_FP64,
bc_update, GrB_DESC_T0)) ;
LG_FREE_WORK ;
return (GrB_SUCCESS) ;
}