Search Apps Documentation Source Content File Folder Download Copy Actions Download State String Boolean Number Struct Map Slice Pointer Function Closure Reference Nil Package Type Interface Unknown

countminsketchdemo.gno

4.10 Kb · 120 lines
  1// Package countminsketchdemo is a small gnoweb demo of the frequency sketch
  2// provided by the
  3// [p/moul/x/daily/countminsketch](/p/moul/x/daily/countminsketch/v0) library:
  4// fixed storage, one-sided error, and what a collision looks like.
  5//
  6// It contains no sketch logic of its own. Stateless, so Render is
  7// deterministic — which is precisely what the library is for.
  8package countminsketchdemo
  9
 10import (
 11	"strconv"
 12	"strings"
 13
 14	"gno.land/p/moul/x/daily/countminsketch/v0"
 15)
 16
 17// stream is the workload: a few heavy hitters and a long tail.
 18var stream = buildStream()
 19
 20func buildStream() []string {
 21	var out []string
 22	for i := 0; i < 40; i++ {
 23		out = append(out, "alice")
 24	}
 25	for i := 0; i < 25; i++ {
 26		out = append(out, "bob")
 27	}
 28	for i := 0; i < 10; i++ {
 29		out = append(out, "carol")
 30	}
 31	for i := 0; i < 120; i++ { // the tail: 120 distinct one-offs
 32		out = append(out, "user"+strconv.Itoa(i))
 33	}
 34	return out
 35}
 36
 37// Render renders the demo for gnoweb.
 38func Render(path string) string {
 39	var b strings.Builder
 40	b.WriteString("# Count–Min Sketch\n\n")
 41	b.WriteString("Frequency estimates in fixed space, demoing the ")
 42	b.WriteString("[`p/moul/x/daily/countminsketch`](/p/moul/x/daily/countminsketch/v0) library.\n\n")
 43
 44	b.WriteString("## The workload\n\n")
 45	b.WriteString("`" + strconv.Itoa(len(stream)) + "` events over `123` distinct keys: ")
 46	b.WriteString("three heavy hitters and a long tail of one-offs.\n\n")
 47
 48	big, _ := countminsketch.New(1024, 4)
 49	fill(big)
 50
 51	b.WriteString("## A generously sized sketch (1024 × 4)\n\n")
 52	b.WriteString("| key | true | estimate |\n|---|---|---|\n")
 53	for _, k := range []string{"alice", "bob", "carol", "user0", "never-seen"} {
 54		b.WriteString("| `" + k + "` | " + strconv.Itoa(trueCount(k)) + " | " +
 55			strconv.FormatInt(big.Estimate(k), 10) + " |\n")
 56	}
 57	b.WriteString("\nExact here, and `never-seen` reads `0` — a **zero estimate is ")
 58	b.WriteString("definitive**: that key was never added.\n\n")
 59
 60	tiny, _ := countminsketch.New(8, 2)
 61	fill(tiny)
 62
 63	b.WriteString("## A deliberately tiny one (8 × 2)\n\n")
 64	b.WriteString("Only `" + strconv.Itoa(tiny.Counters()) + "` counters for `123` distinct ")
 65	b.WriteString("keys, so collisions are guaranteed:\n\n")
 66	b.WriteString("| key | true | estimate | error |\n|---|---|---|---|\n")
 67	for _, k := range []string{"alice", "bob", "carol", "user0"} {
 68		est := tiny.Estimate(k)
 69		b.WriteString("| `" + k + "` | " + strconv.Itoa(trueCount(k)) + " | " +
 70			strconv.FormatInt(est, 10) + " | +" +
 71			strconv.FormatInt(est-int64(trueCount(k)), 10) + " |\n")
 72	}
 73	b.WriteString("\nEvery error is **positive**. That is the guarantee: the sketch may ")
 74	b.WriteString("overcount, never undercount, so an estimate is an upper bound — ")
 75	b.WriteString("\"at most this often\", never \"exactly this often\".\n\n")
 76
 77	b.WriteString("## Where the collisions are\n\n")
 78	b.WriteString("Row 0 of the tiny sketch, and the column each key lands in:\n\n")
 79	b.WriteString("| column | counter |\n|---|---|\n")
 80	for c, v := range tiny.Row(0) {
 81		who := []string{}
 82		for _, k := range []string{"alice", "bob", "carol"} {
 83			if tiny.Index(k, 0) == c {
 84				who = append(who, "`"+k+"`")
 85			}
 86		}
 87		line := "| " + strconv.Itoa(c) + " | " + strconv.FormatInt(v, 10)
 88		if len(who) > 0 {
 89			line += " ← " + strings.Join(who, ", ")
 90		}
 91		b.WriteString(line + " |\n")
 92	}
 93	b.WriteString("\nTaking the **minimum** across rows is what limits the damage: an ")
 94	b.WriteString("overestimate needs a collision in *every* row at once.\n\n")
 95
 96	b.WriteString("## Why bother\n\n")
 97	b.WriteString("| | exact map | sketch (1024 × 4) |\n|---|---|---|\n")
 98	b.WriteString("| storage | one entry per distinct key, unbounded | ")
 99	b.WriteString(strconv.Itoa(big.Counters()) + " counters, fixed |\n")
100	b.WriteString("| answer | exact | upper bound |\n")
101	b.WriteString("\nOn chain the second row is the point: storage driven by user input ")
102	b.WriteString("is a liability, and a sketch sized once cannot be made to grow.\n")
103	return b.String()
104}
105
106func fill(s *countminsketch.Sketch) {
107	for _, e := range stream {
108		s.Add(e)
109	}
110}
111
112func trueCount(k string) int {
113	n := 0
114	for _, e := range stream {
115		if e == k {
116			n++
117		}
118	}
119	return n
120}