github.com/gopherd/gonum@v0.0.4/graph/topo/bron_kerbosch_test.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 "reflect" 9 "testing" 10 11 "github.com/gopherd/gonum/graph" 12 "github.com/gopherd/gonum/graph/internal/ordered" 13 "github.com/gopherd/gonum/graph/simple" 14 ) 15 16 var vOrderTests = []struct { 17 g []intset 18 wantCore [][]int64 19 wantK int 20 }{ 21 { 22 g: []intset{ 23 0: linksTo(1, 2, 4, 6), 24 1: linksTo(2, 4, 6), 25 2: linksTo(3, 6), 26 3: linksTo(4, 5), 27 4: linksTo(6), 28 5: nil, 29 6: nil, 30 }, 31 wantCore: [][]int64{ 32 {}, 33 {5}, 34 {3}, 35 {0, 1, 2, 4, 6}, 36 }, 37 wantK: 3, 38 }, 39 { 40 g: batageljZaversnikGraph, 41 wantCore: [][]int64{ 42 {0}, 43 {5, 9, 10, 16}, 44 {1, 2, 3, 4, 11, 12, 13, 15}, 45 {6, 7, 8, 14, 17, 18, 19, 20}, 46 }, 47 wantK: 3, 48 }, 49 } 50 51 func TestDegeneracyOrdering(t *testing.T) { 52 for i, test := range vOrderTests { 53 g := simple.NewUndirectedGraph() 54 for u, e := range test.g { 55 // Add nodes that are not defined by an edge. 56 if g.Node(int64(u)) == nil { 57 g.AddNode(simple.Node(u)) 58 } 59 for v := range e { 60 g.SetEdge(simple.Edge{F: simple.Node(u), T: simple.Node(v)}) 61 } 62 } 63 order, core := DegeneracyOrdering(g) 64 if len(core)-1 != test.wantK { 65 t.Errorf("unexpected value of k for test %d: got: %d want: %d", i, len(core)-1, test.wantK) 66 } 67 var offset int 68 for k, want := range test.wantCore { 69 ordered.Int64s(want) 70 got := make([]int64, len(want)) 71 for j, n := range order[len(order)-len(want)-offset : len(order)-offset] { 72 got[j] = n.ID() 73 } 74 ordered.Int64s(got) 75 if !reflect.DeepEqual(got, want) { 76 t.Errorf("unexpected %d-core for test %d:\ngot: %v\nwant:%v", k, i, got, want) 77 } 78 79 for j, n := range core[k] { 80 got[j] = n.ID() 81 } 82 ordered.Int64s(got) 83 if !reflect.DeepEqual(got, want) { 84 t.Errorf("unexpected %d-core for test %d:\ngot: %v\nwant:%v", k, i, got, want) 85 } 86 offset += len(want) 87 } 88 } 89 } 90 91 func TestKCore(t *testing.T) { 92 for i, test := range vOrderTests { 93 g := simple.NewUndirectedGraph() 94 for u, e := range test.g { 95 // Add nodes that are not defined by an edge. 96 if g.Node(int64(u)) == nil { 97 g.AddNode(simple.Node(u)) 98 } 99 for v := range e { 100 g.SetEdge(simple.Edge{F: simple.Node(u), T: simple.Node(v)}) 101 } 102 } 103 104 for k := 0; k <= test.wantK+1; k++ { 105 var want []int64 106 for _, c := range test.wantCore[k:] { 107 want = append(want, c...) 108 } 109 core := KCore(k, g) 110 if len(core) != len(want) { 111 t.Errorf("unexpected %d-core length for test %d:\ngot: %v\nwant:%v", k, i, len(core), len(want)) 112 continue 113 } 114 115 var got []int64 116 for _, n := range core { 117 got = append(got, n.ID()) 118 } 119 ordered.Int64s(got) 120 ordered.Int64s(want) 121 if !reflect.DeepEqual(got, want) { 122 t.Errorf("unexpected %d-core for test %d:\ngot: %v\nwant:%v", k, i, got, want) 123 } 124 } 125 } 126 } 127 128 var bronKerboschTests = []struct { 129 name string 130 g []intset 131 want [][]int64 132 }{ 133 { 134 // This is the example given in the Bron-Kerbosch article on wikipedia (renumbered). 135 // http://en.wikipedia.org/w/index.php?title=Bron%E2%80%93Kerbosch_algorithm&oldid=656805858 136 name: "wikipedia example", 137 g: []intset{ 138 0: linksTo(1, 4), 139 1: linksTo(2, 4), 140 2: linksTo(3), 141 3: linksTo(4, 5), 142 4: nil, 143 5: nil, 144 }, 145 want: [][]int64{ 146 {0, 1, 4}, 147 {1, 2}, 148 {2, 3}, 149 {3, 4}, 150 {3, 5}, 151 }, 152 }, 153 { 154 name: "Batagelj-Zaversnik Graph", 155 g: batageljZaversnikGraph, 156 want: [][]int64{ 157 {0}, 158 {1, 2}, 159 {1, 3}, 160 {2, 4}, 161 {3, 4}, 162 {4, 5}, 163 {6, 7, 8, 14}, 164 {7, 11, 12}, 165 {9, 11}, 166 {10, 11}, 167 {12, 18}, 168 {13, 14, 15}, 169 {14, 15, 17}, 170 {15, 16}, 171 {17, 18, 19, 20}, 172 }, 173 }, 174 } 175 176 func TestBronKerbosch(t *testing.T) { 177 for _, test := range bronKerboschTests { 178 g := simple.NewUndirectedGraph() 179 for u, e := range test.g { 180 // Add nodes that are not defined by an edge. 181 if g.Node(int64(u)) == nil { 182 g.AddNode(simple.Node(u)) 183 } 184 for v := range e { 185 g.SetEdge(simple.Edge{F: simple.Node(u), T: simple.Node(v)}) 186 } 187 } 188 cliques := BronKerbosch(g) 189 got := make([][]int64, len(cliques)) 190 for j, c := range cliques { 191 ids := make([]int64, len(c)) 192 for k, n := range c { 193 ids[k] = n.ID() 194 } 195 ordered.Int64s(ids) 196 got[j] = ids 197 } 198 ordered.BySliceValues(got) 199 if !reflect.DeepEqual(got, test.want) { 200 t.Errorf("unexpected cliques for test %q:\ngot: %v\nwant:%v", test.name, got, test.want) 201 } 202 } 203 } 204 205 func BenchmarkBronKerbosch(b *testing.B) { 206 for _, test := range bronKerboschTests { 207 g := simple.NewUndirectedGraph() 208 for u, e := range test.g { 209 // Add nodes that are not defined by an edge. 210 if g.Node(int64(u)) == nil { 211 g.AddNode(simple.Node(u)) 212 } 213 for v := range e { 214 g.SetEdge(simple.Edge{F: simple.Node(u), T: simple.Node(v)}) 215 } 216 } 217 218 b.Run(test.name, func(b *testing.B) { 219 var got [][]graph.Node 220 for i := 0; i < b.N; i++ { 221 got = BronKerbosch(g) 222 } 223 if len(got) != len(test.want) { 224 b.Errorf("unexpected cliques for test %q:\ngot: %v\nwant:%v", test.name, got, test.want) 225 } 226 }) 227 } 228 }