github.com/gopherd/gonum@v0.0.4/graph/flow/control_flow_test.go (about) 1 // Copyright ©2017 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 flow 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 dominatorsTests = []struct { 17 n graph.Node 18 edges []simple.Edge 19 20 want DominatorTree 21 }{ 22 { // Example from Lengauer and Tarjan http://www.dtic.mil/dtic/tr/fulltext/u2/a054144.pdf fig 1. 23 n: char('R'), 24 edges: []simple.Edge{ 25 {F: char('A'), T: char('D')}, 26 {F: char('B'), T: char('A')}, 27 {F: char('B'), T: char('D')}, 28 {F: char('B'), T: char('E')}, 29 {F: char('C'), T: char('F')}, 30 {F: char('C'), T: char('G')}, 31 {F: char('D'), T: char('L')}, 32 {F: char('E'), T: char('H')}, 33 {F: char('F'), T: char('I')}, 34 {F: char('G'), T: char('I')}, 35 {F: char('G'), T: char('J')}, 36 {F: char('H'), T: char('E')}, 37 {F: char('H'), T: char('K')}, 38 {F: char('I'), T: char('K')}, 39 {F: char('J'), T: char('I')}, 40 {F: char('K'), T: char('I')}, 41 {F: char('K'), T: char('R')}, 42 {F: char('L'), T: char('H')}, 43 {F: char('R'), T: char('A')}, 44 {F: char('R'), T: char('B')}, 45 {F: char('R'), T: char('C')}, 46 }, 47 48 want: DominatorTree{ 49 root: char('R'), 50 dominatorOf: map[int64]graph.Node{ 51 'A': char('R'), 52 'B': char('R'), 53 'C': char('R'), 54 'D': char('R'), 55 'E': char('R'), 56 'F': char('C'), 57 'G': char('C'), 58 'H': char('R'), 59 'I': char('R'), 60 'J': char('G'), 61 'K': char('R'), 62 'L': char('D'), 63 }, 64 dominatedBy: map[int64][]graph.Node{ 65 'C': {char('F'), char('G')}, 66 'D': {char('L')}, 67 'G': {char('J')}, 68 'R': {char('A'), char('B'), char('C'), char('D'), char('E'), char('H'), char('I'), char('K')}, 69 }, 70 }, 71 }, 72 { // WP example: https://en.wikipedia.org/w/index.php?title=Dominator_(graph_theory)&oldid=758099236. 73 n: simple.Node(1), 74 edges: []simple.Edge{ 75 {F: simple.Node(1), T: simple.Node(2)}, 76 {F: simple.Node(2), T: simple.Node(3)}, 77 {F: simple.Node(2), T: simple.Node(4)}, 78 {F: simple.Node(2), T: simple.Node(6)}, 79 {F: simple.Node(3), T: simple.Node(5)}, 80 {F: simple.Node(4), T: simple.Node(5)}, 81 {F: simple.Node(5), T: simple.Node(2)}, 82 }, 83 84 want: DominatorTree{ 85 root: simple.Node(1), 86 dominatorOf: map[int64]graph.Node{ 87 2: simple.Node(1), 88 3: simple.Node(2), 89 4: simple.Node(2), 90 5: simple.Node(2), 91 6: simple.Node(2), 92 }, 93 dominatedBy: map[int64][]graph.Node{ 94 1: {simple.Node(2)}, 95 2: {simple.Node(3), simple.Node(4), simple.Node(5), simple.Node(6)}, 96 }, 97 }, 98 }, 99 { // WP example with node IDs decremented by 1. 100 n: simple.Node(0), 101 edges: []simple.Edge{ 102 {F: simple.Node(0), T: simple.Node(1)}, 103 {F: simple.Node(1), T: simple.Node(2)}, 104 {F: simple.Node(1), T: simple.Node(3)}, 105 {F: simple.Node(1), T: simple.Node(5)}, 106 {F: simple.Node(2), T: simple.Node(4)}, 107 {F: simple.Node(3), T: simple.Node(4)}, 108 {F: simple.Node(4), T: simple.Node(1)}, 109 }, 110 111 want: DominatorTree{ 112 root: simple.Node(0), 113 dominatorOf: map[int64]graph.Node{ 114 1: simple.Node(0), 115 2: simple.Node(1), 116 3: simple.Node(1), 117 4: simple.Node(1), 118 5: simple.Node(1), 119 }, 120 dominatedBy: map[int64][]graph.Node{ 121 0: {simple.Node(1)}, 122 1: {simple.Node(2), simple.Node(3), simple.Node(4), simple.Node(5)}, 123 }, 124 }, 125 }, 126 } 127 128 type char rune 129 130 func (n char) ID() int64 { return int64(n) } 131 func (n char) String() string { return string(n) } 132 133 func TestDominators(t *testing.T) { 134 // The dominator functions are non-deterministic due 135 // to map iteration ordering, so repeat the tests to 136 // ensure consistent coverage. The value of 100 was 137 // chosen empirically to have no observed reduction 138 // in coverage in several hundred runs of go test -cover. 139 for i := 0; i < 100; i++ { 140 for _, test := range dominatorsTests { 141 g := simple.NewDirectedGraph() 142 for _, e := range test.edges { 143 g.SetEdge(e) 144 } 145 146 for _, alg := range []struct { 147 name string 148 fn func(graph.Node, graph.Directed) DominatorTree 149 }{ 150 {"Dominators", Dominators}, 151 {"DominatorsSLT", DominatorsSLT}, 152 } { 153 got := alg.fn(test.n, g) 154 155 if !reflect.DeepEqual(got.Root(), test.want.root) { 156 t.Errorf("unexpected dominator tree root from %s: got:%v want:%v", 157 alg.name, got.root, test.want.root) 158 } 159 160 if !reflect.DeepEqual(got.dominatorOf, test.want.dominatorOf) { 161 t.Errorf("unexpected dominator tree from %s: got:%v want:%v", 162 alg.name, got.dominatorOf, test.want.dominatorOf) 163 } 164 165 for q, want := range test.want.dominatorOf { 166 node := got.DominatorOf(q) 167 if node != want { 168 t.Errorf("unexpected dominator tree result from %s dominated of %v: got:%v want:%v", 169 alg.name, q, node, want) 170 } 171 } 172 173 for _, nodes := range got.dominatedBy { 174 ordered.ByID(nodes) 175 } 176 177 if !reflect.DeepEqual(got.dominatedBy, test.want.dominatedBy) { 178 t.Errorf("unexpected dominator tree from %s: got:%v want:%v", 179 alg.name, got.dominatedBy, test.want.dominatedBy) 180 } 181 182 for q, want := range test.want.dominatedBy { 183 nodes := got.DominatedBy(q) 184 if !reflect.DeepEqual(nodes, want) { 185 t.Errorf("unexpected dominator tree result from %s dominated by %v: got:%v want:%v", 186 alg.name, q, nodes, want) 187 } 188 } 189 } 190 } 191 } 192 }