#include "LG_internal.h"
#include <LAGraph.h>
#include <LAGraphX.h>
static void combine (void *z, const void *x, const void *y)
{
*(uint64_t*)z = ((*(uint64_t*)x) << 32) + (*(uint64_t*)y);
}
static void get_fst (void *y, const void *x)
{
*(uint64_t*)y = (*(uint64_t*)x) >> 32;
}
static void get_snd (void *y, const void *x)
{
*(uint64_t*)y = (*(uint64_t*)x) & INT_MAX;
}
#undef LG_FREE_ALL
#define LG_FREE_ALL LAGraph_Free ((void **) &mem, msg) ;
static GrB_Info Reduce_assign (GrB_Vector w,
GrB_Vector s, GrB_Index *index, GrB_Index n, char *msg)
{
GrB_Index *mem = NULL ;
LG_TRY (LAGraph_Malloc ((void **) &mem, n*3, sizeof (GrB_Index), msg)) ;
GrB_Index *ind = mem, *sval = mem + n, *wval = sval + n;
LG_TRY (GrB_Vector_extractTuples(ind, wval, &n, w));
LG_TRY (GrB_Vector_extractTuples(ind, sval, &n, s));
for (GrB_Index i = 0; i < n; i++)
if (sval[i] < wval[index[i]])
wval[index[i]] = sval[i];
LG_TRY (GrB_Vector_clear(w));
LG_TRY (GrB_Vector_build(w, ind, wval, n, GrB_PLUS_UINT64));
LG_FREE_ALL ;
return GrB_SUCCESS;
}
static GrB_Index *weight = NULL, *parent = NULL, *partner = NULL;
void f1 (bool *z, const void *x, GrB_Index i, GrB_Index j, const void *thunk)
{
uint64_t *aij = (uint64_t*) x;
(*z) = (weight[i] == *aij) && (parent[j] == partner[i]);
}
void f2 (bool *z, const void *x, GrB_Index i, GrB_Index j, const void *thunk)
{
(*z) = (parent[i] != parent[j]);
}
#undef LG_FREE_ALL
#define LG_FREE_ALL \
{ \
GrB_free (&S); \
GrB_free (&T); \
LAGraph_Free ((void **) &I, msg); \
LAGraph_Free ((void **) &V, msg); \
LAGraph_Free ((void **) &SI, msg); \
LAGraph_Free ((void **) &SJ, msg); \
LAGraph_Free ((void **) &SX, msg); \
LAGraph_Free ((void **) &parent, msg); \
LAGraph_Free ((void **) &partner, msg); \
LAGraph_Free ((void **) &weight, msg); \
GrB_free (&f); \
GrB_free (&i); \
GrB_free (&t); \
GrB_free (&edge); \
GrB_free (&cedge); \
GrB_free (&mask); \
GrB_free (&index); \
GrB_free (&comb); \
GrB_free (&combMin); \
GrB_free (&fst); \
GrB_free (&snd); \
GrB_free (&s1); \
GrB_free (&s2); \
}
int LAGraph_msf
(
GrB_Matrix *result, GrB_Matrix A, bool sanitize, char *msg
)
{
#if LAGRAPH_SUITESPARSE
LG_CLEAR_MSG ;
GrB_Info info;
GrB_Index n;
GrB_Matrix S = NULL, T = NULL;
GrB_Vector f = NULL, i = NULL, t = NULL,
edge = NULL, cedge = NULL, mask = NULL, index = NULL;
GrB_Index *I = NULL, *V = NULL, *SI = NULL, *SJ = NULL, *SX = NULL;
GrB_BinaryOp comb = NULL;
GrB_Semiring combMin = NULL;
GrB_UnaryOp fst = NULL, snd = NULL;
GrB_IndexUnaryOp s1 = NULL, s2 = NULL;
if (result == NULL || A == NULL) return (GrB_NULL_POINTER) ;
GrB_Index ncols ;
GRB_TRY (GrB_Matrix_nrows (&n, A));
GRB_TRY (GrB_Matrix_ncols (&ncols, A));
if (n != ncols) return (GrB_DIMENSION_MISMATCH) ;
if (sanitize)
{
GRB_TRY (GrB_Matrix_new (&S, GrB_UINT64, n, n));
GRB_TRY (GrB_eWiseAdd (S, 0, 0, GrB_PLUS_UINT64, A, A, GrB_DESC_T1));
}
else
{
GRB_TRY (GrB_Matrix_dup (&S, A));
}
GRB_TRY (GrB_Matrix_new (&T, GrB_UINT64, n, n));
GRB_TRY (GrB_Vector_new (&t, GrB_UINT64, n));
GRB_TRY (GrB_Vector_new (&f, GrB_UINT64, n));
GRB_TRY (GrB_Vector_new (&i, GrB_UINT64, n));
GRB_TRY (GrB_Vector_new (&edge, GrB_UINT64, n));
GRB_TRY (GrB_Vector_new (&cedge, GrB_UINT64, n));
GRB_TRY (GrB_Vector_new (&mask, GrB_BOOL, n));
GRB_TRY (GrB_Vector_new (&index, GrB_UINT64, n));
LG_TRY (LAGraph_Malloc ((void **) &I, n, sizeof (GrB_Index), msg)) ;
LG_TRY (LAGraph_Malloc ((void **) &V, n, sizeof (GrB_Index), msg)) ;
LG_TRY (LAGraph_Malloc ((void **) &SI, 2*n, sizeof (GrB_Index), msg)) ;
LG_TRY (LAGraph_Malloc ((void **) &SJ, 2*n, sizeof (GrB_Index), msg)) ;
LG_TRY (LAGraph_Malloc ((void **) &SX, 2*n, sizeof (GrB_Index), msg)) ;
LG_TRY (LAGraph_Malloc ((void **) &parent, n, sizeof (GrB_Index), msg)) ;
LG_TRY (LAGraph_Malloc ((void **) &weight, n, sizeof (GrB_Index), msg)) ;
LG_TRY (LAGraph_Malloc ((void **) &partner, n, sizeof (GrB_Index), msg)) ;
for (GrB_Index i = 0; i < n; i++)
I[i] = parent[i] = i;
GRB_TRY (GrB_Vector_build (f, I, parent, n, GrB_PLUS_UINT64));
GRB_TRY (GrB_assign (i, 0, 0, f, GrB_ALL, 0, 0));
GrB_Index inf = ((uint64_t) INT_MAX << 32) ^ INT_MAX;
GRB_TRY (GrB_BinaryOp_new (&comb, combine, GrB_UINT64, GrB_UINT64, GrB_UINT64));
GRB_TRY (GrB_Semiring_new (&combMin, GrB_MIN_MONOID_UINT64, comb));
GRB_TRY (GrB_UnaryOp_new (&fst, get_fst, GrB_UINT64, GrB_UINT64));
GRB_TRY (GrB_UnaryOp_new (&snd, get_snd, GrB_UINT64, GrB_UINT64));
GrB_IndexUnaryOp_new (&s1, (void *) f1, GrB_BOOL, GrB_UINT64, GrB_UINT64);
GrB_IndexUnaryOp_new (&s2, (void *) f2, GrB_BOOL, GrB_UINT64, GrB_UINT64);
GrB_Index nvals, diff, ntuples = 0, num;
GRB_TRY (GrB_Matrix_nvals (&nvals, S));
for (int iters = 1; nvals > 0; iters++)
{
GRB_TRY (GrB_assign (edge, 0, 0, inf, GrB_ALL, 0, 0));
GRB_TRY (GrB_mxv (edge, 0, GrB_MIN_UINT64, combMin, S, f, 0));
GRB_TRY (GrB_assign (t, 0, 0, (uint64_t) INT_MAX, GrB_ALL, 0, 0));
GRB_TRY (GrB_eWiseMult (cedge, 0, 0, comb, t, i, 0));
LG_TRY (Reduce_assign (cedge, edge, parent, n, msg));
GRB_TRY (GrB_eWiseMult (mask, 0, 0, GrB_EQ_UINT64, f, i, 0));
GRB_TRY (GrB_apply (f, mask, GrB_SECOND_UINT64, snd, cedge, 0));
GRB_TRY (GrB_Vector_extractTuples (I, V, &n, f));
GRB_TRY (GrB_extract (t, 0, 0, f, V, n, 0));
GRB_TRY (GrB_eWiseMult (mask, 0, 0, GrB_EQ_UINT64, i, t, 0));
GRB_TRY (GrB_assign (f, mask, GrB_MIN_UINT64, i, GrB_ALL, 0, 0));
GRB_TRY (GrB_eWiseMult (mask, 0, 0, GrB_EQ_UINT64, i, f, 0));
GRB_TRY (GrB_assign (cedge, mask, 0, inf, GrB_ALL, 0, 0));
GRB_TRY (GrB_extract (t, 0, 0, cedge, parent, n, 0));
GRB_TRY (GrB_eWiseMult (mask ,0, 0, GrB_EQ_UINT64, edge, t, 0));
GRB_TRY (GrB_assign (index, 0, 0, n, GrB_ALL, 0, 0));
GRB_TRY (GrB_assign (index, mask, 0, i, GrB_ALL, 0, 0));
GRB_TRY (GrB_assign (t, 0, 0, n, GrB_ALL, 0, 0));
LG_TRY (Reduce_assign (t, index, parent, n, msg));
GRB_TRY (GrB_extract (index, 0, 0, t, parent, n, 0));
GRB_TRY (GrB_eWiseMult (mask ,0, 0, GrB_EQ_UINT64, i, index, 0));
GRB_TRY (GrB_assign (t, 0, 0, inf, GrB_ALL, 0, 0));
GRB_TRY (GrB_apply (t, mask, 0, fst, edge, 0));
GRB_TRY (GrB_Vector_extractTuples (I, weight, &n, t));
GRB_TRY (GrB_assign (t, 0, 0, inf, GrB_ALL, 0, 0));
GRB_TRY (GrB_apply (t, mask, 0, snd, edge, 0));
GRB_TRY (GrB_Vector_extractTuples (I, partner, &n, t));
GRB_TRY (GrB_select (T, 0, 0, s1, S, 0, 0));
GRB_TRY (GrB_Vector_clear (t));
GRB_TRY (GrB_Vector_clear (edge));
GRB_TRY (GrB_mxv (edge, mask, GrB_MIN_UINT64, combMin, T, i, 0));
GRB_TRY (GrB_Vector_nvals (&num, edge));
GRB_TRY (GrB_apply (t, 0, 0, snd, edge, 0));
GRB_TRY (GrB_Vector_extractTuples (SI + ntuples, SJ + ntuples, &num, t));
GRB_TRY (GrB_apply (t, 0, 0, fst, edge, 0));
GRB_TRY (GrB_Vector_extractTuples (SI + ntuples, SX + ntuples, &num, t));
GRB_TRY (GrB_Vector_clear (t));
ntuples += num;
do {
GRB_TRY (GrB_Vector_extractTuples (I, V, &n, f));
GRB_TRY (GrB_extract (t, 0, 0, f, V, n, 0));
GRB_TRY (GrB_eWiseMult (mask, 0, 0, GrB_NE_UINT64, f, t, 0));
GRB_TRY (GrB_assign (f, 0, 0, t, GrB_ALL, 0, 0));
GRB_TRY (GrB_reduce (&diff, 0, GrB_PLUS_MONOID_UINT64, mask, 0));
} while (diff != 0);
GRB_TRY (GrB_Vector_extractTuples (I, parent, &n, f));
GRB_TRY (GrB_select (S, 0, 0, s2, S, 0, 0));
GrB_Matrix_nvals (&nvals, S);
if (nvals == 0) break;
}
GRB_TRY (GrB_Matrix_clear (T));
GRB_TRY (GrB_Matrix_build (T, SI, SJ, SX, ntuples, GrB_SECOND_UINT64));
*result = T;
T = NULL ;
LG_FREE_ALL;
return (GrB_SUCCESS) ;
#else
return (GrB_NOT_IMPLEMENTED) ;
#endif
}