github.com/gopherd/gonum@v0.0.4/graph/spectral/laplacian_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 spectral 6 7 import ( 8 "testing" 9 10 "github.com/gopherd/gonum/floats/scalar" 11 "github.com/gopherd/gonum/graph" 12 "github.com/gopherd/gonum/graph/internal/ordered" 13 "github.com/gopherd/gonum/graph/iterator" 14 "github.com/gopherd/gonum/graph/simple" 15 "github.com/gopherd/gonum/mat" 16 ) 17 18 var randomWalkLaplacianTests = []struct { 19 g []set 20 damp float64 21 22 want *mat.Dense 23 }{ 24 { 25 g: []set{ 26 A: linksTo(B, C), 27 B: linksTo(C), 28 C: nil, 29 }, 30 31 want: mat.NewDense(3, 3, []float64{ 32 1, 0, 0, 33 -0.5, 1, 0, 34 -0.5, -1, 0, 35 }), 36 }, 37 { 38 g: []set{ 39 A: linksTo(B, C), 40 B: linksTo(C), 41 C: nil, 42 }, 43 damp: 0.85, 44 45 want: mat.NewDense(3, 3, []float64{ 46 0.15, 0, 0, 47 -0.075, 0.15, 0, 48 -0.075, -0.15, 0, 49 }), 50 }, 51 { 52 g: []set{ 53 A: linksTo(B), 54 B: linksTo(C), 55 C: linksTo(A), 56 }, 57 damp: 0.85, 58 59 want: mat.NewDense(3, 3, []float64{ 60 0.15, 0, -0.15, 61 -0.15, 0.15, 0, 62 0, -0.15, 0.15, 63 }), 64 }, 65 { 66 // Example graph from http://en.wikipedia.org/wiki/File:PageRanks-Example.svg 16:17, 8 July 2009 67 g: []set{ 68 A: nil, 69 B: linksTo(C), 70 C: linksTo(B), 71 D: linksTo(A, B), 72 E: linksTo(D, B, F), 73 F: linksTo(B, E), 74 G: linksTo(B, E), 75 H: linksTo(B, E), 76 I: linksTo(B, E), 77 J: linksTo(E), 78 K: linksTo(E), 79 }, 80 81 want: mat.NewDense(11, 11, []float64{ 82 0, 0, 0, -0.5, 0, 0, 0, 0, 0, 0, 0, 83 0, 1, -1, -0.5, -1. / 3., -0.5, -0.5, -0.5, -0.5, 0, 0, 84 0, -1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 85 0, 0, 0, 1, -1. / 3., 0, 0, 0, 0, 0, 0, 86 0, 0, 0, 0, 1, -0.5, -0.5, -0.5, -0.5, -1, -1, 87 0, 0, 0, 0, -1. / 3., 1, 0, 0, 0, 0, 0, 88 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 89 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 90 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 91 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 92 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 93 }), 94 }, 95 } 96 97 func TestRandomWalkLaplacian(t *testing.T) { 98 const tol = 1e-14 99 for i, test := range randomWalkLaplacianTests { 100 g := simple.NewDirectedGraph() 101 for u, e := range test.g { 102 // Add nodes that are not defined by an edge. 103 if g.Node(int64(u)) == nil { 104 g.AddNode(simple.Node(u)) 105 } 106 for v := range e { 107 g.SetEdge(simple.Edge{F: simple.Node(u), T: simple.Node(v)}) 108 } 109 } 110 l := NewRandomWalkLaplacian(g, test.damp) 111 _, c := l.Dims() 112 for j := 0; j < c; j++ { 113 if got := mat.Sum(l.Matrix.(*mat.Dense).ColView(j)); !scalar.EqualWithinAbsOrRel(got, 0, tol, tol) { 114 t.Errorf("unexpected column sum for test %d, column %d: got:%v want:0", i, j, got) 115 } 116 } 117 l = NewRandomWalkLaplacian(sortedNodeGraph{g}, test.damp) 118 if !mat.EqualApprox(l, test.want, tol) { 119 t.Errorf("unexpected result for test %d:\ngot:\n% .2v\nwant:\n% .2v", 120 i, mat.Formatted(l), mat.Formatted(test.want)) 121 } 122 } 123 } 124 125 type sortedNodeGraph struct { 126 graph.Graph 127 } 128 129 func (g sortedNodeGraph) Nodes() graph.Nodes { 130 n := graph.NodesOf(g.Graph.Nodes()) 131 ordered.ByID(n) 132 return iterator.NewOrderedNodes(n) 133 } 134 135 const ( 136 A = iota 137 B 138 C 139 D 140 E 141 F 142 G 143 H 144 I 145 J 146 K 147 L 148 M 149 N 150 O 151 P 152 Q 153 R 154 S 155 T 156 U 157 V 158 W 159 X 160 Y 161 Z 162 ) 163 164 // set is an integer set. 165 type set map[int64]struct{} 166 167 func linksTo(i ...int64) set { 168 if len(i) == 0 { 169 return nil 170 } 171 s := make(set) 172 for _, v := range i { 173 s[v] = struct{}{} 174 } 175 return s 176 }