-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathtrustgraph.go
142 lines (127 loc) · 3.83 KB
/
trustgraph.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
// 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
}