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  }