File: mis.c

package info (click to toggle)
suitesparse 1%3A5.8.1%2Bdfsg-2
  • links: PTS, VCS
  • area: main
  • in suites: bullseye
  • size: 152,716 kB
  • sloc: ansic: 774,385; cpp: 24,213; makefile: 6,310; fortran: 1,927; java: 1,826; csh: 1,686; ruby: 725; sh: 535; perl: 225; python: 209; sed: 164; awk: 60
file content (185 lines) | stat: -rw-r--r-- 7,196 bytes parent folder | download
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
//------------------------------------------------------------------------------
// GraphBLAS/Demo/Source/mis.c: maximal independent set
//------------------------------------------------------------------------------

// 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.

#include "GraphBLAS.h"
#undef GB_PUBLIC
#define GB_LIBRARY
#include "graphblas_demos.h"

//------------------------------------------------------------------------------
// mis: maximal independent set
//------------------------------------------------------------------------------

// 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                    // 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
)
{

    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
    GrB_Semiring maxSelect1st = NULL ;  // Max/Select1st "semiring"
    GrB_Descriptor r_desc = NULL ;
    GrB_Descriptor sr_desc = NULL ;
    GrB_BinaryOp set_random = NULL ;
    GrB_Vector degrees = NULL ;

    GrB_Index n ;

    GrB_Matrix_nrows (&n, A) ;                 // n = # of nodes in graph

    GrB_Vector_new (&prob, GrB_FP64, n) ;
    GrB_Vector_new (&neighbor_max, GrB_FP64, n) ;
    GrB_Vector_new (&new_members, GrB_BOOL, n) ;
    GrB_Vector_new (&new_neighbors, GrB_BOOL, n) ;
    GrB_Vector_new (&candidates, GrB_BOOL, n) ;

    // Initialize independent set vector, bool
    GrB_Vector_new (&iset, GrB_BOOL, n) ;

    // create the maxSelect1st semiring
    GrB_Semiring_new (&maxSelect1st, GrB_MAX_MONOID_FP64, GrB_FIRST_FP64) ;

    // descriptor: C_replace
    GrB_Descriptor_new (&r_desc) ;
    GrB_Descriptor_set (r_desc, GrB_OUTP, GrB_REPLACE) ;

    // create the random number seeds
    GrB_Vector Seed, X ;
    prand_init ( ) ;
    prand_seed (&Seed, seed, n, 0) ;
    GrB_Vector_new (&X, GrB_FP64, n) ;

    // descriptor: C_replace + structural complement of mask
    GrB_Descriptor_new (&sr_desc) ;
    GrB_Descriptor_set (sr_desc, GrB_MASK, GrB_COMP) ;
    GrB_Descriptor_set (sr_desc, GrB_OUTP, GrB_REPLACE) ;

    // create the mis_score binary operator
    GrB_BinaryOp_new (&set_random, mis_score2, GrB_FP64, GrB_UINT32, GrB_FP64) ;

    // compute the degree of each nodes
    GrB_Vector_new (&degrees, GrB_FP64, n) ;
    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
    GrB_Vector_assign_BOOL (candidates, degrees, NULL, true, GrB_ALL, n, NULL); 

    // add all singletons to iset
    // iset[degree == 0] = 1
    GrB_Vector_assign_BOOL (iset, degrees, NULL, true, GrB_ALL, n, sr_desc) ; 

    // Iterate while there are candidates to check.
    GrB_Index nvals ;
    GrB_Vector_nvals (&nvals, candidates) ;

    int64_t last_nvals = nvals ;

    while (nvals > 0)
    {
        // sparsify the random number seeds (just keep it for each candidate) 
        GrB_Vector_assign (Seed, candidates, NULL, Seed, GrB_ALL, n, r_desc) ;

        // compute a random probability scaled by inverse of degree
        // GrB_Vector_apply (prob, candidates, NULL, set_random, degrees,
        //      r_desc) ;
        prand_xget (X, Seed) ;
        GrB_Vector_eWiseMult_BinaryOp (prob, candidates, NULL, set_random,
            degrees, X, r_desc) ;

        // compute the max probability of all neighbors
        GrB_vxm (neighbor_max, candidates, NULL, maxSelect1st,
            prob, A, r_desc) ;

        // select node if its probability is > than all its active neighbors
        GrB_Vector_eWiseAdd_BinaryOp (new_members, NULL, NULL, GrB_GT_FP64,
            prob, neighbor_max, NULL) ;

        // add new members to independent set.
        GrB_Vector_eWiseAdd_BinaryOp (iset, NULL, NULL, GrB_LOR, iset,
            new_members, NULL) ;

        // remove new members from set of candidates c = c & !new
        GrB_Vector_apply (candidates, new_members, NULL, GrB_IDENTITY_BOOL,
            candidates, sr_desc) ;

        GrB_Vector_nvals (&nvals, candidates) ;
        if (nvals == 0) { break ; }                  // early exit condition

        // Neighbors of new members can also be removed from candidates
        GrB_vxm (new_neighbors, candidates, NULL, GrB_LOR_LAND_SEMIRING_BOOL,
            new_members, A, NULL) ;
        GrB_Vector_apply (candidates, new_neighbors, NULL, GrB_IDENTITY_BOOL,
            candidates, sr_desc) ;

        GrB_Vector_nvals (&nvals, candidates) ;

        // this will not occur, unless the input is corrupted somehow
        if (last_nvals == nvals) { printf ("stall!\n") ; exit (1) ; }
        last_nvals = nvals ;
    }

    // drop explicit false values
    GrB_Vector_apply (iset, iset, NULL, GrB_IDENTITY_BOOL, iset, r_desc) ;

    // return result
    *iset_output = iset ;

    // free workspace
    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 (&degrees) ;
    GrB_Vector_free (&Seed) ;
    GrB_Vector_free (&X) ;
    prand_finalize ( ) ;

    return (GrB_SUCCESS) ;
}