一键导入
theory
Theoretical background for veb-in-c's design choices — memeff root, bitwise leaves, the O(u)-bits derivation from issue
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
Theoretical background for veb-in-c's design choices — memeff root, bitwise leaves, the O(u)-bits derivation from issue
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
基于 SOC 职业分类
Turn a GitHub issue into a concrete implementation plan for the veb-in-c codebase. Given an issue number, fetch the issue, map it onto the current code, and produce a step-by-step plan with affected files, invariants to preserve, and tests to add. Use when the user wants to start work on a tracked item from ROADMAP.md or the issue tracker.
Pick up a refined GitHub issue and implement it end-to-end using strict red-green-refactor TDD. Creates a branch, cycles through Red/Green/Refactor with one commit per phase, and stops at a green local build. Use when the user hands you a ticket number that has already been through /refine.
Run the SortingBenchmark and report the vEB-sort vs qsort timing comparison. Use when the user wants a perf number after changes to vebtrees.h.
Clean-build the veb-in-c library and run all CTest suites (UnitTests + SortingBenchmark). Use after edits to vebtrees.h or anything under test/, or when the user wants to verify the build is green.
Generate the Doxygen documentation website for veb-in-c and report where the output zip landed. Use when the user wants to refresh docs after public-API or comment changes.
Generate a self-contained handoff prompt for the next Claude session to continue this session's work. Captures issue context, branch state, what's done, what's left, and gotchas. The user copies the output and pastes it as the opening prompt of the next session. Use at the end of a work session — especially when stopping mid-task.
| name | theory |
| description | Theoretical background for veb-in-c's design choices — memeff root, bitwise leaves, the O(u)-bits derivation from issue |
Two optimizations work together to keep the struct footprint sane on small-to-mid universes. Neither is a textbook vEB — both come from #2 and #4.
Scope: vebtree_init is publicly capped at universe_bits ≤ 32 (IPv4 address space). The recursion and bit-math below still reason in terms of arbitrary k, but no realistic k > 32 use case is supported.
Where: is_memeff_root branch at _vebtree_init, vebtrees.h:368.
Textbook vEB splits universe u = 2^k into √u clusters of √u each — so at the root, lower_bits = k/2 and there are 2^(k/2) cluster slots. That's catastrophic at large k: u=32 gives 2^16 slots whose cluster structs are each themselves non-trivial vEB nodes, recurring a handful of levels. Total bits: O(u log log u).
Trick from #2: at the root only, pin lower_bits to log u (in our code: the constant VEBTREE_LEAF_BITS = 6). Then:
2^6 = 64 keys — representable as a single bitboard.2^(k - 6) — one flat layer, no recursion inside clusters.2^(k - 6), recursing normally (√u split) from there.Storage, per #2:
locals: 2^(k-6) structs × 48 B each
global: O(u / log u × log(u / log u)) bits = O(u) bits
The O(u) bits bound holds when lower_bits ≈ log u. We freeze it at 6 for ALU reasons (see §2), so for u ≥ 32 the locals array still explodes — that's the cliff #3's lazy allocation and #19's sparse allocation exist to solve. The root trick shifts the cliff from "impossible at u > ~16" to "impossible at u > ~30", which is the difference between "toy" and "usable on moderate universes."
Where: vebtrees.h:238–280.
Issue #2's original suggestion was to use binary search trees as the local structure (where each local manages O(log u) keys). #4 replaces that with a 64-bit bitboard plus bit-scan intrinsics (__builtin_ctzll / __builtin_clzll / MSVC equivalents). All leaf ops — contains, insert, delete, min, max, successor, predecessor — become O(1) ALU ops, beating a BST's O(log log u) on every dimension: speed, branch-predictability, allocation count (zero per leaf).
Since the memeff root already pins local-size to 6 bits = 64 keys, every locals slot fits in one bitboard. The two tricks are mutually reinforcing: memeff root caps cluster size at the ALU word width exactly because bitwise leaves efficiently fill that width. Change either and you need to rethink the other. #17 proposes widening leaves to 256/512 bits via SIMD — would let memeff root expand to lower_bits = 8 or 9, raising the cliff by 2–3 bits of universe without touching sparsity.
tree->locals[i] is always a leaf at the memeff root. That means sparse cluster storage (#19's job) only has to map cluster_idx → one 48 B leaf, not a recursively-allocated subtree. No deep recursion inside a cluster ever happens at the root layer. This is a huge simplification for the sparse-allocation design.tree->global), lower_bits = upper_bits/2, so clusters there are internal nodes. Any sparse design has to handle both — but the leaf-cluster case is the hot path (it's where every key ultimately lives)._ensure_subtrees still allocates the full 2^(k-6) locals array on the first second-key insert. Lazy helps with "never inserted" and "one-key" cases only. Full cliff removal needs sparse locals (#19).