2021-10-27 10:00:35 +00:00
|
|
|
package netmap
|
|
|
|
|
2024-07-12 07:22:35 +00:00
|
|
|
import "slices"
|
2021-10-27 10:00:35 +00:00
|
|
|
|
|
|
|
type (
|
|
|
|
// aggregator can calculate some value across all netmap
|
|
|
|
// such as median, minimum or maximum.
|
|
|
|
aggregator interface {
|
|
|
|
Add(float64)
|
|
|
|
Compute() float64
|
|
|
|
}
|
|
|
|
|
|
|
|
// normalizer normalizes weight.
|
|
|
|
normalizer interface {
|
|
|
|
Normalize(w float64) float64
|
|
|
|
}
|
|
|
|
|
|
|
|
meanAgg struct {
|
|
|
|
mean float64
|
|
|
|
count int
|
|
|
|
}
|
|
|
|
|
|
|
|
minAgg struct {
|
2023-09-16 14:03:38 +00:00
|
|
|
min float64
|
|
|
|
minFound bool
|
2021-10-27 10:00:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
meanIQRAgg struct {
|
|
|
|
k float64
|
|
|
|
arr []float64
|
|
|
|
}
|
|
|
|
|
|
|
|
reverseMinNorm struct {
|
|
|
|
min float64
|
|
|
|
}
|
|
|
|
|
|
|
|
sigmoidNorm struct {
|
|
|
|
scale float64
|
|
|
|
}
|
|
|
|
|
|
|
|
// weightFunc calculates n's weight.
|
2022-06-07 02:12:39 +00:00
|
|
|
weightFunc = func(NodeInfo) float64
|
2021-10-27 10:00:35 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
var (
|
|
|
|
_ aggregator = (*meanAgg)(nil)
|
|
|
|
_ aggregator = (*minAgg)(nil)
|
|
|
|
_ aggregator = (*meanIQRAgg)(nil)
|
|
|
|
|
|
|
|
_ normalizer = (*reverseMinNorm)(nil)
|
|
|
|
_ normalizer = (*sigmoidNorm)(nil)
|
|
|
|
)
|
|
|
|
|
|
|
|
// newWeightFunc returns weightFunc which multiplies normalized
|
|
|
|
// capacity and price.
|
|
|
|
func newWeightFunc(capNorm, priceNorm normalizer) weightFunc {
|
2022-06-07 02:12:39 +00:00
|
|
|
return func(n NodeInfo) float64 {
|
2022-06-07 08:25:34 +00:00
|
|
|
return capNorm.Normalize(float64(n.capacity())) * priceNorm.Normalize(float64(n.Price()))
|
2021-10-27 10:00:35 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// newMeanAgg returns an aggregator which
|
|
|
|
// computes mean value by recalculating it on
|
|
|
|
// every addition.
|
|
|
|
func newMeanAgg() aggregator {
|
|
|
|
return new(meanAgg)
|
|
|
|
}
|
|
|
|
|
|
|
|
// newMinAgg returns an aggregator which
|
|
|
|
// computes min value.
|
|
|
|
func newMinAgg() aggregator {
|
|
|
|
return new(minAgg)
|
|
|
|
}
|
|
|
|
|
|
|
|
// newReverseMinNorm returns a normalizer which
|
|
|
|
// normalize values in range of 0.0 to 1.0 to a minimum value.
|
|
|
|
func newReverseMinNorm(min float64) normalizer {
|
|
|
|
return &reverseMinNorm{min: min}
|
|
|
|
}
|
|
|
|
|
|
|
|
// newSigmoidNorm returns a normalizer which
|
|
|
|
// normalize values in range of 0.0 to 1.0 to a scaled sigmoid.
|
|
|
|
func newSigmoidNorm(scale float64) normalizer {
|
|
|
|
return &sigmoidNorm{scale: scale}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (a *meanAgg) Add(n float64) {
|
|
|
|
c := a.count + 1
|
|
|
|
a.mean = a.mean*(float64(a.count)/float64(c)) + n/float64(c)
|
|
|
|
a.count++
|
|
|
|
}
|
|
|
|
|
|
|
|
func (a *meanAgg) Compute() float64 {
|
|
|
|
return a.mean
|
|
|
|
}
|
|
|
|
|
|
|
|
func (a *minAgg) Add(n float64) {
|
2023-09-16 14:03:38 +00:00
|
|
|
if !a.minFound {
|
|
|
|
a.min = n
|
|
|
|
a.minFound = true
|
|
|
|
return
|
2021-10-27 10:00:35 +00:00
|
|
|
}
|
|
|
|
|
2023-09-16 14:03:38 +00:00
|
|
|
if n < a.min {
|
|
|
|
a.min = n
|
2023-09-12 18:16:06 +00:00
|
|
|
}
|
2023-09-16 14:03:38 +00:00
|
|
|
}
|
2023-09-12 18:16:06 +00:00
|
|
|
|
2023-09-16 14:03:38 +00:00
|
|
|
func (a *minAgg) Compute() float64 {
|
|
|
|
return a.min
|
2021-10-27 10:00:35 +00:00
|
|
|
}
|
|
|
|
|
2024-07-12 07:33:34 +00:00
|
|
|
func (a *meanIQRAgg) clear() {
|
|
|
|
a.k = 0
|
|
|
|
a.arr = a.arr[:0]
|
|
|
|
}
|
|
|
|
|
2021-10-27 10:00:35 +00:00
|
|
|
func (a *meanIQRAgg) Add(n float64) {
|
|
|
|
a.arr = append(a.arr, n)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (a *meanIQRAgg) Compute() float64 {
|
|
|
|
l := len(a.arr)
|
|
|
|
if l == 0 {
|
|
|
|
return 0
|
|
|
|
}
|
|
|
|
|
2024-07-12 07:22:35 +00:00
|
|
|
slices.Sort(a.arr)
|
2021-10-27 10:00:35 +00:00
|
|
|
|
|
|
|
var min, max float64
|
|
|
|
|
|
|
|
const minLn = 4
|
|
|
|
|
|
|
|
if l < minLn {
|
|
|
|
min, max = a.arr[0], a.arr[l-1]
|
|
|
|
} else {
|
|
|
|
start, end := l/minLn, l*3/minLn-1
|
|
|
|
iqr := a.k * (a.arr[end] - a.arr[start])
|
|
|
|
min, max = a.arr[start]-iqr, a.arr[end]+iqr
|
|
|
|
}
|
|
|
|
|
|
|
|
count := 0
|
|
|
|
sum := float64(0)
|
|
|
|
|
|
|
|
for _, e := range a.arr {
|
|
|
|
if e >= min && e <= max {
|
|
|
|
sum += e
|
|
|
|
count++
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return sum / float64(count)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (r *reverseMinNorm) Normalize(w float64) float64 {
|
2023-10-26 11:03:50 +00:00
|
|
|
return (r.min + 1) / (w + 1)
|
2021-10-27 10:00:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (r *sigmoidNorm) Normalize(w float64) float64 {
|
|
|
|
if r.scale == 0 {
|
|
|
|
return 0
|
|
|
|
}
|
|
|
|
|
|
|
|
x := w / r.scale
|
|
|
|
|
|
|
|
return x / (1 + x)
|
|
|
|
}
|