#include <stdint.h>
#include "LG_internal.h"
static GrB_Info Reduce_assign
(
GrB_Vector w, GrB_Vector s, GrB_Index *Px, GrB_Index *mem, GrB_Index n
)
{
char *msg = NULL ;
GrB_Index *ind = mem ;
GrB_Index *sval = ind + n ;
GrB_Index *wval = sval + n ;
GRB_TRY (GrB_Vector_extractTuples (ind, wval, &n, w)) ;
GRB_TRY (GrB_Vector_extractTuples (ind, sval, &n, s)) ;
for (GrB_Index j = 0 ; j < n ; j++)
{
if (sval [j] < wval [Px [j]])
{
wval [Px [j]] = sval [j] ;
}
}
GRB_TRY (GrB_Vector_clear (w)) ;
GRB_TRY (GrB_Vector_build (w, ind, wval, n, GrB_PLUS_UINT64)) ;
LG_FREE_ALL ;
return (GrB_SUCCESS) ;
}
typedef struct
{
GrB_Index *pointer ;
}
Parent_struct ;
void my_select_func (void *z, const void *x,
const GrB_Index i, const GrB_Index j, const void *y)
{
Parent_struct *Parent = (Parent_struct *) y ;
GrB_Index *Px = Parent->pointer ;
(*((bool *) z)) = (Px [i] != Px [j]) ;
}
#undef LG_FREE_ALL
#define LG_FREE_ALL \
{ \
LG_FREE_WORK ; \
GrB_free (&parent) ; \
}
#undef LG_FREE_WORK
#define LG_FREE_WORK \
{ \
LAGraph_Free ((void **) &I, NULL) ; \
LAGraph_Free ((void **) &Px, NULL) ; \
LAGraph_Free ((void **) &mem, NULL) ; \
GrB_free (&S) ; \
GrB_free (&Parent_Type) ; \
GrB_free (&gp) ; \
GrB_free (&mnp) ; \
GrB_free (&ccmn) ; \
GrB_free (&ramp) ; \
GrB_free (&mask) ; \
GrB_free (&select_op) ; \
}
int LG_CC_Boruvka
(
GrB_Vector *component, const LAGraph_Graph G, char *msg
)
{
GrB_Index n, *I = NULL, *Px = NULL, *mem = NULL ;
GrB_Vector parent = NULL, gp = NULL, mnp = NULL, ccmn = NULL, ramp = NULL,
mask = NULL ;
GrB_IndexUnaryOp select_op = NULL ;
GrB_Matrix S = NULL ;
GrB_Type Parent_Type = NULL ;
Parent_struct Parent ;
LG_CLEAR_MSG ;
LG_TRY (LAGraph_CheckGraph (G, msg)) ;
LG_ASSERT (component != NULL, GrB_NULL_POINTER) ;
LG_ASSERT_MSG ((G->kind == LAGraph_ADJACENCY_UNDIRECTED ||
(G->kind == LAGraph_ADJACENCY_DIRECTED &&
G->is_symmetric_structure == LAGraph_TRUE)),
LAGRAPH_SYMMETRIC_STRUCTURE_REQUIRED,
"G->A must be known to be symmetric") ;
LG_TRY (LAGraph_Matrix_Structure (&S, G->A, msg)) ;
GRB_TRY (GrB_Matrix_nrows (&n, S)) ;
GRB_TRY (GrB_Vector_new (&parent, GrB_UINT64, n)) ; GRB_TRY (GrB_Vector_new (&gp, GrB_UINT64, n)) ; GRB_TRY (GrB_Vector_new (&mnp, GrB_UINT64, n)) ; GRB_TRY (GrB_Vector_new (&ccmn, GrB_UINT64, n)) ; GRB_TRY (GrB_Vector_new (&mask, GrB_BOOL, n)) ;
LG_TRY (LAGraph_Malloc ((void **) &mem, 3*n, sizeof (GrB_Index), msg)) ;
LG_TRY (LAGraph_Malloc ((void **) &Px, n, sizeof (GrB_Index), msg)) ;
Parent.pointer = Px ;
GRB_TRY (GrB_Type_new (&Parent_Type, sizeof (Parent_struct))) ;
#if !LAGRAPH_SUITESPARSE
LG_TRY (LAGraph_Malloc ((void **) &I, n, sizeof (GrB_Index), msg)) ;
#endif
GRB_TRY (GrB_assign (parent, NULL, NULL, 0, GrB_ALL, n, NULL)) ;
GRB_TRY (GrB_apply (parent, NULL, NULL, GrB_ROWINDEX_INT64, parent, 0,
NULL)) ;
GRB_TRY (GrB_Vector_dup (&ramp, parent)) ;
GRB_TRY (GrB_Vector_extractTuples (I, Px, &n, parent)) ;
GRB_TRY (GrB_IndexUnaryOp_new (&select_op, my_select_func, GrB_BOOL,
GrB_BOOL, Parent_Type)) ;
GrB_Index nvals ;
GRB_TRY (GrB_Matrix_nvals (&nvals, S)) ;
while (nvals > 0)
{
GRB_TRY (GrB_assign (mnp, NULL, NULL, n, GrB_ALL, n, NULL)) ;
GRB_TRY (GrB_mxv (mnp, NULL, GrB_MIN_UINT64,
GrB_MIN_SECOND_SEMIRING_UINT64, S, parent, NULL)) ;
GRB_TRY (GrB_assign (ccmn, NULL, NULL, n, GrB_ALL, n, NULL)) ;
GRB_TRY (Reduce_assign (ccmn, mnp, Px, mem, n)) ;
GRB_TRY (GrB_apply (mask, NULL, NULL, GrB_NE_UINT64, ccmn, n, NULL)) ;
GRB_TRY (GrB_assign (parent, mask, NULL, ccmn, GrB_ALL, n, NULL)) ;
GRB_TRY (GrB_Vector_extractTuples (I, Px, &n, parent)) ;
GRB_TRY (GrB_extract (gp, NULL, NULL, parent, Px, n, NULL)) ;
GRB_TRY (GrB_eWiseMult (mask, NULL, NULL, GrB_EQ_UINT64, gp, ramp,
NULL)) ;
GRB_TRY (GrB_assign (parent, mask, GrB_MIN_UINT64, ramp, GrB_ALL, n,
NULL)) ;
bool changing = true ;
while (true)
{
GRB_TRY (GrB_Vector_extractTuples (I, Px, &n, parent)) ;
GRB_TRY (GrB_extract (gp, NULL, NULL, parent, Px, n, NULL)) ;
GRB_TRY (GrB_eWiseMult (mask, NULL, NULL, GrB_NE_UINT64, parent, gp,
NULL)) ;
GRB_TRY (GrB_reduce (&changing, NULL, GrB_LOR_MONOID_BOOL, mask,
NULL)) ;
if (!changing) break ;
GRB_TRY (GrB_assign (parent, NULL, NULL, gp, GrB_ALL, n, NULL)) ;
}
GRB_TRY (GrB_Matrix_select_UDT (S, NULL, NULL, select_op, S,
(void *) (&Parent), NULL)) ;
GRB_TRY (GrB_wait (S, GrB_MATERIALIZE)) ;
GRB_TRY (GrB_Matrix_nvals (&nvals, S)) ;
}
GRB_TRY (GrB_wait (parent, GrB_MATERIALIZE)) ;
(*component) = parent ;
LG_FREE_WORK ;
return (GrB_SUCCESS) ;
}