#define LG_FREE_WORK \
{ \
GrB_free(&d); \
GrB_free(&dtmp); \
GrB_free(&Atmp); \
GrB_free(&BF_Tuple3); \
GrB_free(&BF_lMIN_Tuple3); \
GrB_free(&BF_PLUSrhs_Tuple3); \
GrB_free(&BF_EQ_Tuple3); \
GrB_free(&BF_lMIN_Tuple3_Monoid); \
GrB_free(&BF_lMIN_PLUSrhs_Tuple3); \
LAGraph_Free ((void**)&I, NULL); \
LAGraph_Free ((void**)&J, NULL); \
LAGraph_Free ((void**)&w, NULL); \
LAGraph_Free ((void**)&W, NULL); \
LAGraph_Free ((void**)&h, NULL); \
LAGraph_Free ((void**)&pi, NULL); \
}
#define LG_FREE_ALL \
{ \
LG_FREE_WORK ; \
GrB_free (pd_output); \
GrB_free (ppi_output); \
GrB_free (ph_output); \
}
#include <LAGraph.h>
#include <LAGraphX.h>
#include <LG_internal.h>
typedef void (*LAGraph_binary_function) (void *, const void *, const void *) ;
typedef struct
{
double w; GrB_Index h; GrB_Index pi; }
BF_Tuple3_struct;
void BF_lMIN_mxv
(
BF_Tuple3_struct *z,
const BF_Tuple3_struct *y,
const BF_Tuple3_struct *x
)
{
if (x->w < y->w
|| (x->w == y->w && x->h < y->h)
|| (x->w == y->w && x->h == y->h && x->pi < y->pi))
{
if (z != x) { *z = *x; }
}
else
{
*z = *y;
}
}
void BF_PLUSrhs_mxv
(
BF_Tuple3_struct *z,
const BF_Tuple3_struct *y,
const BF_Tuple3_struct *x
)
{
z->w = x->w + y->w;
z->h = x->h + y->h;
z->pi = (x->pi != UINT64_MAX && y->pi != 0) ? y->pi : x->pi ;
}
void BF_EQ_mxv
(
bool *z,
const BF_Tuple3_struct *y,
const BF_Tuple3_struct *x
)
{
(*z) = (x->w == y->w && x->h == y->h && x->pi == y->pi) ;
}
GrB_Info LAGraph_BF_full_mxv
(
GrB_Vector *pd_output, GrB_Vector *ppi_output, GrB_Vector *ph_output, const GrB_Matrix AT, const GrB_Index s )
{
GrB_Info info;
char *msg = NULL ;
GrB_Vector d = NULL, dtmp = NULL;
GrB_Matrix Atmp = NULL;
GrB_Type BF_Tuple3;
GrB_BinaryOp BF_lMIN_Tuple3;
GrB_BinaryOp BF_PLUSrhs_Tuple3;
GrB_BinaryOp BF_EQ_Tuple3;
GrB_Monoid BF_lMIN_Tuple3_Monoid;
GrB_Semiring BF_lMIN_PLUSrhs_Tuple3;
GrB_Index nrows, ncols, n, nz; GrB_Index *I = NULL, *J = NULL; GrB_Index *h = NULL, *pi = NULL;
double *w = NULL;
BF_Tuple3_struct *W = NULL;
LG_ASSERT (AT != NULL && pd_output != NULL &&
ppi_output != NULL && ph_output != NULL, GrB_NULL_POINTER) ;
*pd_output = NULL;
*ppi_output = NULL;
*ph_output = NULL;
GRB_TRY (GrB_Matrix_nrows (&nrows, AT)) ;
GRB_TRY (GrB_Matrix_ncols (&ncols, AT)) ;
GRB_TRY (GrB_Matrix_nvals (&nz, AT));
LG_ASSERT_MSG (nrows == ncols, -1002, "A must be square") ;
n = nrows;
LG_ASSERT_MSG (s < n, GrB_INVALID_INDEX, "invalid source node") ;
GRB_TRY (GrB_Type_new(&BF_Tuple3, sizeof(BF_Tuple3_struct)));
GRB_TRY (GrB_BinaryOp_new(&BF_EQ_Tuple3,
(LAGraph_binary_function) (&BF_EQ_mxv),
GrB_BOOL, BF_Tuple3, BF_Tuple3));
GRB_TRY (GrB_BinaryOp_new(&BF_lMIN_Tuple3,
(LAGraph_binary_function) (&BF_lMIN_mxv),
BF_Tuple3, BF_Tuple3, BF_Tuple3));
GRB_TRY (GrB_BinaryOp_new(&BF_PLUSrhs_Tuple3,
(LAGraph_binary_function)(&BF_PLUSrhs_mxv),
BF_Tuple3, BF_Tuple3, BF_Tuple3));
BF_Tuple3_struct BF_identity = (BF_Tuple3_struct) { .w = INFINITY,
.h = UINT64_MAX, .pi = UINT64_MAX };
GRB_TRY (GrB_Monoid_new_UDT(&BF_lMIN_Tuple3_Monoid, BF_lMIN_Tuple3,
&BF_identity));
GRB_TRY (GrB_Semiring_new(&BF_lMIN_PLUSrhs_Tuple3,
BF_lMIN_Tuple3_Monoid, BF_PLUSrhs_Tuple3));
LAGRAPH_TRY (LAGraph_Malloc ((void **) &I, nz, sizeof(GrB_Index), msg)) ;
LAGRAPH_TRY (LAGraph_Malloc ((void **) &J, nz, sizeof(GrB_Index), msg)) ;
LAGRAPH_TRY (LAGraph_Malloc ((void **) &w, nz, sizeof(double), msg)) ;
LAGRAPH_TRY (LAGraph_Malloc ((void **) &W, nz, sizeof(BF_Tuple3_struct),
msg)) ;
GRB_TRY (GrB_Matrix_extractTuples_FP64(I, J, w, &nz, AT));
for (GrB_Index k = 0; k < nz; k++)
{
if (w[k] == 0) {
W[k] = (BF_Tuple3_struct) { .w = 0, .h = 0, .pi = 0 };
}
else
{
W[k] = (BF_Tuple3_struct) { .w = w[k], .h = 1, .pi = J[k] + 1 };
}
}
GRB_TRY (GrB_Matrix_new(&Atmp, BF_Tuple3, n, n));
GRB_TRY (GrB_Matrix_build_UDT(Atmp, I, J, W, nz, BF_lMIN_Tuple3));
LAGraph_Free ((void**)&I, NULL);
LAGraph_Free ((void**)&J, NULL);
LAGraph_Free ((void**)&W, NULL);
LAGraph_Free ((void**)&w, NULL);
GRB_TRY (GrB_Vector_new(&d, BF_Tuple3, n));
BF_Tuple3_struct d0 = (BF_Tuple3_struct) { .w = 0, .h = 0, .pi = 0 };
GRB_TRY (GrB_Vector_setElement_UDT(d, &d0, s));
GRB_TRY (GrB_Vector_dup(&dtmp, d));
bool same= false; int64_t iter = 0;
while (!same && iter < n - 1)
{
GRB_TRY (GrB_mxv(dtmp, GrB_NULL, GrB_NULL, BF_lMIN_PLUSrhs_Tuple3,
Atmp, d, GrB_NULL));
LG_TRY (LAGraph_Vector_IsEqualOp (&same, dtmp, d, BF_EQ_Tuple3, NULL));
if (!same)
{
GrB_Vector ttmp = dtmp;
dtmp = d;
d = ttmp;
}
iter ++;
}
if (!same)
{
GRB_TRY (GrB_mxv(dtmp, GrB_NULL, GrB_NULL, BF_lMIN_PLUSrhs_Tuple3,
Atmp, d, GrB_NULL));
LG_TRY (LAGraph_Vector_IsEqualOp (&same, dtmp, d, BF_EQ_Tuple3, NULL));
if (!same)
{
LG_FREE_ALL;
return (GrB_NO_VALUE) ;
}
}
LAGRAPH_TRY (LAGraph_Malloc ((void **) &I, n, sizeof(GrB_Index), msg)) ;
LAGRAPH_TRY (LAGraph_Malloc ((void **) &W, n, sizeof(BF_Tuple3_struct),
msg)) ;
LAGRAPH_TRY (LAGraph_Malloc ((void **) &w, n, sizeof(double), msg)) ;
LAGRAPH_TRY (LAGraph_Malloc ((void **) &h, n, sizeof(GrB_Index), msg)) ;
LAGRAPH_TRY (LAGraph_Malloc ((void **) &pi, n, sizeof(GrB_Index), msg)) ;
nz = n ;
GRB_TRY (GrB_Vector_extractTuples_UDT (I, (void *) W, &nz, d));
for (GrB_Index k = 0; k < n; k++)
{
w [k] = W[k].w ;
h [k] = W[k].h ;
pi[k] = W[k].pi;
}
GRB_TRY (GrB_Vector_new(pd_output, GrB_FP64, n));
GRB_TRY (GrB_Vector_new(ppi_output, GrB_UINT64, n));
GRB_TRY (GrB_Vector_new(ph_output, GrB_UINT64, n));
GRB_TRY (GrB_Vector_build (*pd_output , I, w , nz, GrB_MIN_FP64 ));
GRB_TRY (GrB_Vector_build (*ppi_output, I, pi, nz, GrB_MIN_UINT64));
GRB_TRY (GrB_Vector_build (*ph_output , I, h , nz, GrB_MIN_UINT64));
LG_FREE_WORK;
return (GrB_SUCCESS) ;
}