#define LG_FREE_ALL \
{ \
GrB_free(&d) ; \
GrB_free(&dtmp) ; \
}
#include <LAGraph.h>
#include <LAGraphX.h>
#include <LG_internal.h>
GrB_Info LAGraph_BF_basic_pushpull
(
GrB_Vector *pd_output, const GrB_Matrix A, const GrB_Matrix AT, const GrB_Index s )
{
GrB_Info info;
char *msg = NULL ;
GrB_Index nrows, ncols, nvalA;
GrB_Vector d = NULL, dtmp = NULL;
LG_ASSERT ((A != NULL || AT != NULL) && pd_output != NULL,
GrB_NULL_POINTER);
(*pd_output) = NULL;
bool use_vxm_with_A;
if (A == NULL)
{
GRB_TRY (GrB_Matrix_nrows (&nrows, AT)) ;
GRB_TRY (GrB_Matrix_ncols (&ncols, AT)) ;
GRB_TRY (GrB_Matrix_nvals (&nvalA, AT)) ;
use_vxm_with_A = false;
}
else
{
GRB_TRY (GrB_Matrix_nrows (&nrows, A)) ;
GRB_TRY (GrB_Matrix_ncols (&ncols, A)) ;
GRB_TRY (GrB_Matrix_nvals (&nvalA, A)) ;
use_vxm_with_A = true;
}
bool push_pull = (A != NULL && AT != NULL) ;
LG_ASSERT_MSG (nrows == ncols, -1002, "A must be square") ;
GrB_Index n = nrows; double dA = (n == 0) ? 0 : (((double) nvalA) / (double) n) ;
LG_ASSERT_MSG (s < n, GrB_INVALID_INDEX, "invalid source node") ;
int64_t dthreshold ;
if (A == NULL)
{
dthreshold = LAGRAPH_MAX (256, sqrt ((double) n)) ;
}
else
{
dthreshold = n/2;
}
size_t csize = sizeof(double) + sizeof(int64_t) ;
double gs_memory = ((double) n * (double) csize)/1e9 ;
bool dsparse = true;
GRB_TRY (GrB_Vector_new(&d, GrB_FP64, n));
GRB_TRY (GrB_Vector_setElement_FP64(d, 0, s));
GRB_TRY (GrB_Vector_dup(&dtmp, d));
int64_t iter = 0; bool same = false;
while (!same && iter < n - 1)
{
if (!use_vxm_with_A)
{
GRB_TRY (GrB_mxv (dtmp, NULL, NULL, GrB_MIN_PLUS_SEMIRING_FP64,
AT, d, NULL));
}
else
{
GRB_TRY (GrB_vxm (dtmp, NULL, NULL, GrB_MIN_PLUS_SEMIRING_FP64,
d, A, NULL));
}
LG_TRY (LAGraph_Vector_IsEqual (&same, dtmp, d, NULL));
if (!same)
{
GrB_Vector ttmp = dtmp;
dtmp = d;
d = ttmp;
}
iter++;
GrB_Index dnz ;
GRB_TRY (GrB_Vector_nvals (&dnz, d)) ;
if (dsparse)
{
if (!push_pull)
{
if (dnz > dthreshold)
{
dsparse = false;
}
}
else
{
double heap_memory = (((double) dnz+1) *
5 * (double) (sizeof(int64_t))) / 1e9;
int log2dnz = 0 ;
while (dnz > 0)
{
dnz = dnz / 2 ;
log2dnz++ ;
}
dsparse = (4 * log2dnz * heap_memory < gs_memory);
use_vxm_with_A = dsparse;
}
if (!dsparse)
{
GRB_TRY (GrB_Vector_setElement_FP64(d, 1e-16, s));
GRB_TRY (GrB_assign (d, d, NULL, INFINITY, GrB_ALL, n,
GrB_DESC_C)) ;
GRB_TRY (GrB_Vector_setElement_FP64(d, 0, s));
}
}
}
if (!same)
{
if (!use_vxm_with_A)
{
GRB_TRY (GrB_mxv(dtmp, NULL, NULL,
GrB_MIN_PLUS_SEMIRING_FP64, AT, d, NULL));
}
else
{
GRB_TRY (GrB_vxm(dtmp, NULL, NULL,
GrB_MIN_PLUS_SEMIRING_FP64, d, A, NULL));
}
LG_TRY (LAGraph_Vector_IsEqual (&same, dtmp, d, NULL));
if (!same)
{
LG_FREE_ALL;
return (GrB_NO_VALUE) ;
}
}
(*pd_output) = d;
d = NULL;
LG_FREE_ALL;
return (GrB_SUCCESS) ;
}