Files
wehub-resource-sync a06f331eb8
CI / benchmark (push) Has been skipped
install-script / posix-syntax (push) Successful in 6m1s
CI / build-onnx (push) Failing after 6m43s
init-smoke / dry-run (push) Failing after 15m57s
security / govulncheck (push) Has been cancelled
security / trivy-fs (push) Has been cancelled
CI / test (1.26, ubuntu-latest) (push) Has been cancelled
Scorecard supply-chain security / Scorecard analysis (push) Has been cancelled
CI / test (1.26, macos-latest) (push) Has been cancelled
CI / build-windows (push) Has been cancelled
CI / lint (push) Has been cancelled
install-script / powershell-syntax (push) Has been cancelled
install-script / install (macos-14) (push) Has been cancelled
install-script / install (ubuntu-latest) (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 12:33:42 +08:00

143 lines
4.5 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package clones
import (
"encoding/binary"
"math/bits"
)
// CMS is a Count-Min Sketch over uint64 keys: a probabilistic
// frequency estimator with one-sided error — Count(x) ≥ true(x), never
// less. We use it on shingle-hash frequencies across a function-body
// corpus to identify boilerplate (shingles present in many bodies)
// before MinHash signature computation, so signatures reflect
// discriminative content rather than shared-API-pattern noise that
// drives LSH bucket explosions at monorepo scale.
//
// Sizing the sketch:
//
// ε = e/w (additive error coefficient over total N adds)
// δ = (1/2)^d (probability the bound is exceeded)
// bound: Pr[Count(x) > true(x) + εN] ≤ δ
//
// We default to width=65536, depth=4 (1 MB) which gives ε ≈ 0.00004,
// so on a k8s-scale corpus of ~7.5M total Add calls the error is
// bounded at ~300 with 94% confidence — well below the typical
// boilerplate threshold of ~1500 (1% of 150k function bodies). At
// vscode scale the corpus is smaller and the error bound stays
// proportionally tight.
//
// The sketch is fully deterministic: hash seeds derive from a fixed
// xorshift64* state, so two runs over the same corpus produce
// identical counts — signature output is reproducible across daemon
// restarts and across snapshot reuse.
type CMS struct {
width, depth int
mask uint64
counts [][]uint32
seeds []uint64
}
// NewCMS constructs an empty CMS with the requested width × depth.
// width is rounded up to the next power of two so the modulo can be
// a bitmask. depth ≤ 0 defaults to 4. Memory cost: 4 × width × depth
// bytes.
func NewCMS(width, depth int) *CMS {
if width <= 0 {
width = 65536
}
if depth <= 0 {
depth = 4
}
// Round width up to the next power of two.
if width&(width-1) != 0 {
shift := bits.Len(uint(width))
width = 1 << shift
}
cms := &CMS{
width: width,
depth: depth,
mask: uint64(width - 1),
counts: make([][]uint32, depth),
seeds: make([]uint64, depth),
}
// Deterministic seed family: same xorshift64* pattern minhash.go's
// hashParams uses, with a CMS-specific constant so the two
// sketches don't share derived seeds.
state := uint64(0xCEFCC9F3D741F271)
next := func() uint64 {
state ^= state >> 12
state ^= state << 25
state ^= state >> 27
return state * 0x2545F4914F6CDD1D
}
for i := range cms.counts {
cms.counts[i] = make([]uint32, width)
cms.seeds[i] = next()
}
return cms
}
// Add increments the counters for x by one across every hash row.
// Saturating at uint32 max — at our scale (≤ 8M total adds) saturation
// is unreachable, but the check costs nothing in the common case.
func (c *CMS) Add(x uint64) {
for i := 0; i < c.depth; i++ {
idx := cmsHash(x, c.seeds[i]) & c.mask
if c.counts[i][idx] < ^uint32(0) {
c.counts[i][idx]++
}
}
}
// Decrement decreases the counters for x by one across every hash row,
// flooring each at 0: a counter already at 0 is left untouched. It is
// the inverse of Add for incremental maintenance — when a body leaves
// the corpus its shingle hashes are decremented so the boilerplate
// estimate tracks the live set instead of growing monotonically.
//
// Decrementing a key that was never added is a no-op (every row sits
// at 0 already, or sits at some other key's count that this row shares
// — flooring at 0 keeps those undamaged). Because hash collisions can
// leave a row's counter above this key's true frequency, Count stays an
// upper bound after Decrement just as it is after Add; decrement never
// makes Count drop below the true count.
func (c *CMS) Decrement(x uint64) {
for i := 0; i < c.depth; i++ {
idx := cmsHash(x, c.seeds[i]) & c.mask
if c.counts[i][idx] > 0 {
c.counts[i][idx]--
}
}
}
// Count returns the minimum across all hash rows — the canonical CMS
// frequency estimate. The result is an upper bound on the true count.
func (c *CMS) Count(x uint64) uint32 {
minCount := ^uint32(0)
for i := 0; i < c.depth; i++ {
idx := cmsHash(x, c.seeds[i]) & c.mask
if c.counts[i][idx] < minCount {
minCount = c.counts[i][idx]
}
}
return minCount
}
// cmsHash is an inline FNV-1a over the (key, seed) pair. Kept tight
// because every Add/Count touches it depth times.
func cmsHash(x, seed uint64) uint64 {
const (
offset = uint64(14695981039346656037)
prime = uint64(1099511628211)
)
var buf [16]byte
binary.LittleEndian.PutUint64(buf[:8], x)
binary.LittleEndian.PutUint64(buf[8:], seed)
h := offset
for _, b := range buf {
h ^= uint64(b)
h *= prime
}
return h
}