#define LG_FREE_WORK \
{ \
GrB_free (&d1) ; \
GrB_free (&d) ; \
GrB_free (&t) ; \
GrB_free (&w) ; \
GrB_free (&sink) ; \
GrB_free (&rsink) ; \
}
#define LG_FREE_ALL \
{ \
LG_FREE_WORK ; \
GrB_free (&r) ; \
}
#include "LG_internal.h"
int LAGr_PageRank
(
GrB_Vector *centrality, int *iters, const LAGraph_Graph G, float damping, float tol, int itermax, char *msg
)
{
LG_CLEAR_MSG ;
GrB_Vector r = NULL, d = NULL, t = NULL, w = NULL, d1 = NULL ;
GrB_Vector sink = NULL, rsink = NULL ;
LG_ASSERT (centrality != NULL && iters != NULL, GrB_NULL_POINTER) ;
LG_TRY (LAGraph_CheckGraph (G, msg)) ;
GrB_Matrix AT ;
if (G->kind == LAGraph_ADJACENCY_UNDIRECTED ||
G->is_symmetric_structure == LAGraph_TRUE)
{
AT = G->A ;
}
else
{
AT = G->AT ;
LG_ASSERT_MSG (AT != NULL, LAGRAPH_NOT_CACHED, "G->AT is required") ;
}
GrB_Vector d_out = G->out_degree ;
LG_ASSERT_MSG (d_out != NULL,
LAGRAPH_NOT_CACHED, "G->out_degree is required") ;
GrB_Index n ;
(*centrality) = NULL ;
GRB_TRY (GrB_Matrix_nrows (&n, AT)) ;
const float damping_over_n = damping / n ;
const float scaled_damping = (1 - damping) / n ;
float rdiff = 1 ;
GRB_TRY (GrB_Vector_new (&t, GrB_FP32, n)) ;
GRB_TRY (GrB_Vector_new (&r, GrB_FP32, n)) ;
GRB_TRY (GrB_Vector_new (&w, GrB_FP32, n)) ;
GRB_TRY (GrB_assign (r, NULL, NULL, (float) (1.0 / n), GrB_ALL, n, NULL)) ;
GrB_Index nsinks, nvals ;
GRB_TRY (GrB_Vector_nvals (&nvals, d_out)) ;
nsinks = n - nvals ;
if (nsinks > 0)
{
GRB_TRY (GrB_Vector_new (&sink, GrB_BOOL, n)) ;
GRB_TRY (GrB_assign (sink, d_out, NULL, (bool) true, GrB_ALL, n,
GrB_DESC_SC)) ;
GRB_TRY (GrB_Vector_new (&rsink, GrB_FP32, n)) ;
}
GRB_TRY (GrB_Vector_new (&d, GrB_FP32, n)) ;
GRB_TRY (GrB_apply (d, NULL, NULL, GrB_DIV_FP32, d_out, damping, NULL)) ;
float dmin = 1.0 / damping ;
GRB_TRY (GrB_Vector_new (&d1, GrB_FP32, n)) ;
GRB_TRY (GrB_assign (d1, NULL, NULL, dmin, GrB_ALL, n, NULL)) ;
GRB_TRY (GrB_eWiseAdd (d, NULL, NULL, GrB_MAX_FP32, d1, d, NULL)) ;
GrB_free (&d1) ;
for ((*iters) = 0 ; rdiff > tol ; (*iters)++)
{
LG_ASSERT_MSGF ((*iters) < itermax, LAGRAPH_CONVERGENCE_FAILURE,
"pagerank failed to converge in %d iterations", itermax) ;
float teleport = scaled_damping ; if (nsinks > 0)
{
GRB_TRY (GrB_Vector_clear (rsink)) ;
GRB_TRY (GrB_assign (rsink, sink, NULL, r, GrB_ALL, n, GrB_DESC_S));
float sum_rsink = 0 ;
GRB_TRY (GrB_reduce (&sum_rsink, NULL, GrB_PLUS_MONOID_FP32,
rsink, NULL)) ;
teleport += damping_over_n * sum_rsink ;
}
GrB_Vector temp = t ; t = r ; r = temp ;
GRB_TRY (GrB_eWiseMult (w, NULL, NULL, GrB_DIV_FP32, t, d, NULL)) ;
GRB_TRY (GrB_assign (r, NULL, NULL, teleport, GrB_ALL, n, NULL)) ;
GRB_TRY (GrB_mxv (r, NULL, GrB_PLUS_FP32, LAGraph_plus_second_fp32,
AT, w, NULL)) ;
GRB_TRY (GrB_assign (t, NULL, GrB_MINUS_FP32, r, GrB_ALL, n, NULL)) ;
GRB_TRY (GrB_apply (t, NULL, NULL, GrB_ABS_FP32, t, NULL)) ;
GRB_TRY (GrB_reduce (&rdiff, NULL, GrB_PLUS_MONOID_FP32, t, NULL)) ;
}
(*centrality) = r ;
LG_FREE_WORK ;
return (GrB_SUCCESS) ;
}