#define LG_FREE_WORK \
{ \
GrB_free (&frontier) ; \
GrB_free (&next_frontier) ; \
GrB_free (&symbol_frontier) ; \
GrB_free (&visited) ; \
GrB_free (&final_reducer) ; \
LAGraph_Free ((void **) &A, NULL) ; \
LAGraph_Free ((void **) &B, NULL) ; \
LAGraph_Free ((void **) &BT, NULL) ; \
}
#define LG_FREE_ALL \
{ \
LG_FREE_WORK ; \
GrB_free (reachable) ; \
}
#include "LG_internal.h"
#include "LAGraphX.h"
int LAGraph_RegularPathQuery
(
GrB_Vector *reachable, LAGraph_Graph *R, size_t nl, const GrB_Index *QS, size_t nqs, const GrB_Index *QF, size_t nqf, LAGraph_Graph *G, const GrB_Index *S, size_t ns, char *msg )
{
LG_CLEAR_MSG ;
GrB_Matrix frontier = NULL ; GrB_Matrix symbol_frontier = NULL ; GrB_Matrix next_frontier = NULL ; GrB_Matrix visited = NULL ; GrB_Vector final_reducer = NULL ;
GrB_Index ng = 0 ; GrB_Index nr = 0 ; GrB_Index states = ns ;
GrB_Index rows = 0 ; GrB_Index cols = 0 ; GrB_Index vals = 0 ;
GrB_Matrix *A = NULL ;
GrB_Matrix *B = NULL ;
GrB_Matrix *BT = NULL ;
LG_ASSERT (reachable != NULL, GrB_NULL_POINTER) ;
LG_ASSERT (G != NULL, GrB_NULL_POINTER) ;
LG_ASSERT (R != NULL, GrB_NULL_POINTER) ;
LG_ASSERT (S != NULL, GrB_NULL_POINTER) ;
(*reachable) = NULL ;
for (size_t i = 0 ; i < nl ; i++)
{
if (G[i] == NULL) continue ;
LG_TRY (LAGraph_CheckGraph (G[i], msg)) ;
}
for (size_t i = 0 ; i < nl ; i++)
{
if (R[i] == NULL) continue ;
LG_TRY (LAGraph_CheckGraph (R[i], msg)) ;
}
LG_TRY (LAGraph_Malloc ((void **) &A, nl, sizeof (GrB_Matrix), msg)) ;
for (size_t i = 0 ; i < nl ; i++)
{
if (G[i] == NULL)
{
A[i] = NULL ;
continue ;
}
A[i] = G[i]->A ;
}
LG_TRY (LAGraph_Malloc ((void **) &B, nl, sizeof (GrB_Matrix), msg)) ;
LG_TRY (LAGraph_Malloc ((void **) &BT, nl, sizeof (GrB_Matrix), msg)) ;
for (size_t i = 0 ; i < nl ; i++)
{
BT[i] = NULL ;
if (R[i] == NULL)
{
B[i] = NULL ;
continue ;
}
B[i] = R[i]->A ;
if (R[i]->is_symmetric_structure == LAGraph_TRUE)
{
BT[i] = B[i] ;
}
else
{
BT[i] = R[i]->AT ;
}
}
for (size_t i = 0 ; i < nl ; i++)
{
if (A[i] == NULL) continue ;
GRB_TRY (GrB_Matrix_nrows (&ng, A[i])) ;
break ;
}
for (size_t i = 0 ; i < nl ; i++)
{
if (B[i] == NULL) continue ;
GRB_TRY (GrB_Matrix_nrows (&nr, B[i])) ;
break ;
}
for (size_t i = 0 ; i < nl ; i++)
{
if (A[i] == NULL) continue ;
GRB_TRY (GrB_Matrix_nrows (&rows, A[i])) ;
GRB_TRY (GrB_Matrix_ncols (&cols, A[i])) ;
LG_ASSERT_MSG (rows == ng && cols == ng, LAGRAPH_NOT_CACHED,
"all the matrices in the graph adjacency matrix decomposition "
"should have the same dimensions and be square") ;
}
for (size_t i = 0 ; i < nl ; i++)
{
if (B[i] == NULL) continue ;
GrB_Index rows = 0 ;
GrB_Index cols = 0 ;
GRB_TRY (GrB_Matrix_nrows (&rows, B[i])) ;
GRB_TRY (GrB_Matrix_ncols (&cols, B[i])) ;
LG_ASSERT_MSG (rows == nr && cols == nr, LAGRAPH_NOT_CACHED,
"all the matrices in the NFA adjacency matrix decomposition "
"should have the same dimensions and be square") ;
}
for (size_t i = 0 ; i < ns ; i++)
{
GrB_Index s = S [i] ;
LG_ASSERT_MSG (s < ng, GrB_INVALID_INDEX, "invalid graph source node") ;
}
for (size_t i = 0 ; i < nqs ; i++)
{
GrB_Index qs = QS [i] ;
LG_ASSERT_MSG (qs < nr, GrB_INVALID_INDEX,
"invalid NFA starting state") ;
}
for (size_t i = 0 ; i < nqf ; i++)
{
GrB_Index qf = QF [i] ;
LG_ASSERT_MSG (qf < nr, GrB_INVALID_INDEX, "invalid NFA final state") ;
}
GRB_TRY (GrB_Vector_new (reachable, GrB_BOOL, ng)) ;
GRB_TRY (GrB_Vector_new (&final_reducer, GrB_BOOL, nr)) ;
GrB_assign (final_reducer, NULL, NULL, true, QF, nqf, NULL) ;
GRB_TRY (GrB_Matrix_new (&next_frontier, GrB_BOOL, nr, ng)) ;
GRB_TRY (GrB_Matrix_new (&visited, GrB_BOOL, nr, ng)) ;
GrB_assign (next_frontier, NULL, NULL, true, QS, nqs, S, ns, NULL) ;
GrB_assign (visited, NULL, NULL, true, QS, nqs, S, ns, NULL) ;
GRB_TRY (GrB_Matrix_new (&frontier, GrB_BOOL, nr, ng)) ;
GRB_TRY (GrB_Matrix_new (&symbol_frontier, GrB_BOOL, nr, ng)) ;
while (states != 0)
{
GrB_Matrix old_frontier = frontier ;
frontier = next_frontier ;
next_frontier = old_frontier ;
GRB_TRY (GrB_Matrix_clear(next_frontier)) ;
for (size_t i = 0 ; i < nl ; i++)
{
if (A[i] == NULL || B[i] == NULL) continue ;
if (BT[i] != NULL)
{
GRB_TRY (GrB_mxm (symbol_frontier, GrB_NULL, GrB_NULL,
GrB_LOR_LAND_SEMIRING_BOOL, BT[i], frontier, GrB_DESC_R)) ;
}
else
{
GRB_TRY (GrB_mxm (symbol_frontier, GrB_NULL, GrB_NULL,
GrB_LOR_LAND_SEMIRING_BOOL, B[i], frontier, GrB_DESC_RT0)) ;
}
GRB_TRY (GrB_mxm (next_frontier, visited, GrB_LOR,
GrB_LOR_LAND_SEMIRING_BOOL, symbol_frontier, A[i], GrB_DESC_SC)) ;
}
GRB_TRY (GrB_assign (visited, visited, GrB_NULL, next_frontier,
GrB_ALL, nr, GrB_ALL, ng, GrB_DESC_SC)) ;
GRB_TRY (GrB_Matrix_nvals (&states, next_frontier)) ;
}
GRB_TRY (GrB_vxm (*reachable, GrB_NULL, GrB_NULL,
GrB_LOR_LAND_SEMIRING_BOOL, final_reducer, visited, GrB_NULL)) ;
LG_FREE_WORK ;
return (GrB_SUCCESS) ;
}