github.com/jingcheng-WU/gonum@v0.9.1-0.20210323123734-f1a2a11a8f7b/graph/topo/paton_cycles_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  	"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  var undirectedCyclesInTests = []struct {
    18  	g    []intset
    19  	want [][][]int64
    20  }{
    21  	{
    22  		g: []intset{
    23  			0:  linksTo(1, 2),
    24  			1:  linksTo(2, 4, 5, 9),
    25  			2:  linksTo(4, 7, 9),
    26  			3:  linksTo(5),
    27  			4:  linksTo(8),
    28  			5:  linksTo(7, 8),
    29  			6:  nil,
    30  			7:  nil,
    31  			8:  nil,
    32  			9:  nil,
    33  			10: linksTo(11, 12),
    34  			11: linksTo(12),
    35  			12: nil,
    36  		},
    37  		want: [][][]int64{
    38  			{
    39  				{0, 1, 2, 0},
    40  				{1, 2, 7, 5, 1},
    41  				{1, 2, 9, 1},
    42  				{1, 4, 8, 5, 1},
    43  				{2, 4, 8, 5, 7, 2},
    44  				{10, 11, 12, 10},
    45  			},
    46  			{
    47  				{0, 1, 2, 0},
    48  				{1, 2, 4, 1},
    49  				{1, 2, 7, 5, 1},
    50  				{1, 2, 9, 1},
    51  				{1, 4, 8, 5, 1},
    52  				{10, 11, 12, 10},
    53  			},
    54  			{
    55  				{0, 1, 2, 0},
    56  				{1, 2, 4, 1},
    57  				{1, 2, 9, 1},
    58  				{1, 4, 8, 5, 1},
    59  				{2, 4, 8, 5, 7, 2},
    60  				{10, 11, 12, 10},
    61  			},
    62  			{
    63  				{0, 1, 2, 0},
    64  				{1, 2, 4, 1},
    65  				{1, 2, 7, 5, 1},
    66  				{1, 2, 9, 1},
    67  				{2, 4, 8, 5, 7, 2},
    68  				{10, 11, 12, 10},
    69  			},
    70  		},
    71  	},
    72  }
    73  
    74  func TestUndirectedCyclesIn(t *testing.T) {
    75  	for i, test := range undirectedCyclesInTests {
    76  		g := simple.NewUndirectedGraph()
    77  		g.AddNode(simple.Node(-10)) // Make sure we test graphs with sparse IDs.
    78  		for u, e := range test.g {
    79  			// Add nodes that are not defined by an edge.
    80  			if g.Node(int64(u)) == nil {
    81  				g.AddNode(simple.Node(u))
    82  			}
    83  			for v := range e {
    84  				g.SetEdge(simple.Edge{F: simple.Node(u), T: simple.Node(v)})
    85  			}
    86  		}
    87  		cycles := UndirectedCyclesIn(g)
    88  		var got [][]int64
    89  		if cycles != nil {
    90  			got = make([][]int64, len(cycles))
    91  		}
    92  		// Canonicalise the cycles.
    93  		for j, c := range cycles {
    94  			ids := make([]int64, len(c))
    95  			for k, n := range canonicalise(c[:len(c)-1]) {
    96  				ids[k] = n.ID()
    97  			}
    98  			ids[len(ids)-1] = ids[0]
    99  			got[j] = ids
   100  		}
   101  		sort.Sort(ordered.BySliceValues(got))
   102  		var matched bool
   103  		for _, want := range test.want {
   104  			if reflect.DeepEqual(got, want) {
   105  				matched = true
   106  				break
   107  			}
   108  		}
   109  		if !matched {
   110  			t.Errorf("unexpected paton result for %d:\n\tgot:%#v\n\twant from:%#v", i, got, test.want)
   111  		}
   112  	}
   113  }
   114  
   115  // canonicalise returns the cycle path c cyclicly permuted such that
   116  // the first element has the lowest ID and then conditionally
   117  // reversed so that the second element has the lowest possible
   118  // neighbouring ID.
   119  // c lists each node only onces - the final node must not be a
   120  // reiteration of the first node.
   121  func canonicalise(c []graph.Node) []graph.Node {
   122  	if len(c) < 2 {
   123  		return c
   124  	}
   125  	idx := 0
   126  	min := c[0].ID()
   127  	for i, n := range c[1:] {
   128  		if id := n.ID(); id < min {
   129  			idx = i + 1
   130  			min = id
   131  		}
   132  	}
   133  	if idx != 0 {
   134  		c = append(c[idx:], c[:idx]...)
   135  	}
   136  	if c[len(c)-1].ID() < c[1].ID() {
   137  		ordered.Reverse(c[1:])
   138  	}
   139  	return c
   140  }