gonum.org/v1/gonum@v0.14.0/graph/graph_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 graph_test
     6  
     7  import (
     8  	"testing"
     9  
    10  	"gonum.org/v1/gonum/graph"
    11  	"gonum.org/v1/gonum/graph/internal/ordered"
    12  	"gonum.org/v1/gonum/graph/simple"
    13  )
    14  
    15  type graphBuilder interface {
    16  	graph.Graph
    17  	graph.Builder
    18  }
    19  
    20  func TestCopy(t *testing.T) {
    21  	copyTests := []struct {
    22  		desc string
    23  
    24  		src graph.Graph
    25  		dst graphBuilder
    26  
    27  		// If want is nil, compare to src.
    28  		want graph.Graph
    29  	}{
    30  		{
    31  			desc: "undirected to undirected",
    32  			src: func() graph.Graph {
    33  				g := simple.NewUndirectedGraph()
    34  				g.AddNode(simple.Node(-1))
    35  				for _, e := range []simple.Edge{
    36  					{F: simple.Node(0), T: simple.Node(1)},
    37  					{F: simple.Node(0), T: simple.Node(3)},
    38  					{F: simple.Node(1), T: simple.Node(2)},
    39  				} {
    40  					g.SetEdge(e)
    41  				}
    42  				return g
    43  			}(),
    44  			dst: simple.NewUndirectedGraph(),
    45  		},
    46  		{
    47  			desc: "undirected to directed",
    48  			src: func() graph.Graph {
    49  				g := simple.NewUndirectedGraph()
    50  				g.AddNode(simple.Node(-1))
    51  				for _, e := range []simple.Edge{
    52  					{F: simple.Node(0), T: simple.Node(1)},
    53  					{F: simple.Node(0), T: simple.Node(3)},
    54  					{F: simple.Node(1), T: simple.Node(2)},
    55  				} {
    56  					g.SetEdge(e)
    57  				}
    58  				return g
    59  			}(),
    60  			dst: simple.NewDirectedGraph(),
    61  
    62  			want: func() graph.Graph {
    63  				g := simple.NewDirectedGraph()
    64  				g.AddNode(simple.Node(-1))
    65  				for _, e := range []simple.Edge{
    66  					{F: simple.Node(0), T: simple.Node(1)},
    67  					{F: simple.Node(0), T: simple.Node(3)},
    68  					{F: simple.Node(1), T: simple.Node(2)},
    69  				} {
    70  					// want is a directed graph copied from
    71  					// an undirected graph so we need to have
    72  					// all edges in both directions.
    73  					g.SetEdge(e)
    74  					e.T, e.F = e.F, e.T
    75  					g.SetEdge(e)
    76  				}
    77  				return g
    78  			}(),
    79  		},
    80  		{
    81  			desc: "directed to undirected",
    82  			src: func() graph.Graph {
    83  				g := simple.NewDirectedGraph()
    84  				g.AddNode(simple.Node(-1))
    85  				for _, e := range []simple.Edge{
    86  					{F: simple.Node(0), T: simple.Node(1)},
    87  					{F: simple.Node(0), T: simple.Node(3)},
    88  					{F: simple.Node(1), T: simple.Node(2)},
    89  				} {
    90  					g.SetEdge(e)
    91  				}
    92  				return g
    93  			}(),
    94  			dst: simple.NewUndirectedGraph(),
    95  
    96  			want: func() graph.Graph {
    97  				g := simple.NewUndirectedGraph()
    98  				g.AddNode(simple.Node(-1))
    99  				for _, e := range []simple.Edge{
   100  					{F: simple.Node(0), T: simple.Node(1)},
   101  					{F: simple.Node(0), T: simple.Node(3)},
   102  					{F: simple.Node(1), T: simple.Node(2)},
   103  				} {
   104  					g.SetEdge(e)
   105  				}
   106  				return g
   107  			}(),
   108  		},
   109  		{
   110  			desc: "directed to directed",
   111  			src: func() graph.Graph {
   112  				g := simple.NewDirectedGraph()
   113  				g.AddNode(simple.Node(-1))
   114  				for _, e := range []simple.Edge{
   115  					{F: simple.Node(0), T: simple.Node(1)},
   116  					{F: simple.Node(0), T: simple.Node(3)},
   117  					{F: simple.Node(1), T: simple.Node(2)},
   118  				} {
   119  					g.SetEdge(e)
   120  				}
   121  				return g
   122  			}(),
   123  			dst: simple.NewDirectedGraph(),
   124  		},
   125  	}
   126  
   127  	for _, test := range copyTests {
   128  		graph.Copy(test.dst, test.src)
   129  		want := test.want
   130  		if want == nil {
   131  			want = test.src
   132  		}
   133  		if !same(test.dst, want) {
   134  			t.Errorf("unexpected copy result for %s", test.desc)
   135  		}
   136  	}
   137  }
   138  
   139  type graphWeightedBuilder interface {
   140  	graph.Graph
   141  	graph.WeightedBuilder
   142  }
   143  
   144  func TestCopyWeighted(t *testing.T) {
   145  	copyWeightedTests := []struct {
   146  		desc string
   147  
   148  		src graph.Weighted
   149  		dst graphWeightedBuilder
   150  
   151  		// If want is nil, compare to src.
   152  		want graph.Graph
   153  	}{
   154  		{
   155  			desc: "undirected to undirected",
   156  			src: func() graph.Weighted {
   157  				g := simple.NewWeightedUndirectedGraph(0, 0)
   158  				g.AddNode(simple.Node(-1))
   159  				for _, e := range []simple.WeightedEdge{
   160  					{F: simple.Node(0), T: simple.Node(1), W: 1},
   161  					{F: simple.Node(0), T: simple.Node(3), W: 1},
   162  					{F: simple.Node(1), T: simple.Node(2), W: 1},
   163  				} {
   164  					g.SetWeightedEdge(e)
   165  				}
   166  				return g
   167  			}(),
   168  			dst: simple.NewWeightedUndirectedGraph(0, 0),
   169  		},
   170  		{
   171  			desc: "undirected to directed",
   172  			src: func() graph.Weighted {
   173  				g := simple.NewWeightedUndirectedGraph(0, 0)
   174  				g.AddNode(simple.Node(-1))
   175  				for _, e := range []simple.WeightedEdge{
   176  					{F: simple.Node(0), T: simple.Node(1), W: 1},
   177  					{F: simple.Node(0), T: simple.Node(3), W: 1},
   178  					{F: simple.Node(1), T: simple.Node(2), W: 1},
   179  				} {
   180  					g.SetWeightedEdge(e)
   181  				}
   182  				return g
   183  			}(),
   184  			dst: simple.NewWeightedDirectedGraph(0, 0),
   185  
   186  			want: func() graph.Graph {
   187  				g := simple.NewWeightedDirectedGraph(0, 0)
   188  				g.AddNode(simple.Node(-1))
   189  				for _, e := range []simple.WeightedEdge{
   190  					{F: simple.Node(0), T: simple.Node(1), W: 1},
   191  					{F: simple.Node(0), T: simple.Node(3), W: 1},
   192  					{F: simple.Node(1), T: simple.Node(2), W: 1},
   193  				} {
   194  					// want is a directed graph copied from
   195  					// an undirected graph so we need to have
   196  					// all edges in both directions.
   197  					g.SetWeightedEdge(e)
   198  					e.T, e.F = e.F, e.T
   199  					g.SetWeightedEdge(e)
   200  				}
   201  				return g
   202  			}(),
   203  		},
   204  		{
   205  			desc: "directed to undirected",
   206  			src: func() graph.Weighted {
   207  				g := simple.NewWeightedDirectedGraph(0, 0)
   208  				g.AddNode(simple.Node(-1))
   209  				for _, e := range []simple.WeightedEdge{
   210  					{F: simple.Node(0), T: simple.Node(1), W: 1},
   211  					{F: simple.Node(0), T: simple.Node(3), W: 1},
   212  					{F: simple.Node(1), T: simple.Node(2), W: 1},
   213  				} {
   214  					g.SetWeightedEdge(e)
   215  				}
   216  				return g
   217  			}(),
   218  			dst: simple.NewWeightedUndirectedGraph(0, 0),
   219  
   220  			want: func() graph.Weighted {
   221  				g := simple.NewWeightedUndirectedGraph(0, 0)
   222  				g.AddNode(simple.Node(-1))
   223  				for _, e := range []simple.WeightedEdge{
   224  					{F: simple.Node(0), T: simple.Node(1), W: 1},
   225  					{F: simple.Node(0), T: simple.Node(3), W: 1},
   226  					{F: simple.Node(1), T: simple.Node(2), W: 1},
   227  				} {
   228  					g.SetWeightedEdge(e)
   229  				}
   230  				return g
   231  			}(),
   232  		},
   233  		{
   234  			desc: "directed to directed",
   235  			src: func() graph.Weighted {
   236  				g := simple.NewWeightedDirectedGraph(0, 0)
   237  				g.AddNode(simple.Node(-1))
   238  				for _, e := range []simple.WeightedEdge{
   239  					{F: simple.Node(0), T: simple.Node(1), W: 1},
   240  					{F: simple.Node(0), T: simple.Node(3), W: 1},
   241  					{F: simple.Node(1), T: simple.Node(2), W: 1},
   242  				} {
   243  					g.SetWeightedEdge(e)
   244  				}
   245  				return g
   246  			}(),
   247  			dst: simple.NewWeightedDirectedGraph(0, 0),
   248  		},
   249  	}
   250  
   251  	for _, test := range copyWeightedTests {
   252  		graph.CopyWeighted(test.dst, test.src)
   253  		want := test.want
   254  		if want == nil {
   255  			want = test.src
   256  		}
   257  		if !same(test.dst, want) {
   258  			t.Errorf("unexpected copy result for %s", test.desc)
   259  		}
   260  	}
   261  }
   262  
   263  func same(a, b graph.Graph) bool {
   264  	aNodes := graph.NodesOf(a.Nodes())
   265  	bNodes := graph.NodesOf(b.Nodes())
   266  	ordered.ByID(aNodes)
   267  	ordered.ByID(bNodes)
   268  	for i, na := range aNodes {
   269  		nb := bNodes[i]
   270  		if na != nb {
   271  			return false
   272  		}
   273  	}
   274  	for _, u := range graph.NodesOf(a.Nodes()) {
   275  		aFromU := graph.NodesOf(a.From(u.ID()))
   276  		bFromU := graph.NodesOf(b.From(u.ID()))
   277  		if len(aFromU) != len(bFromU) {
   278  			return false
   279  		}
   280  		ordered.ByID(aFromU)
   281  		ordered.ByID(bFromU)
   282  		for i, va := range aFromU {
   283  			vb := bFromU[i]
   284  			if va != vb {
   285  				return false
   286  			}
   287  			aW, aWok := a.(graph.Weighted)
   288  			bW, bWok := b.(graph.Weighted)
   289  			if aWok && bWok {
   290  				if aW.WeightedEdge(u.ID(), va.ID()).Weight() != bW.WeightedEdge(u.ID(), vb.ID()).Weight() {
   291  					return false
   292  				}
   293  			}
   294  		}
   295  	}
   296  	type edger interface {
   297  		Edges() graph.Edges
   298  	}
   299  	type weightedEdger interface {
   300  		WeightedEdges() graph.WeightedEdges
   301  	}
   302  	var sizeA, sizeB int
   303  	switch a := a.(type) {
   304  	case edger:
   305  		sizeA = len(graph.EdgesOf(a.Edges()))
   306  	case weightedEdger:
   307  		sizeA = len(graph.WeightedEdgesOf(a.WeightedEdges()))
   308  	}
   309  	switch b := b.(type) {
   310  	case edger:
   311  		sizeB = len(graph.EdgesOf(b.Edges()))
   312  	case weightedEdger:
   313  		sizeB = len(graph.WeightedEdgesOf(b.WeightedEdges()))
   314  	}
   315  	return sizeA == sizeB
   316  }