github.com/jingcheng-WU/gonum@v0.9.1-0.20210323123734-f1a2a11a8f7b/graph/topo/tarjan_test.go (about) 1 // Copyright ©2014 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 "sort" 10 "testing" 11 12 "github.com/jingcheng-WU/gonum/graph" 13 "github.com/jingcheng-WU/gonum/graph/internal/ordered" 14 "github.com/jingcheng-WU/gonum/graph/simple" 15 ) 16 17 type interval struct{ start, end int } 18 19 var tarjanTests = []struct { 20 g []intset 21 22 ambiguousOrder []interval 23 want [][]int64 24 25 sortedLength int 26 unorderableLength int 27 sortable bool 28 }{ 29 { 30 g: []intset{ 31 0: linksTo(1), 32 1: linksTo(2, 7), 33 2: linksTo(3, 6), 34 3: linksTo(4), 35 4: linksTo(2, 5), 36 6: linksTo(3, 5), 37 7: linksTo(0, 6), 38 }, 39 40 want: [][]int64{ 41 {5}, 42 {2, 3, 4, 6}, 43 {0, 1, 7}, 44 }, 45 46 sortedLength: 1, 47 unorderableLength: 2, 48 sortable: false, 49 }, 50 { 51 g: []intset{ 52 0: linksTo(1, 2, 3), 53 1: linksTo(2), 54 2: linksTo(3), 55 3: linksTo(1), 56 }, 57 58 want: [][]int64{ 59 {1, 2, 3}, 60 {0}, 61 }, 62 63 sortedLength: 1, 64 unorderableLength: 1, 65 sortable: false, 66 }, 67 { 68 g: []intset{ 69 0: linksTo(1), 70 1: linksTo(0, 2), 71 2: linksTo(1), 72 }, 73 74 want: [][]int64{ 75 {0, 1, 2}, 76 }, 77 78 sortedLength: 0, 79 unorderableLength: 1, 80 sortable: false, 81 }, 82 { 83 g: []intset{ 84 0: linksTo(1), 85 1: linksTo(2, 3), 86 2: linksTo(4, 5), 87 3: linksTo(4, 5), 88 4: linksTo(6), 89 5: nil, 90 6: nil, 91 }, 92 93 // Node pairs (2, 3) and (4, 5) are not 94 // relatively orderable within each pair. 95 ambiguousOrder: []interval{ 96 {0, 3}, // This includes node 6 since it only needs to be before 4 in topo sort. 97 {3, 5}, 98 }, 99 want: [][]int64{ 100 {6}, {5}, {4}, {3}, {2}, {1}, {0}, 101 }, 102 103 sortedLength: 7, 104 sortable: true, 105 }, 106 { 107 g: []intset{ 108 0: linksTo(1), 109 1: linksTo(2, 3, 4), 110 2: linksTo(0, 3), 111 3: linksTo(4), 112 4: linksTo(3), 113 }, 114 115 // SCCs are not relatively ordable. 116 ambiguousOrder: []interval{ 117 {0, 2}, 118 }, 119 want: [][]int64{ 120 {0, 1, 2}, 121 {3, 4}, 122 }, 123 124 sortedLength: 0, 125 unorderableLength: 2, 126 sortable: false, 127 }, 128 } 129 130 func TestSort(t *testing.T) { 131 for i, test := range tarjanTests { 132 g := simple.NewDirectedGraph() 133 for u, e := range test.g { 134 // Add nodes that are not defined by an edge. 135 if g.Node(int64(u)) == nil { 136 g.AddNode(simple.Node(u)) 137 } 138 for v := range e { 139 g.SetEdge(simple.Edge{F: simple.Node(u), T: simple.Node(v)}) 140 } 141 } 142 sorted, err := Sort(g) 143 var gotSortedLen int 144 for _, n := range sorted { 145 if n != nil { 146 gotSortedLen++ 147 } 148 } 149 if gotSortedLen != test.sortedLength { 150 t.Errorf("unexpected number of sortable nodes for test %d: got:%d want:%d", i, gotSortedLen, test.sortedLength) 151 } 152 if err == nil != test.sortable { 153 t.Errorf("unexpected sortability for test %d: got error: %v want: nil-error=%t", i, err, test.sortable) 154 } 155 if err != nil && len(err.(Unorderable)) != test.unorderableLength { 156 t.Errorf("unexpected number of unorderable nodes for test %d: got:%d want:%d", i, len(err.(Unorderable)), test.unorderableLength) 157 } 158 } 159 } 160 161 func TestTarjanSCC(t *testing.T) { 162 for i, test := range tarjanTests { 163 g := simple.NewDirectedGraph() 164 for u, e := range test.g { 165 // Add nodes that are not defined by an edge. 166 if g.Node(int64(u)) == nil { 167 g.AddNode(simple.Node(u)) 168 } 169 for v := range e { 170 g.SetEdge(simple.Edge{F: simple.Node(u), T: simple.Node(v)}) 171 } 172 } 173 gotSCCs := TarjanSCC(g) 174 // tarjan.strongconnect does range iteration over maps, 175 // so sort SCC members to ensure consistent ordering. 176 gotIDs := make([][]int64, len(gotSCCs)) 177 for i, scc := range gotSCCs { 178 gotIDs[i] = make([]int64, len(scc)) 179 for j, id := range scc { 180 gotIDs[i][j] = id.ID() 181 } 182 sort.Sort(ordered.Int64s(gotIDs[i])) 183 } 184 for _, iv := range test.ambiguousOrder { 185 sort.Sort(ordered.BySliceValues(test.want[iv.start:iv.end])) 186 sort.Sort(ordered.BySliceValues(gotIDs[iv.start:iv.end])) 187 } 188 if !reflect.DeepEqual(gotIDs, test.want) { 189 t.Errorf("unexpected Tarjan scc result for %d:\n\tgot:%v\n\twant:%v", i, gotIDs, test.want) 190 } 191 } 192 } 193 194 var stabilizedSortTests = []struct { 195 g []intset 196 197 want []graph.Node 198 err error 199 }{ 200 { 201 g: []intset{ 202 0: linksTo(1), 203 1: linksTo(2, 7), 204 2: linksTo(3, 6), 205 3: linksTo(4), 206 4: linksTo(2, 5), 207 6: linksTo(3, 5), 208 7: linksTo(0, 6), 209 }, 210 211 want: []graph.Node{nil, nil, simple.Node(5)}, 212 err: Unorderable{ 213 {simple.Node(0), simple.Node(1), simple.Node(7)}, 214 {simple.Node(2), simple.Node(3), simple.Node(4), simple.Node(6)}, 215 }, 216 }, 217 { 218 g: []intset{ 219 0: linksTo(1, 2, 3), 220 1: linksTo(2), 221 2: linksTo(3), 222 3: linksTo(1), 223 }, 224 225 want: []graph.Node{simple.Node(0), nil}, 226 err: Unorderable{ 227 {simple.Node(1), simple.Node(2), simple.Node(3)}, 228 }, 229 }, 230 { 231 g: []intset{ 232 0: linksTo(1), 233 1: linksTo(0, 2), 234 2: linksTo(1), 235 }, 236 237 want: []graph.Node{nil}, 238 err: Unorderable{ 239 {simple.Node(0), simple.Node(1), simple.Node(2)}, 240 }, 241 }, 242 { 243 g: []intset{ 244 0: linksTo(1), 245 1: linksTo(2, 3), 246 2: linksTo(4, 5), 247 3: linksTo(4, 5), 248 4: linksTo(6), 249 5: nil, 250 6: nil, 251 }, 252 253 want: []graph.Node{simple.Node(0), simple.Node(1), simple.Node(2), simple.Node(3), simple.Node(4), simple.Node(5), simple.Node(6)}, 254 err: nil, 255 }, 256 { 257 g: []intset{ 258 0: linksTo(1), 259 1: linksTo(2, 3, 4), 260 2: linksTo(0, 3), 261 3: linksTo(4), 262 4: linksTo(3), 263 }, 264 265 want: []graph.Node{nil, nil}, 266 err: Unorderable{ 267 {simple.Node(0), simple.Node(1), simple.Node(2)}, 268 {simple.Node(3), simple.Node(4)}, 269 }, 270 }, 271 { 272 g: []intset{ 273 0: linksTo(1, 2, 3, 4, 5, 6), 274 1: linksTo(7), 275 2: linksTo(7), 276 3: linksTo(7), 277 4: linksTo(7), 278 5: linksTo(7), 279 6: linksTo(7), 280 7: nil, 281 }, 282 283 want: []graph.Node{simple.Node(0), simple.Node(1), simple.Node(2), simple.Node(3), simple.Node(4), simple.Node(5), simple.Node(6), simple.Node(7)}, 284 err: nil, 285 }, 286 } 287 288 func TestSortStabilized(t *testing.T) { 289 for i, test := range stabilizedSortTests { 290 g := simple.NewDirectedGraph() 291 for u, e := range test.g { 292 // Add nodes that are not defined by an edge. 293 if g.Node(int64(u)) == nil { 294 g.AddNode(simple.Node(u)) 295 } 296 for v := range e { 297 g.SetEdge(simple.Edge{F: simple.Node(u), T: simple.Node(v)}) 298 } 299 } 300 got, err := SortStabilized(g, nil) 301 if !reflect.DeepEqual(got, test.want) { 302 t.Errorf("unexpected sort result for test %d: got:%d want:%d", i, got, test.want) 303 } 304 if !reflect.DeepEqual(err, test.err) { 305 t.Errorf("unexpected sort error for test %d: got:%v want:%v", i, err, test.want) 306 } 307 } 308 }