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  }