60 lines
1.4 KiB
Go
60 lines
1.4 KiB
Go
package tdigest
|
|
|
|
import (
|
|
"fmt"
|
|
"sort"
|
|
)
|
|
|
|
// ErrWeightLessThanZero is used when the weight is not able to be processed.
|
|
const ErrWeightLessThanZero = Error("centroid weight cannot be less than zero")
|
|
|
|
// Error is a domain error encountered while processing tdigests
|
|
type Error string
|
|
|
|
func (e Error) Error() string {
|
|
return string(e)
|
|
}
|
|
|
|
// Centroid average position of all points in a shape
|
|
type Centroid struct {
|
|
Mean float64
|
|
Weight float64
|
|
}
|
|
|
|
func (c *Centroid) String() string {
|
|
return fmt.Sprintf("{mean: %f weight: %f}", c.Mean, c.Weight)
|
|
}
|
|
|
|
// Add averages the two centroids together and update this centroid
|
|
func (c *Centroid) Add(r Centroid) error {
|
|
if r.Weight < 0 {
|
|
return ErrWeightLessThanZero
|
|
}
|
|
if c.Weight != 0 {
|
|
c.Weight += r.Weight
|
|
c.Mean += r.Weight * (r.Mean - c.Mean) / c.Weight
|
|
} else {
|
|
c.Weight = r.Weight
|
|
c.Mean = r.Mean
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// CentroidList is sorted by the Mean of the centroid, ascending.
|
|
type CentroidList []Centroid
|
|
|
|
func (l *CentroidList) Clear() {
|
|
*l = (*l)[0:0]
|
|
}
|
|
|
|
func (l CentroidList) Len() int { return len(l) }
|
|
func (l CentroidList) Less(i, j int) bool { return l[i].Mean < l[j].Mean }
|
|
func (l CentroidList) Swap(i, j int) { l[i], l[j] = l[j], l[i] }
|
|
|
|
// NewCentroidList creates a priority queue for the centroids
|
|
func NewCentroidList(centroids []Centroid) CentroidList {
|
|
l := CentroidList(centroids)
|
|
sort.Sort(l)
|
|
return l
|
|
}
|