gonum.org/v1/gonum@v0.14.0/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  	"gonum.org/v1/gonum/floats/scalar"
    11  	"gonum.org/v1/gonum/graph"
    12  	"gonum.org/v1/gonum/graph/internal/ordered"
    13  	"gonum.org/v1/gonum/graph/iterator"
    14  	"gonum.org/v1/gonum/graph/simple"
    15  	"gonum.org/v1/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  }