gonum.org/v1/gonum@v0.14.0/graph/network/hits.go (about)

     1  // Copyright ©2015 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 network
     6  
     7  import (
     8  	"math"
     9  
    10  	"gonum.org/v1/gonum/floats"
    11  	"gonum.org/v1/gonum/graph"
    12  )
    13  
    14  // HubAuthority is a Hyperlink-Induced Topic Search hub-authority score pair.
    15  type HubAuthority struct {
    16  	Hub       float64
    17  	Authority float64
    18  }
    19  
    20  // HITS returns the Hyperlink-Induced Topic Search hub-authority scores for
    21  // nodes of the directed graph g. HITS terminates when the 2-norm of the
    22  // vector difference between iterations is below tol. The returned map is
    23  // keyed on the graph node IDs.
    24  func HITS(g graph.Directed, tol float64) map[int64]HubAuthority {
    25  	nodes := graph.NodesOf(g.Nodes())
    26  
    27  	// Make a topological copy of g with dense node IDs.
    28  	indexOf := make(map[int64]int, len(nodes))
    29  	for i, n := range nodes {
    30  		indexOf[n.ID()] = i
    31  	}
    32  	nodesLinkingTo := make([][]int, len(nodes))
    33  	nodesLinkedFrom := make([][]int, len(nodes))
    34  	for i, n := range nodes {
    35  		id := n.ID()
    36  		from := g.To(id)
    37  		for from.Next() {
    38  			u := from.Node()
    39  			nodesLinkingTo[i] = append(nodesLinkingTo[i], indexOf[u.ID()])
    40  		}
    41  		to := g.From(id)
    42  		for to.Next() {
    43  			v := to.Node()
    44  			nodesLinkedFrom[i] = append(nodesLinkedFrom[i], indexOf[v.ID()])
    45  		}
    46  	}
    47  
    48  	w := make([]float64, 4*len(nodes))
    49  	auth := w[:len(nodes)]
    50  	hub := w[len(nodes) : 2*len(nodes)]
    51  	for i := range nodes {
    52  		auth[i] = 1
    53  		hub[i] = 1
    54  	}
    55  	deltaAuth := w[2*len(nodes) : 3*len(nodes)]
    56  	deltaHub := w[3*len(nodes):]
    57  
    58  	var norm float64
    59  	for {
    60  		norm = 0
    61  		for v := range nodes {
    62  			var a float64
    63  			for _, u := range nodesLinkingTo[v] {
    64  				a += hub[u]
    65  			}
    66  			deltaAuth[v] = auth[v]
    67  			auth[v] = a
    68  			norm += a * a
    69  		}
    70  		norm = math.Sqrt(norm)
    71  
    72  		for i := range auth {
    73  			auth[i] /= norm
    74  			deltaAuth[i] -= auth[i]
    75  		}
    76  
    77  		norm = 0
    78  		for u := range nodes {
    79  			var h float64
    80  			for _, v := range nodesLinkedFrom[u] {
    81  				h += auth[v]
    82  			}
    83  			deltaHub[u] = hub[u]
    84  			hub[u] = h
    85  			norm += h * h
    86  		}
    87  		norm = math.Sqrt(norm)
    88  
    89  		for i := range hub {
    90  			hub[i] /= norm
    91  			deltaHub[i] -= hub[i]
    92  		}
    93  
    94  		if floats.Norm(deltaAuth, 2) < tol && floats.Norm(deltaHub, 2) < tol {
    95  			break
    96  		}
    97  	}
    98  
    99  	hubAuth := make(map[int64]HubAuthority, len(nodes))
   100  	for i, n := range nodes {
   101  		hubAuth[n.ID()] = HubAuthority{Hub: hub[i], Authority: auth[i]}
   102  	}
   103  
   104  	return hubAuth
   105  }