storj/satellite/reputation/calculations.go
paul cannon 37a4edbaff all: reformat comments as required by gofmt 1.19
I don't know why the go people thought this was a good idea, because
this automatic reformatting is bound to do the wrong thing sometimes,
which is very annoying. But I don't see a way to turn it off, so best to
get this change out of the way.

Change-Id: Ib5dbbca6a6f6fc944d76c9b511b8c904f796e4f3
2022-08-10 18:24:55 +00:00

68 lines
2.4 KiB
Go

// Copyright (C) 2022 Storj Labs, Inc.
// See LICENSE for copying information.
package reputation
import "math"
// UpdateReputation uses the Beta distribution model to determine a node's reputation.
// lambda is the "forgetting factor" which determines how much past info is kept when determining current reputation score.
// w is the normalization weight that affects how severely new updates affect the current reputation distribution.
func UpdateReputation(isSuccess bool, alpha, beta, lambda, w float64) (newAlpha, newBeta float64) {
// v is a single feedback value that allows us to update both alpha and beta
var v float64 = -1
if isSuccess {
v = 1
}
newAlpha = lambda*alpha + w*(1+v)/2
newBeta = lambda*beta + w*(1-v)/2
return newAlpha, newBeta
}
// UpdateReputationMultiple works like UpdateReputation, but applies multiple
// successive counts of an event type to the alpha and beta measures.
//
// With the arguments as named, applies 'count' successful audits. To apply negative
// audits, swap the alpha and beta parameters and return values.
//
// WARNING: GREEK LETTER MATH AHEAD
//
// Applying n successful audit results to an initial alpha value of α₀ gives a
// new α₁ value of:
//
// α₁ = λⁿα₀ + λⁿ⁻¹w + λⁿ⁻²w + ... + λ²w + λw + w
//
// The terms with w are the first n terms of a geometric series with coefficient
// w and common ratio λ. The closed form formula for the sum of those first n
// terms is (w(1-λⁿ) / (1-λ))
// (https://en.wikipedia.org/wiki/Geometric_series#Closed-form_formula).
// Adding the initial λⁿα₀ term, we get
//
// α₁ = λⁿα₀ + w(1-λⁿ) / (1-λ)
//
// The formula has the same structure for beta for n _failures_.
//
// β₁ = λⁿβ₀ + w(1-λⁿ) / (1-λ)
//
// For n _failures_,
//
// α₁ = λⁿα₀
//
// For n _successes_,
//
// β₁ = λⁿβ₀
func UpdateReputationMultiple(count int, alpha, beta, lambda, w float64) (newAlpha, newBeta float64) {
if lambda == 1 {
// special case: when the coefficient is 1, the closed-form formula is invalid
// (gives NaN because of a division by zero). Fortunately, the replacement
// formula in this case is even simpler.
newAlpha = alpha + w*float64(count)
newBeta = beta
} else {
lambdaPowN := math.Pow(lambda, float64(count))
newAlpha = lambdaPowN*alpha + w*(1-lambdaPowN)/(1-lambda)
newBeta = lambdaPowN * beta
}
return newAlpha, newBeta
}