github.com/gopherd/gonum@v0.0.4/graph/topo/bron_kerbosch.go (about) 1 // Copyright ©2015 The Gonum Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package topo 6 7 import ( 8 "github.com/gopherd/gonum/graph" 9 "github.com/gopherd/gonum/graph/internal/ordered" 10 "github.com/gopherd/gonum/graph/internal/set" 11 ) 12 13 // DegeneracyOrdering returns the degeneracy ordering and the k-cores of 14 // the undirected graph g. 15 func DegeneracyOrdering(g graph.Undirected) (order []graph.Node, cores [][]graph.Node) { 16 order, offsets := degeneracyOrdering(g) 17 18 ordered.Reverse(order) 19 cores = make([][]graph.Node, len(offsets)) 20 offset := len(order) 21 for i, n := range offsets { 22 cores[i] = order[offset-n : offset] 23 offset -= n 24 } 25 return order, cores 26 } 27 28 // KCore returns the k-core of the undirected graph g with nodes in an 29 // optimal ordering for the coloring number. 30 func KCore(k int, g graph.Undirected) []graph.Node { 31 order, offsets := degeneracyOrdering(g) 32 33 var offset int 34 for _, n := range offsets[:k] { 35 offset += n 36 } 37 core := make([]graph.Node, len(order)-offset) 38 copy(core, order[offset:]) 39 return core 40 } 41 42 // degeneracyOrdering is the common code for DegeneracyOrdering and KCore. It 43 // returns l, the nodes of g in optimal ordering for coloring number and 44 // s, a set of relative offsets into l for each k-core, where k is an index 45 // into s. 46 func degeneracyOrdering(g graph.Undirected) (l []graph.Node, s []int) { 47 nodes := graph.NodesOf(g.Nodes()) 48 49 // The algorithm used here is essentially as described at 50 // http://en.wikipedia.org/w/index.php?title=Degeneracy_%28graph_theory%29&oldid=640308710 51 52 // Initialize an output list L in return parameters. 53 54 // Compute a number d_v for each vertex v in G, 55 // the number of neighbors of v that are not already in L. 56 // Initially, these numbers are just the degrees of the vertices. 57 dv := make(map[int64]int, len(nodes)) 58 var ( 59 maxDegree int 60 neighbours = make(map[int64][]graph.Node) 61 ) 62 for _, n := range nodes { 63 id := n.ID() 64 adj := graph.NodesOf(g.From(id)) 65 neighbours[id] = adj 66 dv[id] = len(adj) 67 if len(adj) > maxDegree { 68 maxDegree = len(adj) 69 } 70 } 71 72 // Initialize an array D such that D[i] contains a list of the 73 // vertices v that are not already in L for which d_v = i. 74 d := make([][]graph.Node, maxDegree+1) 75 for _, n := range nodes { 76 deg := dv[n.ID()] 77 d[deg] = append(d[deg], n) 78 } 79 80 // Initialize k to 0. 81 k := 0 82 // Repeat n times: 83 s = []int{0} 84 for range nodes { 85 // Scan the array cells D[0], D[1], ... until 86 // finding an i for which D[i] is nonempty. 87 var ( 88 i int 89 di []graph.Node 90 ) 91 for i, di = range d { 92 if len(di) != 0 { 93 break 94 } 95 } 96 97 // Set k to max(k,i). 98 if i > k { 99 k = i 100 s = append(s, make([]int, k-len(s)+1)...) 101 } 102 103 // Select a vertex v from D[i]. Add v to the 104 // beginning of L and remove it from D[i]. 105 var v graph.Node 106 v, d[i] = di[len(di)-1], di[:len(di)-1] 107 l = append(l, v) 108 s[k]++ 109 delete(dv, v.ID()) 110 111 // For each neighbor w of v not already in L, 112 // subtract one from d_w and move w to the 113 // cell of D corresponding to the new value of d_w. 114 for _, w := range neighbours[v.ID()] { 115 dw, ok := dv[w.ID()] 116 if !ok { 117 continue 118 } 119 for i, n := range d[dw] { 120 if n.ID() == w.ID() { 121 d[dw][i], d[dw] = d[dw][len(d[dw])-1], d[dw][:len(d[dw])-1] 122 dw-- 123 d[dw] = append(d[dw], w) 124 break 125 } 126 } 127 dv[w.ID()] = dw 128 } 129 } 130 131 return l, s 132 } 133 134 // BronKerbosch returns the set of maximal cliques of the undirected graph g. 135 func BronKerbosch(g graph.Undirected) [][]graph.Node { 136 nodes := graph.NodesOf(g.Nodes()) 137 138 // The algorithm used here is essentially BronKerbosch3 as described at 139 // http://en.wikipedia.org/w/index.php?title=Bron%E2%80%93Kerbosch_algorithm&oldid=656805858 140 141 p := set.NewNodesSize(len(nodes)) 142 for _, n := range nodes { 143 p.Add(n) 144 } 145 x := set.NewNodes() 146 var bk bronKerbosch 147 order, _ := degeneracyOrdering(g) 148 ordered.Reverse(order) 149 for _, v := range order { 150 neighbours := graph.NodesOf(g.From(v.ID())) 151 nv := set.NewNodesSize(len(neighbours)) 152 for _, n := range neighbours { 153 nv.Add(n) 154 } 155 bk.maximalCliquePivot(g, []graph.Node{v}, set.IntersectionOfNodes(p, nv), set.IntersectionOfNodes(x, nv)) 156 p.Remove(v) 157 x.Add(v) 158 } 159 return bk 160 } 161 162 type bronKerbosch [][]graph.Node 163 164 func (bk *bronKerbosch) maximalCliquePivot(g graph.Undirected, r []graph.Node, p, x set.Nodes) { 165 if len(p) == 0 && len(x) == 0 { 166 *bk = append(*bk, r) 167 return 168 } 169 170 neighbours := bk.choosePivotFrom(g, p, x) 171 nu := set.NewNodesSize(len(neighbours)) 172 for _, n := range neighbours { 173 nu.Add(n) 174 } 175 for _, v := range p { 176 if nu.Has(v) { 177 continue 178 } 179 vid := v.ID() 180 neighbours := graph.NodesOf(g.From(vid)) 181 nv := set.NewNodesSize(len(neighbours)) 182 for _, n := range neighbours { 183 nv.Add(n) 184 } 185 186 var found bool 187 for _, n := range r { 188 if n.ID() == vid { 189 found = true 190 break 191 } 192 } 193 var sr []graph.Node 194 if !found { 195 sr = append(r[:len(r):len(r)], v) 196 } 197 198 bk.maximalCliquePivot(g, sr, set.IntersectionOfNodes(p, nv), set.IntersectionOfNodes(x, nv)) 199 p.Remove(v) 200 x.Add(v) 201 } 202 } 203 204 func (*bronKerbosch) choosePivotFrom(g graph.Undirected, p, x set.Nodes) (neighbors []graph.Node) { 205 // TODO(kortschak): Investigate the impact of pivot choice that maximises 206 // |p ⋂ neighbours(u)| as a function of input size. Until then, leave as 207 // compile time option. 208 if !tomitaTanakaTakahashi { 209 for _, n := range p { 210 return graph.NodesOf(g.From(n.ID())) 211 } 212 for _, n := range x { 213 return graph.NodesOf(g.From(n.ID())) 214 } 215 panic("bronKerbosch: empty set") 216 } 217 218 var ( 219 max = -1 220 pivot graph.Node 221 ) 222 maxNeighbors := func(s set.Nodes) { 223 outer: 224 for _, u := range s { 225 nb := graph.NodesOf(g.From(u.ID())) 226 c := len(nb) 227 if c <= max { 228 continue 229 } 230 for n := range nb { 231 if _, ok := p[int64(n)]; ok { 232 continue 233 } 234 c-- 235 if c <= max { 236 continue outer 237 } 238 } 239 max = c 240 pivot = u 241 neighbors = nb 242 } 243 } 244 maxNeighbors(p) 245 maxNeighbors(x) 246 if pivot == nil { 247 panic("bronKerbosch: empty set") 248 } 249 return neighbors 250 }