Skip to content Search Apps Documentation Source Content File Folder Download Copy Actions 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}