143 lines
3.8 KiB
Go
143 lines
3.8 KiB
Go
|
// Package trustGraph is based on EigenTrust
|
||
|
// http://nlp.stanford.edu/pubs/eigentrust.pdf
|
||
|
package trustGraph
|
||
|
|
||
|
import (
|
||
|
"errors"
|
||
|
)
|
||
|
|
||
|
// Group represents a group of peers. Peers need to be given unique, int IDs.
|
||
|
// Certainty represents the threshold of RMS change at which the algorithm will
|
||
|
// escape. Max is the maximum number of loos the algorithm will perform before
|
||
|
// escaping (regardless of certainty). These default to 0.001 and 200
|
||
|
// respectivly and generally don't need to be changed.
|
||
|
type Group struct {
|
||
|
trustGrid map[int]map[int]float32
|
||
|
initialTrust map[int]float32
|
||
|
Certainty float32
|
||
|
Max int
|
||
|
Alpha float32
|
||
|
}
|
||
|
|
||
|
// NewGroup is the constructor for Group.
|
||
|
func NewGroup() Group {
|
||
|
return Group{
|
||
|
trustGrid: map[int]map[int]float32{},
|
||
|
initialTrust: map[int]float32{},
|
||
|
Certainty: 0.001,
|
||
|
Max: 200,
|
||
|
Alpha: 0.95,
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Add will add or override a trust relationship. The first arg is the peer who
|
||
|
// is extending trust, the second arg is the peer being trusted (by the peer
|
||
|
// in the first arg). The 3rd arg is the amount of trust, which must be
|
||
|
func (g Group) Add(truster, trusted int, amount float32) (err error) {
|
||
|
err = float32InRange(amount)
|
||
|
if err == nil {
|
||
|
a, ok := g.trustGrid[truster]
|
||
|
if !ok {
|
||
|
a = map[int]float32{}
|
||
|
g.trustGrid[truster] = a
|
||
|
}
|
||
|
a[trusted] = amount
|
||
|
}
|
||
|
return
|
||
|
}
|
||
|
|
||
|
// InitialTrust sets the vaulues used to seed the calculation as well as the
|
||
|
// corrective factor used by Alpha.
|
||
|
func (g Group) InitialTrust(trusted int, amount float32) (err error) {
|
||
|
err = float32InRange(amount)
|
||
|
if err == nil {
|
||
|
g.initialTrust[trusted] = amount
|
||
|
}
|
||
|
return
|
||
|
}
|
||
|
|
||
|
// float32InRange is a helper to check that a value is 0.0 <= x <= 1.0
|
||
|
func float32InRange(x float32) error {
|
||
|
if x < 0 {
|
||
|
return errors.New("Trust amount cannot be less than 0")
|
||
|
}
|
||
|
if x > 1 {
|
||
|
return errors.New("Trust amount cannot be greater than 1")
|
||
|
}
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
// Compute will approximate the trustworthyness of each peer from the
|
||
|
// information known of how much peers trust eachother.
|
||
|
// It wil loop, upto g.Max times or until the average difference between
|
||
|
// iterations is less than g.Certainty.
|
||
|
func (g Group) Compute() map[int]float32 {
|
||
|
if len(g.initialTrust) == 0 {
|
||
|
return map[int]float32{}
|
||
|
}
|
||
|
t0 := g.initialTrust //trust map for previous iteration
|
||
|
|
||
|
for i := 0; i < g.Max; i++ {
|
||
|
t1 := *g.computeIteration(&t0) // trust map for current iteration
|
||
|
d := avgD(&t0, &t1)
|
||
|
t0 = t1
|
||
|
if d < g.Certainty {
|
||
|
break
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return t0
|
||
|
}
|
||
|
|
||
|
// computeIteration is broken out of Compute to aid comprehension. It is the
|
||
|
// inner loop of Compute. It loops over every value in t (the current trust map)
|
||
|
// and looks up how much trust that peer extends to every other peer. The
|
||
|
// product of the direct trust and indirect trust
|
||
|
func (g Group) computeIteration(t0 *map[int]float32) *map[int]float32 {
|
||
|
|
||
|
t1 := map[int]float32{}
|
||
|
for truster, directTrust := range *t0 {
|
||
|
for trusted, indirectTrust := range g.trustGrid[truster] {
|
||
|
if trusted != truster {
|
||
|
t1[trusted] += directTrust * indirectTrust
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// normalize the trust values
|
||
|
// in the EigenTrust paper, this was not done every step, but I prefer to
|
||
|
// Not doing it means the diff (d) needs to be normalized in
|
||
|
// proportion to the values (because they increase with every iteration)
|
||
|
highestTrust := float32(0)
|
||
|
for _, v := range t1 {
|
||
|
if v > highestTrust {
|
||
|
highestTrust = v
|
||
|
}
|
||
|
}
|
||
|
//Todo handle highestTrust == 0
|
||
|
for i, v := range t1 {
|
||
|
t1[i] = (v/highestTrust)*g.Alpha + (1-g.Alpha)*g.initialTrust[i]
|
||
|
}
|
||
|
|
||
|
return &t1
|
||
|
}
|
||
|
|
||
|
// abs is helper to take abs of float32
|
||
|
func abs(x float32) float32 {
|
||
|
if x < 0 {
|
||
|
return -x
|
||
|
}
|
||
|
return x
|
||
|
}
|
||
|
|
||
|
// avgD is helper to compare 2 maps of float32s and return the average
|
||
|
// difference between them
|
||
|
func avgD(t0, t1 *map[int]float32) float32 {
|
||
|
d := float32(0)
|
||
|
for i, v := range *t1 {
|
||
|
d += abs(v - (*t0)[i])
|
||
|
}
|
||
|
d = d / float32(len(*t0))
|
||
|
return d
|
||
|
}
|