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