1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219
|
//------------------------------------------------------------------------------
// GraphBLAS/Demo/Source/mis_check.c: maximal independent set, w/error checking
//------------------------------------------------------------------------------
// SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights Reserved.
// http://suitesparse.com See GraphBLAS/Doc/License.txt for license.
//------------------------------------------------------------------------------
// Modified from the GraphBLAS C API Specification, by Aydin Buluc, Timothy
// Mattson, Scott McMillan, Jose' Moreira, Carl Yang. Based on "GraphBLAS
// Mathematics" by Jeremy Kepner.
// No copyright claim is made for this particular file; the above copyright
// applies to all of SuiteSparse:GraphBLAS, not this file.
// This method has been updated as of Version 2.2 of SuiteSparse:GraphBLAS. It
// now uses GrB_vxm instead of GrB_mxv.
// This version also relies on predefined monoids and semirings, just to
// give an example of their use.
#include "GraphBLAS.h"
#ifdef GxB_SUITESPARSE_GRAPHBLAS
// use predefined semirings. They are safe to free,
// so the FREE_ALL macro can be used as-is in either case.
#define maxSelect1st GxB_MAX_FIRST_FP64
#endif
// "OK(x)" macro defined in graphblas_demos.h calls a GraphBLAS method, and if
// it fails, prints the error, frees workspace, and returns to the caller. It
// uses the FREE_ALL macro to free the workspace.
#define FREE_ALL \
GrB_Vector_free (&iset) ; \
GrB_Vector_free (&prob) ; \
GrB_Vector_free (&neighbor_max) ; \
GrB_Vector_free (&new_members) ; \
GrB_Vector_free (&new_neighbors) ; \
GrB_Vector_free (&candidates) ; \
GrB_Semiring_free (&maxSelect1st) ; \
GrB_Descriptor_free (&r_desc) ; \
GrB_Descriptor_free (&sr_desc) ; \
GrB_BinaryOp_free (&set_random) ; \
GrB_Vector_free (°rees) ; \
GrB_Vector_free (&Seed) ; \
GrB_Vector_free (&X) ; \
prand_finalize ( ) ;
#undef GB_PUBLIC
#define GB_LIBRARY
#include "graphblas_demos.h"
//------------------------------------------------------------------------------
// mis_check: maximal independent set, with error checking
//------------------------------------------------------------------------------
// A variant of Luby's randomized algorithm [Luby 1985].
// Given a numeric n x n adjacency matrix A of an unweighted and undirected
// graph (where the value true represents an edge), compute a maximal set of
// independent nodes and return it in a boolean n-vector, 'iset' where
// set[i] == true implies node i is a member of the set (the iset vector
// should be uninitialized on input.)
// The graph cannot have any self edges, and it must be symmetric. These
// conditions are not checked. Self-edges will cause the method to stall.
// Singletons require special treatment. Since they have no neighbors, their
// prob is never greater than the max of their neighbors, so they never get
// selected and cause the method to stall. To avoid this case they are removed
// from the candidate set at the begining, and added to the iset.
GB_PUBLIC
GrB_Info mis_check // compute a maximal independent set
(
GrB_Vector *iset_output, // iset(i) = true if i is in the set
const GrB_Matrix A, // symmetric Boolean matrix
int64_t seed // random number seed
)
{
// these are set to NULL so that FREE_ALL can safely free all objects
// at any time
GrB_Vector iset = NULL ;
GrB_Vector prob = NULL ; // random probability for each node
GrB_Vector neighbor_max = NULL ; // value of max neighbor probability
GrB_Vector new_members = NULL ; // set of new members to iset
GrB_Vector new_neighbors = NULL ; // new neighbors to new iset members
GrB_Vector candidates = NULL ; // candidate members to iset
#ifndef GxB_SUITESPARSE_GRAPHBLAS
GrB_Semiring maxSelect1st = NULL ; // Max/Select1st "semiring"
#endif
GrB_Descriptor r_desc = NULL ;
GrB_Descriptor sr_desc = NULL ;
GrB_BinaryOp set_random = NULL ;
GrB_Vector degrees = NULL ;
GrB_Vector Seed = NULL ;
GrB_Vector X = NULL ;
GrB_Index n ;
GrB_Info info ;
OK (GrB_Matrix_nrows (&n, A)) ; // n = # of nodes in graph
OK (GrB_Vector_new (&prob, GrB_FP64, n)) ;
OK (GrB_Vector_new (&neighbor_max, GrB_FP64, n)) ;
OK (GrB_Vector_new (&new_members, GrB_BOOL, n)) ;
OK (GrB_Vector_new (&new_neighbors, GrB_BOOL, n)) ;
OK (GrB_Vector_new (&candidates, GrB_BOOL, n)) ;
// Initialize independent set vector, bool
OK (GrB_Vector_new (&iset, GrB_BOOL, n)) ;
#ifndef GxB_SUITESPARSE_GRAPHBLAS
// create the maxSelect1st semiring
OK (GrB_Semiring_new (&maxSelect1st, GrB_MAX_MONOID_FP64, GrB_FIRST_FP64)) ;
#endif
// descriptor: C_replace
OK (GrB_Descriptor_new (&r_desc)) ;
OK (GrB_Descriptor_set (r_desc, GrB_OUTP, GrB_REPLACE)) ;
// create the random number seeds
OK (prand_init ( )) ;
OK (prand_seed (&Seed, seed, n, 0)) ;
OK (GrB_Vector_new (&X, GrB_FP64, n)) ;
// descriptor: C_replace + structural complement of mask
OK (GrB_Descriptor_new (&sr_desc)) ;
OK (GrB_Descriptor_set (sr_desc, GrB_MASK, GrB_COMP)) ;
OK (GrB_Descriptor_set (sr_desc, GrB_OUTP, GrB_REPLACE)) ;
// create the mis_score binary operator
OK (GrB_BinaryOp_new (&set_random, mis_score2,
GrB_FP64, GrB_UINT32, GrB_FP64)) ;
// compute the degree of each node
OK (GrB_Vector_new (°rees, GrB_FP64, n)) ;
OK (GrB_Matrix_reduce_BinaryOp (degrees, NULL, NULL, GrB_PLUS_FP64,
A, NULL)) ;
// singletons are not candidates; they are added to iset first instead
// candidates[degree != 0] = 1
OK (GrB_Vector_assign_BOOL (candidates, degrees, NULL, true,
GrB_ALL, n, NULL)) ;
// add all singletons to iset
// iset[degree == 0] = 1
OK (GrB_Vector_assign_BOOL (iset, degrees, NULL, true,
GrB_ALL, n, sr_desc)) ;
// Iterate while there are candidates to check.
GrB_Index nvals ;
OK (GrB_Vector_nvals (&nvals, candidates)) ;
int64_t last_nvals = nvals ; // just for error-checking
while (nvals > 0)
{
// sparsify the random number seeds (just keep it for each candidate)
OK (GrB_Vector_assign (Seed, candidates, NULL, Seed,
GrB_ALL, n, r_desc)) ;
// compute a random probability scaled by inverse of degree
OK (prand_xget (X, Seed)) ;
OK (GrB_Vector_eWiseMult_BinaryOp (prob, candidates, NULL, set_random,
degrees, X, r_desc)) ;
// compute the max probability of all neighbors
OK (GrB_vxm (neighbor_max, candidates, NULL, maxSelect1st,
prob, A, r_desc)) ;
// select node if its probability is > than all its active neighbors
OK (GrB_Vector_eWiseAdd_BinaryOp (new_members, NULL, NULL, GrB_GT_FP64,
prob, neighbor_max, NULL)) ;
// add new members to independent set.
OK (GrB_Vector_eWiseAdd_BinaryOp (iset, NULL, NULL, GrB_LOR, iset,
new_members, NULL)) ;
// remove new members from set of candidates c = c & !new
OK (GrB_Vector_apply (candidates, new_members, NULL, GrB_IDENTITY_BOOL,
candidates, sr_desc)) ;
OK (GrB_Vector_nvals (&nvals, candidates)) ;
if (nvals == 0) { break ; } // early exit condition
// Neighbors of new members can also be removed from candidates
OK (GrB_vxm (new_neighbors, candidates, NULL,
GrB_LOR_LAND_SEMIRING_BOOL, new_members, A, NULL)) ;
OK (GrB_Vector_apply (candidates, new_neighbors, NULL,
GrB_IDENTITY_BOOL, candidates, sr_desc)) ;
OK (GrB_Vector_nvals (&nvals, candidates)) ;
// this will not occur, unless the input is corrupted somehow,
// or if two candidates have exactly the same score
if (last_nvals == nvals)
{
printf ("stall!\n") ;
OK (GrB_INVALID_VALUE) ;
}
last_nvals = nvals ;
}
// drop explicit false values
OK (GrB_Vector_apply (iset, iset, NULL, GrB_IDENTITY_BOOL, iset, r_desc)) ;
// return result
*iset_output = iset ;
iset = NULL ; // set to NULL so FREE_ALL doesn't free it
// free workspace
FREE_ALL ;
return (GrB_SUCCESS) ;
}
|