├── .gitignore ├── histogram ├── bench_test.go ├── histogram_test.go └── histogram.go ├── topk ├── topk_test.go └── topk.go ├── LICENSE ├── quantile ├── bench_test.go ├── example_test.go ├── stream_test.go ├── stream.go └── exampledata.txt └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | *.test 2 | *.prof 3 | -------------------------------------------------------------------------------- /histogram/bench_test.go: -------------------------------------------------------------------------------- 1 | package histogram 2 | 3 | import ( 4 | "math/rand" 5 | "testing" 6 | ) 7 | 8 | func BenchmarkInsert10Bins(b *testing.B) { 9 | b.StopTimer() 10 | h := New(10) 11 | b.StartTimer() 12 | for i := 0; i < b.N; i++ { 13 | f := rand.ExpFloat64() 14 | h.Insert(f) 15 | } 16 | } 17 | 18 | func BenchmarkInsert100Bins(b *testing.B) { 19 | b.StopTimer() 20 | h := New(100) 21 | b.StartTimer() 22 | for i := 0; i < b.N; i++ { 23 | f := rand.ExpFloat64() 24 | h.Insert(f) 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /histogram/histogram_test.go: -------------------------------------------------------------------------------- 1 | package histogram 2 | 3 | import ( 4 | "math/rand" 5 | "testing" 6 | ) 7 | 8 | func TestHistogram(t *testing.T) { 9 | const numPoints = 1e6 10 | const maxBins = 3 11 | 12 | h := New(maxBins) 13 | for i := 0; i < numPoints; i++ { 14 | f := rand.ExpFloat64() 15 | h.Insert(f) 16 | } 17 | 18 | bins := h.Bins() 19 | if g := len(bins); g > maxBins { 20 | t.Fatalf("got %d bins, wanted <= %d", g, maxBins) 21 | } 22 | 23 | for _, b := range bins { 24 | t.Logf("%+v", b) 25 | } 26 | 27 | if g := count(h.Bins()); g != numPoints { 28 | t.Fatalf("binned %d points, wanted %d", g, numPoints) 29 | } 30 | } 31 | 32 | func count(bins Bins) int { 33 | binCounts := 0 34 | for _, b := range bins { 35 | binCounts += b.Count 36 | } 37 | return binCounts 38 | } 39 | -------------------------------------------------------------------------------- /topk/topk_test.go: -------------------------------------------------------------------------------- 1 | package topk 2 | 3 | import ( 4 | "fmt" 5 | "math/rand" 6 | "sort" 7 | "testing" 8 | ) 9 | 10 | func TestTopK(t *testing.T) { 11 | stream := New(10) 12 | ss := []*Stream{New(10), New(10), New(10)} 13 | m := make(map[string]int) 14 | for _, s := range ss { 15 | for i := 0; i < 1e6; i++ { 16 | v := fmt.Sprintf("%x", int8(rand.ExpFloat64())) 17 | s.Insert(v) 18 | m[v]++ 19 | } 20 | stream.Merge(s.Query()) 21 | } 22 | 23 | var sm Samples 24 | for x, s := range m { 25 | sm = append(sm, &Element{x, s}) 26 | } 27 | sort.Sort(sort.Reverse(sm)) 28 | 29 | g := stream.Query() 30 | if len(g) != 10 { 31 | t.Fatalf("got %d, want 10", len(g)) 32 | } 33 | for i, e := range g { 34 | if sm[i].Value != e.Value { 35 | t.Errorf("at %d: want %q, got %q", i, sm[i].Value, e.Value) 36 | } 37 | } 38 | } 39 | 40 | func TestQuery(t *testing.T) { 41 | queryTests := []struct { 42 | value string 43 | expected int 44 | }{ 45 | {"a", 1}, 46 | {"b", 2}, 47 | {"c", 2}, 48 | } 49 | 50 | stream := New(2) 51 | for _, tt := range queryTests { 52 | stream.Insert(tt.value) 53 | if n := len(stream.Query()); n != tt.expected { 54 | t.Errorf("want %d, got %d", tt.expected, n) 55 | } 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | BSD 2-Clause License 2 | 3 | Copyright (c) 2022, Blake Mizerany 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | 9 | 1. Redistributions of source code must retain the above copyright notice, this 10 | list of conditions and the following disclaimer. 11 | 12 | 2. Redistributions in binary form must reproduce the above copyright notice, 13 | this list of conditions and the following disclaimer in the documentation 14 | and/or other materials provided with the distribution. 15 | 16 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 17 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 20 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 22 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 23 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 24 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 25 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | -------------------------------------------------------------------------------- /quantile/bench_test.go: -------------------------------------------------------------------------------- 1 | package quantile 2 | 3 | import ( 4 | "testing" 5 | ) 6 | 7 | func BenchmarkInsertTargeted(b *testing.B) { 8 | b.ReportAllocs() 9 | 10 | s := NewTargeted(0.01, 0.5, 0.9, 0.99) 11 | b.ResetTimer() 12 | for i := float64(0); i < float64(b.N); i++ { 13 | s.Insert(i) 14 | } 15 | } 16 | 17 | func BenchmarkInsertTargetedSmallEpsilon(b *testing.B) { 18 | s := NewTargeted(0.01, 0.5, 0.9, 0.99) 19 | s.SetEpsilon(0.0001) 20 | b.ResetTimer() 21 | for i := float64(0); i < float64(b.N); i++ { 22 | s.Insert(i) 23 | } 24 | } 25 | 26 | func BenchmarkInsertBiased(b *testing.B) { 27 | s := NewBiased() 28 | b.ResetTimer() 29 | for i := float64(0); i < float64(b.N); i++ { 30 | s.Insert(i) 31 | } 32 | } 33 | 34 | func BenchmarkInsertBiasedSmallEpsilon(b *testing.B) { 35 | s := NewBiased() 36 | s.SetEpsilon(0.0001) 37 | b.ResetTimer() 38 | for i := float64(0); i < float64(b.N); i++ { 39 | s.Insert(i) 40 | } 41 | } 42 | 43 | func BenchmarkQuery(b *testing.B) { 44 | s := NewTargeted(0.01, 0.5, 0.9, 0.99) 45 | for i := float64(0); i < 1e6; i++ { 46 | s.Insert(i) 47 | } 48 | b.ResetTimer() 49 | n := float64(b.N) 50 | for i := float64(0); i < n; i++ { 51 | s.Query(i / n) 52 | } 53 | } 54 | 55 | func BenchmarkQuerySmallEpsilon(b *testing.B) { 56 | s := NewTargeted(0.01, 0.5, 0.9, 0.99) 57 | s.SetEpsilon(0.0001) 58 | for i := float64(0); i < 1e6; i++ { 59 | s.Insert(i) 60 | } 61 | b.ResetTimer() 62 | n := float64(b.N) 63 | for i := float64(0); i < n; i++ { 64 | s.Query(i / n) 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /topk/topk.go: -------------------------------------------------------------------------------- 1 | package topk 2 | 3 | import ( 4 | "sort" 5 | ) 6 | 7 | // http://www.cs.ucsb.edu/research/tech_reports/reports/2005-23.pdf 8 | 9 | type Element struct { 10 | Value string 11 | Count int 12 | } 13 | 14 | type Samples []*Element 15 | 16 | func (sm Samples) Len() int { 17 | return len(sm) 18 | } 19 | 20 | func (sm Samples) Less(i, j int) bool { 21 | return sm[i].Count < sm[j].Count 22 | } 23 | 24 | func (sm Samples) Swap(i, j int) { 25 | sm[i], sm[j] = sm[j], sm[i] 26 | } 27 | 28 | type Stream struct { 29 | k int 30 | mon map[string]*Element 31 | 32 | // the minimum Element 33 | min *Element 34 | } 35 | 36 | func New(k int) *Stream { 37 | s := new(Stream) 38 | s.k = k 39 | s.mon = make(map[string]*Element) 40 | s.min = &Element{} 41 | 42 | // Track k+1 so that less frequenet items contended for that spot, 43 | // resulting in k being more accurate. 44 | return s 45 | } 46 | 47 | func (s *Stream) Insert(x string) { 48 | s.insert(&Element{x, 1}) 49 | } 50 | 51 | func (s *Stream) Merge(sm Samples) { 52 | for _, e := range sm { 53 | s.insert(e) 54 | } 55 | } 56 | 57 | func (s *Stream) insert(in *Element) { 58 | e := s.mon[in.Value] 59 | if e != nil { 60 | e.Count++ 61 | } else { 62 | if len(s.mon) < s.k+1 { 63 | e = &Element{in.Value, in.Count} 64 | s.mon[in.Value] = e 65 | } else { 66 | e = s.min 67 | delete(s.mon, e.Value) 68 | e.Value = in.Value 69 | e.Count += in.Count 70 | s.min = e 71 | } 72 | } 73 | if e.Count < s.min.Count { 74 | s.min = e 75 | } 76 | } 77 | 78 | func (s *Stream) Query() Samples { 79 | var sm Samples 80 | for _, e := range s.mon { 81 | sm = append(sm, e) 82 | } 83 | sort.Sort(sort.Reverse(sm)) 84 | 85 | if len(sm) < s.k { 86 | return sm 87 | } 88 | 89 | return sm[:s.k] 90 | } 91 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Perks for Go (golang.org) 2 | 3 | Perks contains the Go package quantile that computes approximate quantiles over 4 | an unbounded data stream within low memory and CPU bounds. 5 | 6 | For more information and examples, see: 7 | http://godoc.org/github.com/bmizerany/perks 8 | 9 | A very special thank you and shout out to Graham Cormode (Rutgers University), 10 | Flip Korn (AT&T Labs–Research), S. Muthukrishnan (Rutgers University), and 11 | Divesh Srivastava (AT&T Labs–Research) for their research and publication of 12 | [Effective Computation of Biased Quantiles over Data Streams](http://dimacs.rutgers.edu/~graham/pubs/papers/bquant-icde.pdf) 13 | 14 | Thank you, also: 15 | * Armon Dadgar (@armon) 16 | * Andrew Gerrand (@nf) 17 | * Brad Fitzpatrick (@bradfitz) 18 | * Keith Rarick (@kr) 19 | 20 | FAQ: 21 | 22 | Q: Why not move the quantile package into the project root? 23 | A: I want to add more packages to perks later. 24 | 25 | Copyright (C) 2013 Blake Mizerany 26 | 27 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 28 | 29 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 30 | 31 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 32 | -------------------------------------------------------------------------------- /histogram/histogram.go: -------------------------------------------------------------------------------- 1 | // Package histogram provides a Go implementation of BigML's histogram package 2 | // for Clojure/Java. It is currently experimental. 3 | package histogram 4 | 5 | import ( 6 | "container/heap" 7 | "math" 8 | "sort" 9 | ) 10 | 11 | type Bin struct { 12 | Count int 13 | Sum float64 14 | } 15 | 16 | func (b *Bin) Update(x *Bin) { 17 | b.Count += x.Count 18 | b.Sum += x.Sum 19 | } 20 | 21 | func (b *Bin) Mean() float64 { 22 | return b.Sum / float64(b.Count) 23 | } 24 | 25 | type Bins []*Bin 26 | 27 | func (bs Bins) Len() int { return len(bs) } 28 | func (bs Bins) Less(i, j int) bool { return bs[i].Mean() < bs[j].Mean() } 29 | func (bs Bins) Swap(i, j int) { bs[i], bs[j] = bs[j], bs[i] } 30 | 31 | func (bs *Bins) Push(x interface{}) { 32 | *bs = append(*bs, x.(*Bin)) 33 | } 34 | 35 | func (bs *Bins) Pop() interface{} { 36 | return bs.remove(len(*bs) - 1) 37 | } 38 | 39 | func (bs *Bins) remove(n int) *Bin { 40 | if n < 0 || len(*bs) < n { 41 | return nil 42 | } 43 | x := (*bs)[n] 44 | *bs = append((*bs)[:n], (*bs)[n+1:]...) 45 | return x 46 | } 47 | 48 | type Histogram struct { 49 | res *reservoir 50 | } 51 | 52 | func New(maxBins int) *Histogram { 53 | return &Histogram{res: newReservoir(maxBins)} 54 | } 55 | 56 | func (h *Histogram) Insert(f float64) { 57 | h.res.insert(&Bin{1, f}) 58 | h.res.compress() 59 | } 60 | 61 | func (h *Histogram) Bins() Bins { 62 | return h.res.bins 63 | } 64 | 65 | type reservoir struct { 66 | n int 67 | maxBins int 68 | bins Bins 69 | } 70 | 71 | func newReservoir(maxBins int) *reservoir { 72 | return &reservoir{maxBins: maxBins} 73 | } 74 | 75 | func (r *reservoir) insert(bin *Bin) { 76 | r.n += bin.Count 77 | i := sort.Search(len(r.bins), func(i int) bool { 78 | return r.bins[i].Mean() >= bin.Mean() 79 | }) 80 | if i < 0 || i == r.bins.Len() { 81 | // TODO(blake): Maybe use an .insert(i, bin) instead of 82 | // performing the extra work of a heap.Push. 83 | heap.Push(&r.bins, bin) 84 | return 85 | } 86 | r.bins[i].Update(bin) 87 | } 88 | 89 | func (r *reservoir) compress() { 90 | for r.bins.Len() > r.maxBins { 91 | minGapIndex := -1 92 | minGap := math.MaxFloat64 93 | for i := 0; i < r.bins.Len()-1; i++ { 94 | gap := gapWeight(r.bins[i], r.bins[i+1]) 95 | if minGap > gap { 96 | minGap = gap 97 | minGapIndex = i 98 | } 99 | } 100 | prev := r.bins[minGapIndex] 101 | next := r.bins.remove(minGapIndex + 1) 102 | prev.Update(next) 103 | } 104 | } 105 | 106 | func gapWeight(prev, next *Bin) float64 { 107 | return next.Mean() - prev.Mean() 108 | } 109 | -------------------------------------------------------------------------------- /quantile/example_test.go: -------------------------------------------------------------------------------- 1 | // +build go1.1 2 | 3 | package quantile_test 4 | 5 | import ( 6 | "bufio" 7 | "fmt" 8 | "github.com/bmizerany/perks/quantile" 9 | "log" 10 | "os" 11 | "strconv" 12 | "time" 13 | ) 14 | 15 | func Example_simple() { 16 | ch := make(chan float64) 17 | go sendFloats(ch) 18 | 19 | // Compute the 50th, 90th, and 99th percentile. 20 | q := quantile.NewTargeted(0.50, 0.90, 0.99) 21 | for v := range ch { 22 | q.Insert(v) 23 | } 24 | 25 | fmt.Println("perc50:", q.Query(0.50)) 26 | fmt.Println("perc90:", q.Query(0.90)) 27 | fmt.Println("perc99:", q.Query(0.99)) 28 | fmt.Println("count:", q.Count()) 29 | // Output: 30 | // perc50: 5 31 | // perc90: 14 32 | // perc99: 40 33 | // count: 2388 34 | } 35 | 36 | func Example_mergeMultipleStreams() { 37 | // Scenario: 38 | // We have multiple database shards. On each shard, there is a process 39 | // collecting query response times from the database logs and inserting 40 | // them into a Stream (created via NewTargeted(0.90)), much like the 41 | // Simple example. These processes expose a network interface for us to 42 | // ask them to serialize and send us the results of their 43 | // Stream.Samples so we may Merge and Query them. 44 | // 45 | // NOTES: 46 | // * These sample sets are small, allowing us to get them 47 | // across the network much faster than sending the entire list of data 48 | // points. 49 | // 50 | // * For this to work correctly, we must supply the same quantiles 51 | // a priori the process collecting the samples supplied to NewTargeted, 52 | // even if we do not plan to query them all here. 53 | ch := make(chan quantile.Samples) 54 | getDBQuerySamples(ch) 55 | q := quantile.NewTargeted(0.90) 56 | for samples := range ch { 57 | q.Merge(samples) 58 | } 59 | fmt.Println("perc90:", q.Query(0.90)) 60 | } 61 | 62 | func Example_window() { 63 | // Scenario: We want the 90th, 95th, and 99th percentiles for each 64 | // minute. 65 | 66 | ch := make(chan float64) 67 | go sendStreamValues(ch) 68 | 69 | tick := time.NewTicker(1 * time.Minute) 70 | q := quantile.NewTargeted(0.90, 0.95, 0.99) 71 | for { 72 | select { 73 | case t := <-tick.C: 74 | flushToDB(t, q.Samples()) 75 | q.Reset() 76 | case v := <-ch: 77 | q.Insert(v) 78 | } 79 | } 80 | } 81 | 82 | func sendStreamValues(ch chan float64) { 83 | // Use your imagination 84 | } 85 | 86 | func flushToDB(t time.Time, samples quantile.Samples) { 87 | // Use your imagination 88 | } 89 | 90 | // This is a stub for the above example. In reality this would hit the remote 91 | // servers via http or something like it. 92 | func getDBQuerySamples(ch chan quantile.Samples) {} 93 | 94 | func sendFloats(ch chan<- float64) { 95 | f, err := os.Open("exampledata.txt") 96 | if err != nil { 97 | log.Fatal(err) 98 | } 99 | sc := bufio.NewScanner(f) 100 | for sc.Scan() { 101 | b := sc.Bytes() 102 | v, err := strconv.ParseFloat(string(b), 64) 103 | if err != nil { 104 | log.Fatal(err) 105 | } 106 | ch <- v 107 | } 108 | if sc.Err() != nil { 109 | log.Fatal(sc.Err()) 110 | } 111 | close(ch) 112 | } 113 | -------------------------------------------------------------------------------- /quantile/stream_test.go: -------------------------------------------------------------------------------- 1 | package quantile 2 | 3 | import ( 4 | "math" 5 | "math/rand" 6 | "sort" 7 | "testing" 8 | ) 9 | 10 | func TestQuantRandQuery(t *testing.T) { 11 | s := NewTargeted(0.5, 0.90, 0.99) 12 | a := make([]float64, 0, 1e5) 13 | rand.Seed(42) 14 | for i := 0; i < cap(a); i++ { 15 | v := float64(rand.Int63()) 16 | s.Insert(v) 17 | a = append(a, v) 18 | } 19 | t.Logf("len: %d", s.Count()) 20 | sort.Float64s(a) 21 | w := getPerc(a, 0.50) 22 | if g := s.Query(0.50); math.Abs(w-g)/w > 0.03 { 23 | t.Errorf("perc50: want %v, got %v", w, g) 24 | t.Logf("e: %f", math.Abs(w-g)/w) 25 | } 26 | w = getPerc(a, 0.90) 27 | if g := s.Query(0.90); math.Abs(w-g)/w > 0.03 { 28 | t.Errorf("perc90: want %v, got %v", w, g) 29 | t.Logf("e: %f", math.Abs(w-g)/w) 30 | } 31 | w = getPerc(a, 0.99) 32 | if g := s.Query(0.99); math.Abs(w-g)/w > 0.03 { 33 | t.Errorf("perc99: want %v, got %v", w, g) 34 | t.Logf("e: %f", math.Abs(w-g)/w) 35 | } 36 | } 37 | 38 | func TestQuantRandMergeQuery(t *testing.T) { 39 | ch := make(chan float64) 40 | done := make(chan *Stream) 41 | for i := 0; i < 2; i++ { 42 | go func() { 43 | s := NewTargeted(0.5, 0.90, 0.99) 44 | for v := range ch { 45 | s.Insert(v) 46 | } 47 | done <- s 48 | }() 49 | } 50 | 51 | rand.Seed(42) 52 | a := make([]float64, 0, 1e6) 53 | for i := 0; i < cap(a); i++ { 54 | v := float64(rand.Int63()) 55 | a = append(a, v) 56 | ch <- v 57 | } 58 | close(ch) 59 | 60 | s := <-done 61 | o := <-done 62 | s.Merge(o.Samples()) 63 | 64 | t.Logf("len: %d", s.Count()) 65 | sort.Float64s(a) 66 | w := getPerc(a, 0.50) 67 | if g := s.Query(0.50); math.Abs(w-g)/w > 0.03 { 68 | t.Errorf("perc50: want %v, got %v", w, g) 69 | t.Logf("e: %f", math.Abs(w-g)/w) 70 | } 71 | w = getPerc(a, 0.90) 72 | if g := s.Query(0.90); math.Abs(w-g)/w > 0.03 { 73 | t.Errorf("perc90: want %v, got %v", w, g) 74 | t.Logf("e: %f", math.Abs(w-g)/w) 75 | } 76 | w = getPerc(a, 0.99) 77 | if g := s.Query(0.99); math.Abs(w-g)/w > 0.03 { 78 | t.Errorf("perc99: want %v, got %v", w, g) 79 | t.Logf("e: %f", math.Abs(w-g)/w) 80 | } 81 | } 82 | 83 | func TestUncompressed(t *testing.T) { 84 | tests := []float64{0.50, 0.90, 0.95, 0.99} 85 | q := NewTargeted(tests...) 86 | for i := 100; i > 0; i-- { 87 | q.Insert(float64(i)) 88 | } 89 | if g := q.Count(); g != 100 { 90 | t.Errorf("want count 100, got %d", g) 91 | } 92 | // Before compression, Query should have 100% accuracy. 93 | for _, v := range tests { 94 | w := v * 100 95 | if g := q.Query(v); g != w { 96 | t.Errorf("want %f, got %f", w, g) 97 | } 98 | } 99 | } 100 | 101 | func TestUncompressedSamples(t *testing.T) { 102 | q := NewTargeted(0.99) 103 | for i := 1; i <= 100; i++ { 104 | q.Insert(float64(i)) 105 | } 106 | if g := q.Samples().Len(); g != 100 { 107 | t.Errorf("want count 100, got %d", g) 108 | } 109 | } 110 | 111 | func TestUncompressedOne(t *testing.T) { 112 | q := NewTargeted(0.90) 113 | q.Insert(3.14) 114 | if g := q.Query(0.90); g != 3.14 { 115 | t.Error("want PI, got", g) 116 | } 117 | } 118 | 119 | func TestDefaults(t *testing.T) { 120 | if g := NewTargeted(0.99).Query(0.99); g != 0 { 121 | t.Errorf("want 0, got %f", g) 122 | } 123 | } 124 | 125 | func getPerc(x []float64, p float64) float64 { 126 | k := int(float64(len(x)) * p) 127 | return x[k] 128 | } 129 | -------------------------------------------------------------------------------- /quantile/stream.go: -------------------------------------------------------------------------------- 1 | // Package quantile computes approximate quantiles over an unbounded data 2 | // stream within low memory and CPU bounds. 3 | // 4 | // A small amount of accuracy is traded to achieve the above properties. 5 | // 6 | // Multiple streams can be merged before calling Query to generate a single set 7 | // of results. This is meaningful when the streams represent the same type of 8 | // data. See Merge and Samples. 9 | // 10 | // For more detailed information about the algorithm used, see: 11 | // 12 | // Effective Computation of Biased Quantiles over Data Streams 13 | // 14 | // http://dimacs.rutgers.edu/~graham/pubs/papers/bquant-icde.pdf 15 | package quantile 16 | 17 | import ( 18 | "math" 19 | "sort" 20 | ) 21 | 22 | // Sample holds an observed value and meta information for compression. JSON 23 | // tags have been added for convenience. 24 | type Sample struct { 25 | Value float64 `json:",string"` 26 | Width float64 `json:",string"` 27 | Delta float64 `json:",string"` 28 | } 29 | 30 | // Samples represents a slice of samples. It implements sort.Interface. 31 | type Samples []Sample 32 | 33 | func (a Samples) Len() int { return len(a) } 34 | func (a Samples) Less(i, j int) bool { return a[i].Value < a[j].Value } 35 | func (a Samples) Swap(i, j int) { a[i], a[j] = a[j], a[i] } 36 | 37 | type invariant func(s *stream, r float64) float64 38 | 39 | // NewBiased returns an initialized Stream for high-biased quantiles (e.g. 40 | // 50th, 90th, 99th) not known a priori with finer error guarantees for the 41 | // higher ranks of the data distribution. 42 | // See http://dimacs.rutgers.edu/~graham/pubs/papers/bquant-icde.pdf for time, space, and error properties. 43 | func NewBiased() *Stream { 44 | ƒ := func(s *stream, r float64) float64 { 45 | return 2 * s.epsilon * r 46 | } 47 | return newStream(ƒ) 48 | } 49 | 50 | // NewTargeted returns an initialized Stream concerned with a particular set of 51 | // quantile values that are supplied a priori. Knowing these a priori reduces 52 | // space and computation time. 53 | // See http://dimacs.rutgers.edu/~graham/pubs/papers/bquant-icde.pdf for time, space, and error properties. 54 | func NewTargeted(quantiles ...float64) *Stream { 55 | ƒ := func(s *stream, r float64) float64 { 56 | var m float64 = math.MaxFloat64 57 | var f float64 58 | for _, q := range quantiles { 59 | if q*s.n <= r { 60 | f = (2 * s.epsilon * r) / q 61 | } else { 62 | f = (2 * s.epsilon * (s.n - r)) / (1 - q) 63 | } 64 | if f < m { 65 | m = f 66 | } 67 | } 68 | return m 69 | } 70 | return newStream(ƒ) 71 | } 72 | 73 | // Stream computes quantiles for a stream of float64s. It is not thread-safe by 74 | // design. Take care when using across multiple goroutines. 75 | type Stream struct { 76 | *stream 77 | b Samples 78 | sorted bool 79 | } 80 | 81 | func newStream(ƒ invariant) *Stream { 82 | const defaultEpsilon = 0.01 83 | x := &stream{epsilon: defaultEpsilon, ƒ: ƒ} 84 | return &Stream{x, make(Samples, 0, 500), true} 85 | } 86 | 87 | // Insert inserts v into the stream. 88 | func (s *Stream) Insert(v float64) { 89 | s.insert(Sample{Value: v, Width: 1}) 90 | } 91 | 92 | func (s *Stream) insert(sample Sample) { 93 | s.b = append(s.b, sample) 94 | s.sorted = false 95 | if len(s.b) == cap(s.b) { 96 | s.flush() 97 | s.compress() 98 | } 99 | } 100 | 101 | // Query returns the computed qth percentiles value. If s was created with 102 | // NewTargeted, and q is not in the set of quantiles provided a priori, Query 103 | // will return an unspecified result. 104 | func (s *Stream) Query(q float64) float64 { 105 | if !s.flushed() { 106 | // Fast path when there hasn't been enough data for a flush; 107 | // this also yields better accuracy for small sets of data. 108 | l := len(s.b) 109 | if l == 0 { 110 | return 0 111 | } 112 | i := int(float64(l) * q) 113 | if i > 0 { 114 | i -= 1 115 | } 116 | s.maybeSort() 117 | return s.b[i].Value 118 | } 119 | s.flush() 120 | return s.stream.query(q) 121 | } 122 | 123 | // Merge merges samples into the underlying streams samples. This is handy when 124 | // merging multiple streams from separate threads, database shards, etc. 125 | func (s *Stream) Merge(samples Samples) { 126 | sort.Sort(samples) 127 | s.stream.merge(samples) 128 | } 129 | 130 | // Reset reinitializes and clears the list reusing the samples buffer memory. 131 | func (s *Stream) Reset() { 132 | s.stream.reset() 133 | s.b = s.b[:0] 134 | } 135 | 136 | // Samples returns stream samples held by s. 137 | func (s *Stream) Samples() Samples { 138 | if !s.flushed() { 139 | return s.b 140 | } 141 | s.flush() 142 | s.compress() 143 | return s.stream.samples() 144 | } 145 | 146 | // Count returns the total number of samples observed in the stream 147 | // since initialization. 148 | func (s *Stream) Count() int { 149 | return len(s.b) + s.stream.count() 150 | } 151 | 152 | func (s *Stream) flush() { 153 | s.maybeSort() 154 | s.stream.merge(s.b) 155 | s.b = s.b[:0] 156 | } 157 | 158 | func (s *Stream) maybeSort() { 159 | if !s.sorted { 160 | s.sorted = true 161 | sort.Sort(s.b) 162 | } 163 | } 164 | 165 | func (s *Stream) flushed() bool { 166 | return len(s.stream.l) > 0 167 | } 168 | 169 | type stream struct { 170 | epsilon float64 171 | n float64 172 | l []Sample 173 | ƒ invariant 174 | } 175 | 176 | // SetEpsilon sets the error epsilon for the Stream. The default epsilon is 177 | // 0.01 and is usually satisfactory. If needed, this must be called before all 178 | // Inserts. 179 | // To learn more, see: http://dimacs.rutgers.edu/~graham/pubs/papers/bquant-icde.pdf 180 | func (s *stream) SetEpsilon(epsilon float64) { 181 | s.epsilon = epsilon 182 | } 183 | 184 | func (s *stream) reset() { 185 | s.l = s.l[:0] 186 | s.n = 0 187 | } 188 | 189 | func (s *stream) insert(v float64) { 190 | s.merge(Samples{{v, 1, 0}}) 191 | } 192 | 193 | func (s *stream) merge(samples Samples) { 194 | var r float64 195 | i := 0 196 | for _, sample := range samples { 197 | for ; i < len(s.l); i++ { 198 | c := s.l[i] 199 | if c.Value > sample.Value { 200 | // Insert at position i. 201 | s.l = append(s.l, Sample{}) 202 | copy(s.l[i+1:], s.l[i:]) 203 | s.l[i] = Sample{sample.Value, sample.Width, math.Floor(s.ƒ(s, r)) - 1} 204 | i++ 205 | goto inserted 206 | } 207 | r += c.Width 208 | } 209 | s.l = append(s.l, Sample{sample.Value, sample.Width, 0}) 210 | i++ 211 | inserted: 212 | s.n += sample.Width 213 | } 214 | } 215 | 216 | func (s *stream) count() int { 217 | return int(s.n) 218 | } 219 | 220 | func (s *stream) query(q float64) float64 { 221 | t := math.Ceil(q * s.n) 222 | t += math.Ceil(s.ƒ(s, t) / 2) 223 | p := s.l[0] 224 | r := float64(0) 225 | for _, c := range s.l[1:] { 226 | if r+c.Width+c.Delta > t { 227 | return p.Value 228 | } 229 | r += p.Width 230 | p = c 231 | } 232 | return p.Value 233 | } 234 | 235 | func (s *stream) compress() { 236 | if len(s.l) < 2 { 237 | return 238 | } 239 | x := s.l[len(s.l)-1] 240 | xi := len(s.l) - 1 241 | r := s.n - 1 - x.Width 242 | 243 | for i := len(s.l) - 2; i >= 0; i-- { 244 | c := s.l[i] 245 | if c.Width+x.Width+x.Delta <= s.ƒ(s, r) { 246 | x.Width += c.Width 247 | s.l[xi] = x 248 | // Remove element at i. 249 | copy(s.l[i:], s.l[i+1:]) 250 | s.l = s.l[:len(s.l)-1] 251 | xi -= 1 252 | } else { 253 | x = c 254 | xi = i 255 | } 256 | r -= c.Width 257 | } 258 | } 259 | 260 | func (s *stream) samples() Samples { 261 | samples := make(Samples, len(s.l)) 262 | copy(samples, s.l) 263 | return samples 264 | } 265 | -------------------------------------------------------------------------------- /quantile/exampledata.txt: -------------------------------------------------------------------------------- 1 | 8 2 | 5 3 | 26 4 | 12 5 | 5 6 | 235 7 | 13 8 | 6 9 | 28 10 | 30 11 | 3 12 | 3 13 | 3 14 | 3 15 | 5 16 | 2 17 | 33 18 | 7 19 | 2 20 | 4 21 | 7 22 | 12 23 | 14 24 | 5 25 | 8 26 | 3 27 | 10 28 | 4 29 | 5 30 | 3 31 | 6 32 | 6 33 | 209 34 | 20 35 | 3 36 | 10 37 | 14 38 | 3 39 | 4 40 | 6 41 | 8 42 | 5 43 | 11 44 | 7 45 | 3 46 | 2 47 | 3 48 | 3 49 | 212 50 | 5 51 | 222 52 | 4 53 | 10 54 | 10 55 | 5 56 | 6 57 | 3 58 | 8 59 | 3 60 | 10 61 | 254 62 | 220 63 | 2 64 | 3 65 | 5 66 | 24 67 | 5 68 | 4 69 | 222 70 | 7 71 | 3 72 | 3 73 | 223 74 | 8 75 | 15 76 | 12 77 | 14 78 | 14 79 | 3 80 | 2 81 | 2 82 | 3 83 | 13 84 | 3 85 | 11 86 | 4 87 | 4 88 | 6 89 | 5 90 | 7 91 | 13 92 | 5 93 | 3 94 | 5 95 | 2 96 | 5 97 | 3 98 | 5 99 | 2 100 | 7 101 | 15 102 | 17 103 | 14 104 | 3 105 | 6 106 | 6 107 | 3 108 | 17 109 | 5 110 | 4 111 | 7 112 | 6 113 | 4 114 | 4 115 | 8 116 | 6 117 | 8 118 | 3 119 | 9 120 | 3 121 | 6 122 | 3 123 | 4 124 | 5 125 | 3 126 | 3 127 | 660 128 | 4 129 | 6 130 | 10 131 | 3 132 | 6 133 | 3 134 | 2 135 | 5 136 | 13 137 | 2 138 | 4 139 | 4 140 | 10 141 | 4 142 | 8 143 | 4 144 | 3 145 | 7 146 | 9 147 | 9 148 | 3 149 | 10 150 | 37 151 | 3 152 | 13 153 | 4 154 | 12 155 | 3 156 | 6 157 | 10 158 | 8 159 | 5 160 | 21 161 | 2 162 | 3 163 | 8 164 | 3 165 | 2 166 | 3 167 | 3 168 | 4 169 | 12 170 | 2 171 | 4 172 | 8 173 | 8 174 | 4 175 | 3 176 | 2 177 | 20 178 | 1 179 | 6 180 | 32 181 | 2 182 | 11 183 | 6 184 | 18 185 | 3 186 | 8 187 | 11 188 | 3 189 | 212 190 | 3 191 | 4 192 | 2 193 | 6 194 | 7 195 | 12 196 | 11 197 | 3 198 | 2 199 | 16 200 | 10 201 | 6 202 | 4 203 | 6 204 | 3 205 | 2 206 | 7 207 | 3 208 | 2 209 | 2 210 | 2 211 | 2 212 | 5 213 | 6 214 | 4 215 | 3 216 | 10 217 | 3 218 | 4 219 | 6 220 | 5 221 | 3 222 | 4 223 | 4 224 | 5 225 | 6 226 | 4 227 | 3 228 | 4 229 | 4 230 | 5 231 | 7 232 | 5 233 | 5 234 | 3 235 | 2 236 | 7 237 | 2 238 | 4 239 | 12 240 | 4 241 | 5 242 | 6 243 | 2 244 | 4 245 | 4 246 | 8 247 | 4 248 | 15 249 | 13 250 | 7 251 | 16 252 | 5 253 | 3 254 | 23 255 | 5 256 | 5 257 | 7 258 | 3 259 | 2 260 | 9 261 | 8 262 | 7 263 | 5 264 | 8 265 | 11 266 | 4 267 | 10 268 | 76 269 | 4 270 | 47 271 | 4 272 | 3 273 | 2 274 | 7 275 | 4 276 | 2 277 | 3 278 | 37 279 | 10 280 | 4 281 | 2 282 | 20 283 | 5 284 | 4 285 | 4 286 | 10 287 | 10 288 | 4 289 | 3 290 | 7 291 | 23 292 | 240 293 | 7 294 | 13 295 | 5 296 | 5 297 | 3 298 | 3 299 | 2 300 | 5 301 | 4 302 | 2 303 | 8 304 | 7 305 | 19 306 | 2 307 | 23 308 | 8 309 | 7 310 | 2 311 | 5 312 | 3 313 | 8 314 | 3 315 | 8 316 | 13 317 | 5 318 | 5 319 | 5 320 | 2 321 | 3 322 | 23 323 | 4 324 | 9 325 | 8 326 | 4 327 | 3 328 | 3 329 | 5 330 | 220 331 | 2 332 | 3 333 | 4 334 | 6 335 | 14 336 | 3 337 | 53 338 | 6 339 | 2 340 | 5 341 | 18 342 | 6 343 | 3 344 | 219 345 | 6 346 | 5 347 | 2 348 | 5 349 | 3 350 | 6 351 | 5 352 | 15 353 | 4 354 | 3 355 | 17 356 | 3 357 | 2 358 | 4 359 | 7 360 | 2 361 | 3 362 | 3 363 | 4 364 | 4 365 | 3 366 | 2 367 | 664 368 | 6 369 | 3 370 | 23 371 | 5 372 | 5 373 | 16 374 | 5 375 | 8 376 | 2 377 | 4 378 | 2 379 | 24 380 | 12 381 | 3 382 | 2 383 | 3 384 | 5 385 | 8 386 | 3 387 | 5 388 | 4 389 | 3 390 | 14 391 | 3 392 | 5 393 | 8 394 | 2 395 | 3 396 | 7 397 | 9 398 | 4 399 | 2 400 | 3 401 | 6 402 | 8 403 | 4 404 | 3 405 | 4 406 | 6 407 | 5 408 | 3 409 | 3 410 | 6 411 | 3 412 | 19 413 | 4 414 | 4 415 | 6 416 | 3 417 | 6 418 | 3 419 | 5 420 | 22 421 | 5 422 | 4 423 | 4 424 | 3 425 | 8 426 | 11 427 | 4 428 | 9 429 | 7 430 | 6 431 | 13 432 | 4 433 | 4 434 | 4 435 | 6 436 | 17 437 | 9 438 | 3 439 | 3 440 | 3 441 | 4 442 | 3 443 | 221 444 | 5 445 | 11 446 | 3 447 | 4 448 | 2 449 | 12 450 | 6 451 | 3 452 | 5 453 | 7 454 | 5 455 | 7 456 | 4 457 | 9 458 | 7 459 | 14 460 | 37 461 | 19 462 | 217 463 | 16 464 | 3 465 | 5 466 | 2 467 | 2 468 | 7 469 | 19 470 | 7 471 | 6 472 | 7 473 | 4 474 | 24 475 | 5 476 | 11 477 | 4 478 | 7 479 | 7 480 | 9 481 | 13 482 | 3 483 | 4 484 | 3 485 | 6 486 | 28 487 | 4 488 | 4 489 | 5 490 | 5 491 | 2 492 | 5 493 | 6 494 | 4 495 | 4 496 | 6 497 | 10 498 | 5 499 | 4 500 | 3 501 | 2 502 | 3 503 | 3 504 | 6 505 | 5 506 | 5 507 | 4 508 | 3 509 | 2 510 | 3 511 | 7 512 | 4 513 | 6 514 | 18 515 | 16 516 | 8 517 | 16 518 | 4 519 | 5 520 | 8 521 | 6 522 | 9 523 | 13 524 | 1545 525 | 6 526 | 215 527 | 6 528 | 5 529 | 6 530 | 3 531 | 45 532 | 31 533 | 5 534 | 2 535 | 2 536 | 4 537 | 3 538 | 3 539 | 2 540 | 5 541 | 4 542 | 3 543 | 5 544 | 7 545 | 7 546 | 4 547 | 5 548 | 8 549 | 5 550 | 4 551 | 749 552 | 2 553 | 31 554 | 9 555 | 11 556 | 2 557 | 11 558 | 5 559 | 4 560 | 4 561 | 7 562 | 9 563 | 11 564 | 4 565 | 5 566 | 4 567 | 7 568 | 3 569 | 4 570 | 6 571 | 2 572 | 15 573 | 3 574 | 4 575 | 3 576 | 4 577 | 3 578 | 5 579 | 2 580 | 13 581 | 5 582 | 5 583 | 3 584 | 3 585 | 23 586 | 4 587 | 4 588 | 5 589 | 7 590 | 4 591 | 13 592 | 2 593 | 4 594 | 3 595 | 4 596 | 2 597 | 6 598 | 2 599 | 7 600 | 3 601 | 5 602 | 5 603 | 3 604 | 29 605 | 5 606 | 4 607 | 4 608 | 3 609 | 10 610 | 2 611 | 3 612 | 79 613 | 16 614 | 6 615 | 6 616 | 7 617 | 7 618 | 3 619 | 5 620 | 5 621 | 7 622 | 4 623 | 3 624 | 7 625 | 9 626 | 5 627 | 6 628 | 5 629 | 9 630 | 6 631 | 3 632 | 6 633 | 4 634 | 17 635 | 2 636 | 10 637 | 9 638 | 3 639 | 6 640 | 2 641 | 3 642 | 21 643 | 22 644 | 5 645 | 11 646 | 4 647 | 2 648 | 17 649 | 2 650 | 224 651 | 2 652 | 14 653 | 3 654 | 4 655 | 4 656 | 2 657 | 4 658 | 4 659 | 4 660 | 4 661 | 5 662 | 3 663 | 4 664 | 4 665 | 10 666 | 2 667 | 6 668 | 3 669 | 3 670 | 5 671 | 7 672 | 2 673 | 7 674 | 5 675 | 6 676 | 3 677 | 218 678 | 2 679 | 2 680 | 5 681 | 2 682 | 6 683 | 3 684 | 5 685 | 222 686 | 14 687 | 6 688 | 33 689 | 3 690 | 2 691 | 5 692 | 3 693 | 3 694 | 3 695 | 9 696 | 5 697 | 3 698 | 3 699 | 2 700 | 7 701 | 4 702 | 3 703 | 4 704 | 3 705 | 5 706 | 6 707 | 5 708 | 26 709 | 4 710 | 13 711 | 9 712 | 7 713 | 3 714 | 221 715 | 3 716 | 3 717 | 4 718 | 4 719 | 4 720 | 4 721 | 2 722 | 18 723 | 5 724 | 3 725 | 7 726 | 9 727 | 6 728 | 8 729 | 3 730 | 10 731 | 3 732 | 11 733 | 9 734 | 5 735 | 4 736 | 17 737 | 5 738 | 5 739 | 6 740 | 6 741 | 3 742 | 2 743 | 4 744 | 12 745 | 17 746 | 6 747 | 7 748 | 218 749 | 4 750 | 2 751 | 4 752 | 10 753 | 3 754 | 5 755 | 15 756 | 3 757 | 9 758 | 4 759 | 3 760 | 3 761 | 6 762 | 29 763 | 3 764 | 3 765 | 4 766 | 5 767 | 5 768 | 3 769 | 8 770 | 5 771 | 6 772 | 6 773 | 7 774 | 5 775 | 3 776 | 5 777 | 3 778 | 29 779 | 2 780 | 31 781 | 5 782 | 15 783 | 24 784 | 16 785 | 5 786 | 207 787 | 4 788 | 3 789 | 3 790 | 2 791 | 15 792 | 4 793 | 4 794 | 13 795 | 5 796 | 5 797 | 4 798 | 6 799 | 10 800 | 2 801 | 7 802 | 8 803 | 4 804 | 6 805 | 20 806 | 5 807 | 3 808 | 4 809 | 3 810 | 12 811 | 12 812 | 5 813 | 17 814 | 7 815 | 3 816 | 3 817 | 3 818 | 6 819 | 10 820 | 3 821 | 5 822 | 25 823 | 80 824 | 4 825 | 9 826 | 3 827 | 2 828 | 11 829 | 3 830 | 3 831 | 2 832 | 3 833 | 8 834 | 7 835 | 5 836 | 5 837 | 19 838 | 5 839 | 3 840 | 3 841 | 12 842 | 11 843 | 2 844 | 6 845 | 5 846 | 5 847 | 5 848 | 3 849 | 3 850 | 3 851 | 4 852 | 209 853 | 14 854 | 3 855 | 2 856 | 5 857 | 19 858 | 4 859 | 4 860 | 3 861 | 4 862 | 14 863 | 5 864 | 6 865 | 4 866 | 13 867 | 9 868 | 7 869 | 4 870 | 7 871 | 10 872 | 2 873 | 9 874 | 5 875 | 7 876 | 2 877 | 8 878 | 4 879 | 6 880 | 5 881 | 5 882 | 222 883 | 8 884 | 7 885 | 12 886 | 5 887 | 216 888 | 3 889 | 4 890 | 4 891 | 6 892 | 3 893 | 14 894 | 8 895 | 7 896 | 13 897 | 4 898 | 3 899 | 3 900 | 3 901 | 3 902 | 17 903 | 5 904 | 4 905 | 3 906 | 33 907 | 6 908 | 6 909 | 33 910 | 7 911 | 5 912 | 3 913 | 8 914 | 7 915 | 5 916 | 2 917 | 9 918 | 4 919 | 2 920 | 233 921 | 24 922 | 7 923 | 4 924 | 8 925 | 10 926 | 3 927 | 4 928 | 15 929 | 2 930 | 16 931 | 3 932 | 3 933 | 13 934 | 12 935 | 7 936 | 5 937 | 4 938 | 207 939 | 4 940 | 2 941 | 4 942 | 27 943 | 15 944 | 2 945 | 5 946 | 2 947 | 25 948 | 6 949 | 5 950 | 5 951 | 6 952 | 13 953 | 6 954 | 18 955 | 6 956 | 4 957 | 12 958 | 225 959 | 10 960 | 7 961 | 5 962 | 2 963 | 2 964 | 11 965 | 4 966 | 14 967 | 21 968 | 8 969 | 10 970 | 3 971 | 5 972 | 4 973 | 232 974 | 2 975 | 5 976 | 5 977 | 3 978 | 7 979 | 17 980 | 11 981 | 6 982 | 6 983 | 23 984 | 4 985 | 6 986 | 3 987 | 5 988 | 4 989 | 2 990 | 17 991 | 3 992 | 6 993 | 5 994 | 8 995 | 3 996 | 2 997 | 2 998 | 14 999 | 9 1000 | 4 1001 | 4 1002 | 2 1003 | 5 1004 | 5 1005 | 3 1006 | 7 1007 | 6 1008 | 12 1009 | 6 1010 | 10 1011 | 3 1012 | 6 1013 | 2 1014 | 2 1015 | 19 1016 | 5 1017 | 4 1018 | 4 1019 | 9 1020 | 2 1021 | 4 1022 | 13 1023 | 3 1024 | 5 1025 | 6 1026 | 3 1027 | 6 1028 | 5 1029 | 4 1030 | 9 1031 | 6 1032 | 3 1033 | 5 1034 | 7 1035 | 3 1036 | 6 1037 | 6 1038 | 4 1039 | 3 1040 | 10 1041 | 6 1042 | 3 1043 | 221 1044 | 3 1045 | 5 1046 | 3 1047 | 6 1048 | 4 1049 | 8 1050 | 5 1051 | 3 1052 | 6 1053 | 4 1054 | 4 1055 | 2 1056 | 54 1057 | 5 1058 | 6 1059 | 11 1060 | 3 1061 | 3 1062 | 4 1063 | 4 1064 | 4 1065 | 3 1066 | 7 1067 | 3 1068 | 11 1069 | 11 1070 | 7 1071 | 10 1072 | 6 1073 | 13 1074 | 223 1075 | 213 1076 | 15 1077 | 231 1078 | 7 1079 | 3 1080 | 7 1081 | 228 1082 | 2 1083 | 3 1084 | 4 1085 | 4 1086 | 5 1087 | 6 1088 | 7 1089 | 4 1090 | 13 1091 | 3 1092 | 4 1093 | 5 1094 | 3 1095 | 6 1096 | 4 1097 | 6 1098 | 7 1099 | 2 1100 | 4 1101 | 3 1102 | 4 1103 | 3 1104 | 3 1105 | 6 1106 | 3 1107 | 7 1108 | 3 1109 | 5 1110 | 18 1111 | 5 1112 | 6 1113 | 8 1114 | 10 1115 | 3 1116 | 3 1117 | 3 1118 | 2 1119 | 4 1120 | 2 1121 | 4 1122 | 4 1123 | 5 1124 | 6 1125 | 6 1126 | 4 1127 | 10 1128 | 13 1129 | 3 1130 | 12 1131 | 5 1132 | 12 1133 | 16 1134 | 8 1135 | 4 1136 | 19 1137 | 11 1138 | 2 1139 | 4 1140 | 5 1141 | 6 1142 | 8 1143 | 5 1144 | 6 1145 | 4 1146 | 18 1147 | 10 1148 | 4 1149 | 2 1150 | 216 1151 | 6 1152 | 6 1153 | 6 1154 | 2 1155 | 4 1156 | 12 1157 | 8 1158 | 3 1159 | 11 1160 | 5 1161 | 6 1162 | 14 1163 | 5 1164 | 3 1165 | 13 1166 | 4 1167 | 5 1168 | 4 1169 | 5 1170 | 3 1171 | 28 1172 | 6 1173 | 3 1174 | 7 1175 | 219 1176 | 3 1177 | 9 1178 | 7 1179 | 3 1180 | 10 1181 | 6 1182 | 3 1183 | 4 1184 | 19 1185 | 5 1186 | 7 1187 | 11 1188 | 6 1189 | 15 1190 | 19 1191 | 4 1192 | 13 1193 | 11 1194 | 3 1195 | 7 1196 | 5 1197 | 10 1198 | 2 1199 | 8 1200 | 11 1201 | 2 1202 | 6 1203 | 4 1204 | 6 1205 | 24 1206 | 6 1207 | 3 1208 | 3 1209 | 3 1210 | 3 1211 | 6 1212 | 18 1213 | 4 1214 | 11 1215 | 4 1216 | 2 1217 | 5 1218 | 10 1219 | 8 1220 | 3 1221 | 9 1222 | 5 1223 | 3 1224 | 4 1225 | 5 1226 | 6 1227 | 2 1228 | 5 1229 | 7 1230 | 4 1231 | 4 1232 | 14 1233 | 6 1234 | 4 1235 | 4 1236 | 5 1237 | 5 1238 | 7 1239 | 2 1240 | 4 1241 | 3 1242 | 7 1243 | 3 1244 | 3 1245 | 6 1246 | 4 1247 | 5 1248 | 4 1249 | 4 1250 | 4 1251 | 3 1252 | 3 1253 | 3 1254 | 3 1255 | 8 1256 | 14 1257 | 2 1258 | 3 1259 | 5 1260 | 3 1261 | 2 1262 | 4 1263 | 5 1264 | 3 1265 | 7 1266 | 3 1267 | 3 1268 | 18 1269 | 3 1270 | 4 1271 | 4 1272 | 5 1273 | 7 1274 | 3 1275 | 3 1276 | 3 1277 | 13 1278 | 5 1279 | 4 1280 | 8 1281 | 211 1282 | 5 1283 | 5 1284 | 3 1285 | 5 1286 | 2 1287 | 5 1288 | 4 1289 | 2 1290 | 655 1291 | 6 1292 | 3 1293 | 5 1294 | 11 1295 | 2 1296 | 5 1297 | 3 1298 | 12 1299 | 9 1300 | 15 1301 | 11 1302 | 5 1303 | 12 1304 | 217 1305 | 2 1306 | 6 1307 | 17 1308 | 3 1309 | 3 1310 | 207 1311 | 5 1312 | 5 1313 | 4 1314 | 5 1315 | 9 1316 | 3 1317 | 2 1318 | 8 1319 | 5 1320 | 4 1321 | 3 1322 | 2 1323 | 5 1324 | 12 1325 | 4 1326 | 14 1327 | 5 1328 | 4 1329 | 2 1330 | 13 1331 | 5 1332 | 8 1333 | 4 1334 | 225 1335 | 4 1336 | 3 1337 | 4 1338 | 5 1339 | 4 1340 | 3 1341 | 3 1342 | 6 1343 | 23 1344 | 9 1345 | 2 1346 | 6 1347 | 7 1348 | 233 1349 | 4 1350 | 4 1351 | 6 1352 | 18 1353 | 3 1354 | 4 1355 | 6 1356 | 3 1357 | 4 1358 | 4 1359 | 2 1360 | 3 1361 | 7 1362 | 4 1363 | 13 1364 | 227 1365 | 4 1366 | 3 1367 | 5 1368 | 4 1369 | 2 1370 | 12 1371 | 9 1372 | 17 1373 | 3 1374 | 7 1375 | 14 1376 | 6 1377 | 4 1378 | 5 1379 | 21 1380 | 4 1381 | 8 1382 | 9 1383 | 2 1384 | 9 1385 | 25 1386 | 16 1387 | 3 1388 | 6 1389 | 4 1390 | 7 1391 | 8 1392 | 5 1393 | 2 1394 | 3 1395 | 5 1396 | 4 1397 | 3 1398 | 3 1399 | 5 1400 | 3 1401 | 3 1402 | 3 1403 | 2 1404 | 3 1405 | 19 1406 | 2 1407 | 4 1408 | 3 1409 | 4 1410 | 2 1411 | 3 1412 | 4 1413 | 4 1414 | 2 1415 | 4 1416 | 3 1417 | 3 1418 | 3 1419 | 2 1420 | 6 1421 | 3 1422 | 17 1423 | 5 1424 | 6 1425 | 4 1426 | 3 1427 | 13 1428 | 5 1429 | 3 1430 | 3 1431 | 3 1432 | 4 1433 | 9 1434 | 4 1435 | 2 1436 | 14 1437 | 12 1438 | 4 1439 | 5 1440 | 24 1441 | 4 1442 | 3 1443 | 37 1444 | 12 1445 | 11 1446 | 21 1447 | 3 1448 | 4 1449 | 3 1450 | 13 1451 | 4 1452 | 2 1453 | 3 1454 | 15 1455 | 4 1456 | 11 1457 | 4 1458 | 4 1459 | 3 1460 | 8 1461 | 3 1462 | 4 1463 | 4 1464 | 12 1465 | 8 1466 | 5 1467 | 3 1468 | 3 1469 | 4 1470 | 2 1471 | 220 1472 | 3 1473 | 5 1474 | 223 1475 | 3 1476 | 3 1477 | 3 1478 | 10 1479 | 3 1480 | 15 1481 | 4 1482 | 241 1483 | 9 1484 | 7 1485 | 3 1486 | 6 1487 | 6 1488 | 23 1489 | 4 1490 | 13 1491 | 7 1492 | 3 1493 | 4 1494 | 7 1495 | 4 1496 | 9 1497 | 3 1498 | 3 1499 | 4 1500 | 10 1501 | 5 1502 | 5 1503 | 1 1504 | 5 1505 | 24 1506 | 2 1507 | 4 1508 | 5 1509 | 5 1510 | 6 1511 | 14 1512 | 3 1513 | 8 1514 | 2 1515 | 3 1516 | 5 1517 | 13 1518 | 13 1519 | 3 1520 | 5 1521 | 2 1522 | 3 1523 | 15 1524 | 3 1525 | 4 1526 | 2 1527 | 10 1528 | 4 1529 | 4 1530 | 4 1531 | 5 1532 | 5 1533 | 3 1534 | 5 1535 | 3 1536 | 4 1537 | 7 1538 | 4 1539 | 27 1540 | 3 1541 | 6 1542 | 4 1543 | 15 1544 | 3 1545 | 5 1546 | 6 1547 | 6 1548 | 5 1549 | 4 1550 | 8 1551 | 3 1552 | 9 1553 | 2 1554 | 6 1555 | 3 1556 | 4 1557 | 3 1558 | 7 1559 | 4 1560 | 18 1561 | 3 1562 | 11 1563 | 3 1564 | 3 1565 | 8 1566 | 9 1567 | 7 1568 | 24 1569 | 3 1570 | 219 1571 | 7 1572 | 10 1573 | 4 1574 | 5 1575 | 9 1576 | 12 1577 | 2 1578 | 5 1579 | 4 1580 | 4 1581 | 4 1582 | 3 1583 | 3 1584 | 19 1585 | 5 1586 | 8 1587 | 16 1588 | 8 1589 | 6 1590 | 22 1591 | 3 1592 | 23 1593 | 3 1594 | 242 1595 | 9 1596 | 4 1597 | 3 1598 | 3 1599 | 5 1600 | 7 1601 | 3 1602 | 3 1603 | 5 1604 | 8 1605 | 3 1606 | 7 1607 | 5 1608 | 14 1609 | 8 1610 | 10 1611 | 3 1612 | 4 1613 | 3 1614 | 7 1615 | 4 1616 | 6 1617 | 7 1618 | 4 1619 | 10 1620 | 4 1621 | 3 1622 | 11 1623 | 3 1624 | 7 1625 | 10 1626 | 3 1627 | 13 1628 | 6 1629 | 8 1630 | 12 1631 | 10 1632 | 5 1633 | 7 1634 | 9 1635 | 3 1636 | 4 1637 | 7 1638 | 7 1639 | 10 1640 | 8 1641 | 30 1642 | 9 1643 | 19 1644 | 4 1645 | 3 1646 | 19 1647 | 15 1648 | 4 1649 | 13 1650 | 3 1651 | 215 1652 | 223 1653 | 4 1654 | 7 1655 | 4 1656 | 8 1657 | 17 1658 | 16 1659 | 3 1660 | 7 1661 | 6 1662 | 5 1663 | 5 1664 | 4 1665 | 12 1666 | 3 1667 | 7 1668 | 4 1669 | 4 1670 | 13 1671 | 4 1672 | 5 1673 | 2 1674 | 5 1675 | 6 1676 | 5 1677 | 6 1678 | 6 1679 | 7 1680 | 10 1681 | 18 1682 | 23 1683 | 9 1684 | 3 1685 | 3 1686 | 6 1687 | 5 1688 | 2 1689 | 4 1690 | 2 1691 | 7 1692 | 3 1693 | 3 1694 | 2 1695 | 5 1696 | 5 1697 | 14 1698 | 10 1699 | 224 1700 | 6 1701 | 3 1702 | 4 1703 | 3 1704 | 7 1705 | 5 1706 | 9 1707 | 3 1708 | 6 1709 | 4 1710 | 2 1711 | 5 1712 | 11 1713 | 4 1714 | 3 1715 | 3 1716 | 2 1717 | 8 1718 | 4 1719 | 7 1720 | 4 1721 | 10 1722 | 7 1723 | 3 1724 | 3 1725 | 18 1726 | 18 1727 | 17 1728 | 3 1729 | 3 1730 | 3 1731 | 4 1732 | 5 1733 | 3 1734 | 3 1735 | 4 1736 | 12 1737 | 7 1738 | 3 1739 | 11 1740 | 13 1741 | 5 1742 | 4 1743 | 7 1744 | 13 1745 | 5 1746 | 4 1747 | 11 1748 | 3 1749 | 12 1750 | 3 1751 | 6 1752 | 4 1753 | 4 1754 | 21 1755 | 4 1756 | 6 1757 | 9 1758 | 5 1759 | 3 1760 | 10 1761 | 8 1762 | 4 1763 | 6 1764 | 4 1765 | 4 1766 | 6 1767 | 5 1768 | 4 1769 | 8 1770 | 6 1771 | 4 1772 | 6 1773 | 4 1774 | 4 1775 | 5 1776 | 9 1777 | 6 1778 | 3 1779 | 4 1780 | 2 1781 | 9 1782 | 3 1783 | 18 1784 | 2 1785 | 4 1786 | 3 1787 | 13 1788 | 3 1789 | 6 1790 | 6 1791 | 8 1792 | 7 1793 | 9 1794 | 3 1795 | 2 1796 | 16 1797 | 3 1798 | 4 1799 | 6 1800 | 3 1801 | 2 1802 | 33 1803 | 22 1804 | 14 1805 | 4 1806 | 9 1807 | 12 1808 | 4 1809 | 5 1810 | 6 1811 | 3 1812 | 23 1813 | 9 1814 | 4 1815 | 3 1816 | 5 1817 | 5 1818 | 3 1819 | 4 1820 | 5 1821 | 3 1822 | 5 1823 | 3 1824 | 10 1825 | 4 1826 | 5 1827 | 5 1828 | 8 1829 | 4 1830 | 4 1831 | 6 1832 | 8 1833 | 5 1834 | 4 1835 | 3 1836 | 4 1837 | 6 1838 | 3 1839 | 3 1840 | 3 1841 | 5 1842 | 9 1843 | 12 1844 | 6 1845 | 5 1846 | 9 1847 | 3 1848 | 5 1849 | 3 1850 | 2 1851 | 2 1852 | 2 1853 | 18 1854 | 3 1855 | 2 1856 | 21 1857 | 2 1858 | 5 1859 | 4 1860 | 6 1861 | 4 1862 | 5 1863 | 10 1864 | 3 1865 | 9 1866 | 3 1867 | 2 1868 | 10 1869 | 7 1870 | 3 1871 | 6 1872 | 6 1873 | 4 1874 | 4 1875 | 8 1876 | 12 1877 | 7 1878 | 3 1879 | 7 1880 | 3 1881 | 3 1882 | 9 1883 | 3 1884 | 4 1885 | 5 1886 | 4 1887 | 4 1888 | 5 1889 | 5 1890 | 10 1891 | 15 1892 | 4 1893 | 4 1894 | 14 1895 | 6 1896 | 227 1897 | 3 1898 | 14 1899 | 5 1900 | 216 1901 | 22 1902 | 5 1903 | 4 1904 | 2 1905 | 2 1906 | 6 1907 | 3 1908 | 4 1909 | 2 1910 | 9 1911 | 9 1912 | 4 1913 | 3 1914 | 28 1915 | 13 1916 | 11 1917 | 4 1918 | 5 1919 | 3 1920 | 3 1921 | 2 1922 | 3 1923 | 3 1924 | 5 1925 | 3 1926 | 4 1927 | 3 1928 | 5 1929 | 23 1930 | 26 1931 | 3 1932 | 4 1933 | 5 1934 | 6 1935 | 4 1936 | 6 1937 | 3 1938 | 5 1939 | 5 1940 | 3 1941 | 4 1942 | 3 1943 | 2 1944 | 2 1945 | 2 1946 | 7 1947 | 14 1948 | 3 1949 | 6 1950 | 7 1951 | 17 1952 | 2 1953 | 2 1954 | 15 1955 | 14 1956 | 16 1957 | 4 1958 | 6 1959 | 7 1960 | 13 1961 | 6 1962 | 4 1963 | 5 1964 | 6 1965 | 16 1966 | 3 1967 | 3 1968 | 28 1969 | 3 1970 | 6 1971 | 15 1972 | 3 1973 | 9 1974 | 2 1975 | 4 1976 | 6 1977 | 3 1978 | 3 1979 | 22 1980 | 4 1981 | 12 1982 | 6 1983 | 7 1984 | 2 1985 | 5 1986 | 4 1987 | 10 1988 | 3 1989 | 16 1990 | 6 1991 | 9 1992 | 2 1993 | 5 1994 | 12 1995 | 7 1996 | 5 1997 | 5 1998 | 5 1999 | 5 2000 | 2 2001 | 11 2002 | 9 2003 | 17 2004 | 4 2005 | 3 2006 | 11 2007 | 7 2008 | 3 2009 | 5 2010 | 15 2011 | 4 2012 | 3 2013 | 4 2014 | 211 2015 | 8 2016 | 7 2017 | 5 2018 | 4 2019 | 7 2020 | 6 2021 | 7 2022 | 6 2023 | 3 2024 | 6 2025 | 5 2026 | 6 2027 | 5 2028 | 3 2029 | 4 2030 | 4 2031 | 26 2032 | 4 2033 | 6 2034 | 10 2035 | 4 2036 | 4 2037 | 3 2038 | 2 2039 | 3 2040 | 3 2041 | 4 2042 | 5 2043 | 9 2044 | 3 2045 | 9 2046 | 4 2047 | 4 2048 | 5 2049 | 5 2050 | 8 2051 | 2 2052 | 4 2053 | 2 2054 | 3 2055 | 8 2056 | 4 2057 | 11 2058 | 19 2059 | 5 2060 | 8 2061 | 6 2062 | 3 2063 | 5 2064 | 6 2065 | 12 2066 | 3 2067 | 2 2068 | 4 2069 | 16 2070 | 12 2071 | 3 2072 | 4 2073 | 4 2074 | 8 2075 | 6 2076 | 5 2077 | 6 2078 | 6 2079 | 219 2080 | 8 2081 | 222 2082 | 6 2083 | 16 2084 | 3 2085 | 13 2086 | 19 2087 | 5 2088 | 4 2089 | 3 2090 | 11 2091 | 6 2092 | 10 2093 | 4 2094 | 7 2095 | 7 2096 | 12 2097 | 5 2098 | 3 2099 | 3 2100 | 5 2101 | 6 2102 | 10 2103 | 3 2104 | 8 2105 | 2 2106 | 5 2107 | 4 2108 | 7 2109 | 2 2110 | 4 2111 | 4 2112 | 2 2113 | 12 2114 | 9 2115 | 6 2116 | 4 2117 | 2 2118 | 40 2119 | 2 2120 | 4 2121 | 10 2122 | 4 2123 | 223 2124 | 4 2125 | 2 2126 | 20 2127 | 6 2128 | 7 2129 | 24 2130 | 5 2131 | 4 2132 | 5 2133 | 2 2134 | 20 2135 | 16 2136 | 6 2137 | 5 2138 | 13 2139 | 2 2140 | 3 2141 | 3 2142 | 19 2143 | 3 2144 | 2 2145 | 4 2146 | 5 2147 | 6 2148 | 7 2149 | 11 2150 | 12 2151 | 5 2152 | 6 2153 | 7 2154 | 7 2155 | 3 2156 | 5 2157 | 3 2158 | 5 2159 | 3 2160 | 14 2161 | 3 2162 | 4 2163 | 4 2164 | 2 2165 | 11 2166 | 1 2167 | 7 2168 | 3 2169 | 9 2170 | 6 2171 | 11 2172 | 12 2173 | 5 2174 | 8 2175 | 6 2176 | 221 2177 | 4 2178 | 2 2179 | 12 2180 | 4 2181 | 3 2182 | 15 2183 | 4 2184 | 5 2185 | 226 2186 | 7 2187 | 218 2188 | 7 2189 | 5 2190 | 4 2191 | 5 2192 | 18 2193 | 4 2194 | 5 2195 | 9 2196 | 4 2197 | 4 2198 | 2 2199 | 9 2200 | 18 2201 | 18 2202 | 9 2203 | 5 2204 | 6 2205 | 6 2206 | 3 2207 | 3 2208 | 7 2209 | 3 2210 | 5 2211 | 4 2212 | 4 2213 | 4 2214 | 12 2215 | 3 2216 | 6 2217 | 31 2218 | 5 2219 | 4 2220 | 7 2221 | 3 2222 | 6 2223 | 5 2224 | 6 2225 | 5 2226 | 11 2227 | 2 2228 | 2 2229 | 11 2230 | 11 2231 | 6 2232 | 7 2233 | 5 2234 | 8 2235 | 7 2236 | 10 2237 | 5 2238 | 23 2239 | 7 2240 | 4 2241 | 3 2242 | 5 2243 | 34 2244 | 2 2245 | 5 2246 | 23 2247 | 7 2248 | 3 2249 | 6 2250 | 8 2251 | 4 2252 | 4 2253 | 4 2254 | 2 2255 | 5 2256 | 3 2257 | 8 2258 | 5 2259 | 4 2260 | 8 2261 | 25 2262 | 2 2263 | 3 2264 | 17 2265 | 8 2266 | 3 2267 | 4 2268 | 8 2269 | 7 2270 | 3 2271 | 15 2272 | 6 2273 | 5 2274 | 7 2275 | 21 2276 | 9 2277 | 5 2278 | 6 2279 | 6 2280 | 5 2281 | 3 2282 | 2 2283 | 3 2284 | 10 2285 | 3 2286 | 6 2287 | 3 2288 | 14 2289 | 7 2290 | 4 2291 | 4 2292 | 8 2293 | 7 2294 | 8 2295 | 2 2296 | 6 2297 | 12 2298 | 4 2299 | 213 2300 | 6 2301 | 5 2302 | 21 2303 | 8 2304 | 2 2305 | 5 2306 | 23 2307 | 3 2308 | 11 2309 | 2 2310 | 3 2311 | 6 2312 | 25 2313 | 2 2314 | 3 2315 | 6 2316 | 7 2317 | 6 2318 | 6 2319 | 4 2320 | 4 2321 | 6 2322 | 3 2323 | 17 2324 | 9 2325 | 7 2326 | 6 2327 | 4 2328 | 3 2329 | 10 2330 | 7 2331 | 2 2332 | 3 2333 | 3 2334 | 3 2335 | 11 2336 | 8 2337 | 3 2338 | 7 2339 | 6 2340 | 4 2341 | 14 2342 | 36 2343 | 3 2344 | 4 2345 | 3 2346 | 3 2347 | 22 2348 | 13 2349 | 21 2350 | 4 2351 | 2 2352 | 7 2353 | 4 2354 | 4 2355 | 17 2356 | 15 2357 | 3 2358 | 7 2359 | 11 2360 | 2 2361 | 4 2362 | 7 2363 | 6 2364 | 209 2365 | 6 2366 | 3 2367 | 2 2368 | 2 2369 | 24 2370 | 4 2371 | 9 2372 | 4 2373 | 3 2374 | 3 2375 | 3 2376 | 29 2377 | 2 2378 | 2 2379 | 4 2380 | 3 2381 | 3 2382 | 5 2383 | 4 2384 | 6 2385 | 3 2386 | 3 2387 | 2 2388 | 4 2389 | --------------------------------------------------------------------------------