github.com/jingcheng-WU/gonum@v0.9.1-0.20210323123734-f1a2a11a8f7b/graph/layout/eades_test.go (about)

     1  // Copyright ©2019 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 layout_test
     6  
     7  import (
     8  	"path/filepath"
     9  	"testing"
    10  
    11  	"golang.org/x/exp/rand"
    12  
    13  	"github.com/jingcheng-WU/gonum/graph"
    14  	"github.com/jingcheng-WU/gonum/graph/simple"
    15  	"github.com/jingcheng-WU/gonum/spatial/r2"
    16  	"gonum.org/v1/plot"
    17  	"gonum.org/v1/plot/vg"
    18  
    19  	. "github.com/jingcheng-WU/gonum/graph/layout"
    20  )
    21  
    22  var eadesR2Tests = []struct {
    23  	name      string
    24  	g         graph.Graph
    25  	param     EadesR2
    26  	wantIters int
    27  }{
    28  	{
    29  		name: "line",
    30  		g: func() graph.Graph {
    31  			edges := []simple.Edge{
    32  				{F: simple.Node(0), T: simple.Node(1)},
    33  			}
    34  			g := simple.NewUndirectedGraph()
    35  			for _, e := range edges {
    36  				g.SetEdge(e)
    37  			}
    38  			return orderedGraph{g}
    39  		}(),
    40  		param:     EadesR2{Repulsion: 1, Rate: 0.1, Updates: 100, Theta: 0.1, Src: rand.NewSource(1)},
    41  		wantIters: 100,
    42  	},
    43  	{
    44  		name: "square",
    45  		g: func() graph.Graph {
    46  			edges := []simple.Edge{
    47  				{F: simple.Node(0), T: simple.Node(1)},
    48  				{F: simple.Node(0), T: simple.Node(2)},
    49  				{F: simple.Node(1), T: simple.Node(3)},
    50  				{F: simple.Node(2), T: simple.Node(3)},
    51  			}
    52  			g := simple.NewUndirectedGraph()
    53  			for _, e := range edges {
    54  				g.SetEdge(e)
    55  			}
    56  			return orderedGraph{g}
    57  		}(),
    58  		param:     EadesR2{Repulsion: 1, Rate: 0.1, Updates: 100, Theta: 0.1, Src: rand.NewSource(1)},
    59  		wantIters: 100,
    60  	},
    61  	{
    62  		name: "tetrahedron",
    63  		g: func() graph.Graph {
    64  			edges := []simple.Edge{
    65  				{F: simple.Node(0), T: simple.Node(1)},
    66  				{F: simple.Node(0), T: simple.Node(2)},
    67  				{F: simple.Node(0), T: simple.Node(3)},
    68  				{F: simple.Node(1), T: simple.Node(2)},
    69  				{F: simple.Node(1), T: simple.Node(3)},
    70  				{F: simple.Node(2), T: simple.Node(3)},
    71  			}
    72  			g := simple.NewUndirectedGraph()
    73  			for _, e := range edges {
    74  				g.SetEdge(e)
    75  			}
    76  			return orderedGraph{g}
    77  		}(),
    78  		param:     EadesR2{Repulsion: 1, Rate: 0.1, Updates: 100, Theta: 0.1, Src: rand.NewSource(1)},
    79  		wantIters: 100,
    80  	},
    81  	{
    82  		name: "sheet",
    83  		g: func() graph.Graph {
    84  			edges := []simple.Edge{
    85  				{F: simple.Node(0), T: simple.Node(1)},
    86  				{F: simple.Node(0), T: simple.Node(3)},
    87  				{F: simple.Node(1), T: simple.Node(2)},
    88  				{F: simple.Node(1), T: simple.Node(4)},
    89  				{F: simple.Node(2), T: simple.Node(5)},
    90  				{F: simple.Node(3), T: simple.Node(4)},
    91  				{F: simple.Node(3), T: simple.Node(6)},
    92  				{F: simple.Node(4), T: simple.Node(5)},
    93  				{F: simple.Node(4), T: simple.Node(7)},
    94  				{F: simple.Node(5), T: simple.Node(8)},
    95  				{F: simple.Node(6), T: simple.Node(7)},
    96  				{F: simple.Node(7), T: simple.Node(8)},
    97  			}
    98  			g := simple.NewUndirectedGraph()
    99  			for _, e := range edges {
   100  				g.SetEdge(e)
   101  			}
   102  			return orderedGraph{g}
   103  		}(),
   104  		param:     EadesR2{Repulsion: 1, Rate: 0.1, Updates: 100, Theta: 0.1, Src: rand.NewSource(1)},
   105  		wantIters: 100,
   106  	},
   107  	{
   108  		name: "tube",
   109  		g: func() graph.Graph {
   110  			edges := []simple.Edge{
   111  				{F: simple.Node(0), T: simple.Node(1)},
   112  				{F: simple.Node(0), T: simple.Node(2)},
   113  				{F: simple.Node(0), T: simple.Node(3)},
   114  				{F: simple.Node(1), T: simple.Node(2)},
   115  				{F: simple.Node(1), T: simple.Node(4)},
   116  				{F: simple.Node(2), T: simple.Node(5)},
   117  				{F: simple.Node(3), T: simple.Node(4)},
   118  				{F: simple.Node(3), T: simple.Node(5)},
   119  				{F: simple.Node(3), T: simple.Node(6)},
   120  				{F: simple.Node(4), T: simple.Node(5)},
   121  				{F: simple.Node(4), T: simple.Node(7)},
   122  				{F: simple.Node(5), T: simple.Node(8)},
   123  				{F: simple.Node(6), T: simple.Node(7)},
   124  				{F: simple.Node(6), T: simple.Node(8)},
   125  				{F: simple.Node(7), T: simple.Node(8)},
   126  			}
   127  			g := simple.NewUndirectedGraph()
   128  			for _, e := range edges {
   129  				g.SetEdge(e)
   130  			}
   131  			return orderedGraph{g}
   132  		}(),
   133  		param:     EadesR2{Repulsion: 1, Rate: 0.1, Updates: 100, Theta: 0.1, Src: rand.NewSource(1)},
   134  		wantIters: 100,
   135  	},
   136  	{
   137  		// This test does not produce a good layout, but is here to
   138  		// ensure that Update does not panic with steep decent rates.
   139  		name: "tube-steep",
   140  		g: func() graph.Graph {
   141  			edges := []simple.Edge{
   142  				{F: simple.Node(0), T: simple.Node(1)},
   143  				{F: simple.Node(0), T: simple.Node(2)},
   144  				{F: simple.Node(0), T: simple.Node(3)},
   145  				{F: simple.Node(1), T: simple.Node(2)},
   146  				{F: simple.Node(1), T: simple.Node(4)},
   147  				{F: simple.Node(2), T: simple.Node(5)},
   148  				{F: simple.Node(3), T: simple.Node(4)},
   149  				{F: simple.Node(3), T: simple.Node(5)},
   150  				{F: simple.Node(3), T: simple.Node(6)},
   151  				{F: simple.Node(4), T: simple.Node(5)},
   152  				{F: simple.Node(4), T: simple.Node(7)},
   153  				{F: simple.Node(5), T: simple.Node(8)},
   154  				{F: simple.Node(6), T: simple.Node(7)},
   155  				{F: simple.Node(6), T: simple.Node(8)},
   156  				{F: simple.Node(7), T: simple.Node(8)},
   157  			}
   158  			g := simple.NewUndirectedGraph()
   159  			for _, e := range edges {
   160  				g.SetEdge(e)
   161  			}
   162  			return orderedGraph{g}
   163  		}(),
   164  		param:     EadesR2{Repulsion: 1, Rate: 1, Updates: 100, Theta: 0.1, Src: rand.NewSource(1)},
   165  		wantIters: 99,
   166  	},
   167  
   168  	{
   169  		name: "wp_page", // https://en.wikipedia.org/wiki/PageRank#/media/File:PageRanks-Example.jpg
   170  		g: func() graph.Graph {
   171  			edges := []simple.Edge{
   172  				{F: simple.Node(0), T: simple.Node(3)},
   173  				{F: simple.Node(1), T: simple.Node(2)},
   174  				{F: simple.Node(1), T: simple.Node(3)},
   175  				{F: simple.Node(1), T: simple.Node(4)},
   176  				{F: simple.Node(1), T: simple.Node(5)},
   177  				{F: simple.Node(1), T: simple.Node(6)},
   178  				{F: simple.Node(1), T: simple.Node(7)},
   179  				{F: simple.Node(1), T: simple.Node(8)},
   180  				{F: simple.Node(3), T: simple.Node(4)},
   181  				{F: simple.Node(4), T: simple.Node(5)},
   182  				{F: simple.Node(4), T: simple.Node(6)},
   183  				{F: simple.Node(4), T: simple.Node(7)},
   184  				{F: simple.Node(4), T: simple.Node(8)},
   185  				{F: simple.Node(4), T: simple.Node(9)},
   186  				{F: simple.Node(4), T: simple.Node(10)},
   187  			}
   188  			g := simple.NewUndirectedGraph()
   189  			for _, e := range edges {
   190  				g.SetEdge(e)
   191  			}
   192  			return orderedGraph{g}
   193  		}(),
   194  		param:     EadesR2{Repulsion: 1, Rate: 0.1, Updates: 100, Theta: 0.1, Src: rand.NewSource(1)},
   195  		wantIters: 100,
   196  	},
   197  }
   198  
   199  func TestEadesR2(t *testing.T) {
   200  	for _, test := range eadesR2Tests {
   201  		eades := test.param
   202  		o := NewOptimizerR2(test.g, eades.Update)
   203  		var n int
   204  		for o.Update() {
   205  			n++
   206  		}
   207  		if n != test.wantIters {
   208  			t.Errorf("unexpected number of iterations for %q: got:%d want:%d", test.name, n, test.wantIters)
   209  		}
   210  
   211  		p := plot.New()
   212  		p.Add(render{o})
   213  		p.HideAxes()
   214  		path := filepath.Join("testdata", test.name+".png")
   215  		err := p.Save(10*vg.Centimeter, 10*vg.Centimeter, path)
   216  		if err != nil {
   217  			t.Errorf("unexpected error: %v", err)
   218  			continue
   219  		}
   220  		ok := checkRenderedLayout(t, path)
   221  		if !ok {
   222  			got := make(map[int64]r2.Vec)
   223  			nodes := test.g.Nodes()
   224  			for nodes.Next() {
   225  				id := nodes.Node().ID()
   226  				got[id] = o.Coord2(id)
   227  			}
   228  			t.Logf("got node positions: %#v", got)
   229  		}
   230  	}
   231  }