An open API service indexing awesome lists of open source software.

https://github.com/oz4462/aletheia

Entropy-aware containers for Roaring bitmaps: near-Shannon-H0 space in the dense-irregular regime where Roaring spends a flat 8 KiB, never larger than Roaring, with a faster select. Pure Rust, zero deps, no unsafe.
https://github.com/oz4462/aletheia

bitmap bitmap-index bitset compression data-structures elias-fano entropy-coding information-retrieval roaring roaring-bitmaps rust rust-crate succinct succinct-data-structures zero-dependencies

Last synced: about 3 hours ago
JSON representation

Entropy-aware containers for Roaring bitmaps: near-Shannon-H0 space in the dense-irregular regime where Roaring spends a flat 8 KiB, never larger than Roaring, with a faster select. Pure Rust, zero deps, no unsafe.

Awesome Lists containing this project

README

          

# ๐Ÿ”“ ALETHEIA

### Near-entropy containers for Roaring bitmaps

*aletheia* (แผ€ฮปฮฎฮธฮตฮนฮฑ) โ€” *"unconcealment"*: the 8 KiB a flat bitset hides, revealed.

[![CI](https://github.com/Oz4462/aletheia/actions/workflows/ci.yml/badge.svg)](https://github.com/Oz4462/aletheia/actions/workflows/ci.yml)
[![License: PolyForm--Noncommercial](https://img.shields.io/badge/License-PolyForm--Noncommercial-blue.svg)](LICENSE)
[![unsafe: forbidden](https://img.shields.io/badge/unsafe-forbidden-success.svg)](src/lib.rs)
[![runtime deps: 0](https://img.shields.io/badge/runtime%20deps-0-success.svg)](Cargo.toml)
[![Rust: 1.94+](https://img.shields.io/badge/rust-1.94%2B-orange.svg)](https://www.rust-lang.org)


> ### Up to **4ร— smaller** than Roaring โ€” **never larger** โ€” with a **14ร— faster `select`**.

โ‰ค ยผ


the size
on its worst-case chunks

0ร—


ever larger
mathematically guaranteed

14ร—


faster select
vs a flat bitset

0


runtime deps
pure std ยท no unsafe

---

## โœจ At a glance

- **The problem.** Roaring stores any 2ยนโถ chunk with cardinality > 4096 as a **flat, uncompressed 8 KiB bitset** โ€” no matter how compressible the chunk is. In the *dense-but-irregular* band (โ‰ˆ10 % or โ‰ˆ90 % full) that's **2โ€“4ร— bigger than the Shannon entropy floor**, and Roaring has no smaller option.
- **The fix.** ALETHEIA adds two **Elias-Fano** encodings โ€” of the set positions *and* of the complement โ€” as extra candidates, and keeps the smallest per chunk.
- **The guarantee.** Its candidate set is a **strict superset** of Roaring's, so the result is **never larger than Roaring** โ€” and *strictly smaller* across the whole dense-irregular band.
- **The proof.** Every claim is backed by reproducible, CPU-only, zero-dependency tests โ€” including an independent cross-check against the real [`roaring`](https://crates.io/crates/roaring) crate's actual serialized bytes.

```rust
use aletheia::Container;

// a dense-but-irregular chunk Roaring would store as a flat 8 KiB bitset
let values: Vec = (0u16..65_535).step_by(7).collect();
let c = Container::from_sorted(&values);

assert!(c.size_bytes() < 8192); // โ† Roaring spends a full 8192 here
```

---

An **entropy-aware container** for Roaring-style bitmaps. It closes a real,
literature-grounded gap: Roaring stores any 2ยนโถ chunk with cardinality > 4096
as a **flat, uncompressed 8 KiB bitset**, no matter the chunk's entropy. In the
dense-but-irregular regime (too many runs for a run container, too dense for an
array) that bitset can be 2โ€“4ร— larger than the Shannon-Hโ‚€ floor โ€” and Roaring
has no smaller option there.

ALETHEIA adds two Elias-Fano candidate encodings (of the set positions, and of
the **complement** for the symmetric high-density tail) to the container
selector and keeps the smallest representation per chunk. Because the candidate
set is a strict superset of Roaring's (array, run, bitset **+** EF-set,
EF-clear), the result is **never larger than the container Roaring would
choose**, and strictly smaller across the dense-irregular band.

## ๐Ÿ‘ฅ Who is this for?

Anyone who stores **large sets of integer IDs** with Roaring and is **memory- or
storage-bound** โ€” and whose access pattern leans on `select`/`rank`/`iterate`
rather than point membership:

| Domain | Typical use |
|---|---|
| ๐Ÿ”Ž **Search engines** (Lucene, Elasticsearch, Solr) | inverted-index posting lists โ€” "which documents contain term *X*" |
| ๐Ÿ“Š **Analytical / OLAP databases** (Druid, ClickHouse, Pinot) | bitmap indexes & fast filters over billions of rows |
| โšก **Big-data engines** (Spark) | set operations over huge ID sets |
| ๐Ÿšฉ **Feature flags / permissions** | "which users are in segment *Y*" |

Best fit: **medium-cardinality columns** with many chunks in the dense-irregular
band, where shrinking each chunk means more fits in cache/RAM and less I/O.
**Not the goal:** membership-heavy hot loops โ€” see the honest speed tradeoff below.

## ๐Ÿš€ Quickstart

```toml
[dependencies]
aletheia = { git = "https://github.com/Oz4462/aletheia" }
```

```rust
use aletheia::Container;

// a dense-but-irregular chunk Roaring would store as a flat 8 KiB bitset
let values: Vec = (0u16..65_535).step_by(7).collect();
let c = Container::from_sorted(&values);

assert!(c.contains(7));
assert_eq!(c.iter().len(), c.cardinality() as usize);
println!("{} bytes (Roaring would use 8192)", c.size_bytes());
```

> **Tip:** `from_sorted` trusts that its input is sorted & distinct (the fast
> path). If you're not sure, use `Container::from_values`, which sorts and
> de-duplicates for you.

### Full `u32` bitmap, set operations & serialization

```rust
use aletheia::Bitmap;

let a = Bitmap::from_values(&[1, 2, 3, 1_000_000, 5_000_000]);
let b = Bitmap::from_values(&[3, 4, 1_000_000]);

assert_eq!((&a & &b).to_vec(), vec![3, 1_000_000]); // โˆฉ (operators or .and())
assert_eq!((&a | &b).cardinality(), 6); // โˆช
assert_eq!((&a ^ &b).to_vec(), vec![1, 2, 4, 5_000_000]);
assert_eq!((&a - &b).to_vec(), vec![1, 2, 5_000_000]);

// rank / select / mutation over the whole u32 universe
assert_eq!(a.rank(1_000_000), 3);
assert_eq!(a.select(0), Some(1));
let mut m = a.clone();
m.insert(7);
m.remove(2);

// ALETHEIA's own compact format (validated: malformed bytes are refused
// with a DecodeError naming the violated check โ€” never a panic)
let bytes = a.serialize();
assert_eq!(Bitmap::deserialize(&bytes).unwrap(), a);

// the official Roaring interop format โ€” byte-identical to what
// roaring-rs itself writes, readable by every Roaring implementation
let portable = a.serialize_portable();
assert_eq!(Bitmap::deserialize_portable(&portable).unwrap(), a);
```

`Bitmap` is the Roaring-shaped wrapper: one entropy-aware `Container` per 2ยนโถ
chunk, so the never-larger-than-Roaring guarantee holds chunk by chunk.
Both deserializers validate everything (magic/version, per-container
structure, cardinality cross-checks, ordering) and refuse malformed input
with a typed `DecodeError` โ€” never a panic, never attacker-driven allocation.

## ๐Ÿ“ Verified result (reproducible, CPU-only, zero dependencies)

**Space** โ€” `cargo run --release --example space_report`:

| density | card | roaring | aletheia | kind | ratio | Hโ‚€ floor |
|--------:|------:|--------:|---------:|---------|------:|---------:|
| 0.065 | 4260 | 8192 | **3259** | EfSet | 2.51ร— | 2843 |
| 0.111 | 7260 | 8192 | **4783** | EfSet | 1.71ร— | 4115 |
| 0.199 | 13073 | 8192 | 7187 | EfSet | 1.14ร— | 5906 |
| 0.299 | 19575 | 8192 | 8192 | Bitset | 1.00ร— | 7207 |
| 0.496 | 32525 | 8192 | 8192 | Bitset | 1.00ร— | 8192 |
| 0.851 | 55750 | 8192 | **5931** | EfClear | 1.38ร— | 4982 |
| 0.935 | 61305 | 8192 | **3244** | EfClear | 2.53ร— | 2829 |
| 0.964 | 63147 | 8192 | **2062** | EfClear | 3.97ร— | 1850 |
| 0.985 | 64583 | 3766ยน | **982** | EfClear | 3.84ร— | 898 |

ยน at this density Roaring picks a *run* container (3766 B), not a bitset โ€”
ALETHEIA still beats it 3.84ร—. The container tracks the Hโ‚€ floor to within
~10โ€“16% across the band, and degrades to exactly Roaring's bitset (1.00ร—, never
worse) in the middle.

**Speed** โ€” `cargo run --release --example speed_report` (card 6486, dโ‰ˆ0.10,
min-of-7):

> ๐Ÿ’ก **The tradeoff in one line:** ALETHEIA is a *different Pareto point*, not a
> free lunch โ€” **smaller and far faster at `select`**, at the cost of slower
> point membership.

| op | aletheia | bitset | factor |
|----------|---------:|--------:|-----------------|
| contains | ~73 ns | ~1.6 ns | **~45ร— slower** |
| select | ~60 ns | ~893 ns | **~15ร— faster** |
| iter | ~4.6 ns | ~2.2 ns | ~2ร— slower |

(Numbers swing between runs on a clock-scaling CPU; min-of-7 methodology,
fresh run 2026-07-04 โ€” full tables with machine info in `docs/CLAIMS.md`.)
`contains` started at 176 ns and a single-`select0` fast path brought it to
`select`-parity โ€” both are now dominated by one directory lookup. Set
operations cost ~0.4โ€“1.1 ms per 2ยนโถ chunk (materialize + full re-selection โ€”
the documented single-code-path trade-off).

This is the honest tradeoff, not a hidden one: ALETHEIA is a **different Pareto
point**, not a free lunch. It is smaller *and* dramatically faster at `select`
(Roaring's bitset `select` is an O(U) popcount scan), at the cost of ~40ร— slower
membership (a directory lookup vs a flat bit test). It fits memory-constrained,
select-/rank-/iterate-heavy, membership-light workloads โ€” e.g. bitmap-index
posting lists on medium-cardinality columns.

## โœ… Correctness

`cargo test` runs a deterministic splitmix64 fuzz oracle that verifies every
`contains`/`rank`/`select`/`iter` against a brute-force `Vec` truth table
across the **full 65536-value universe** for ~110 configurations (all
densities, uniform + clustered + edge cases), and asserts the never-larger-than-
Roaring guarantee on every one. `space_win.rs` additionally asserts the โ‰ฅ1.5ร—
win at the band edges, so CI fails if any change erases it. A failure prints the
exact seed to replay.

As a second, independent witness, `roaring_crosscheck.rs` checks every
cardinality, full-universe membership, iteration, and set-operation result
against the real `roaring` crate (roaring-rs โ€” a separate codebase), and
confirms never-larger against its *actual serialized output* โ€” including a
whole-bitmap footprint check (the measured edge-band ratios, 1.2ร—โ€“6.5ร— on
the current run, are printed by the test; the CI-gated bound is
never-larger plus the โ‰ฅ1.5ร— band-edge floor in `space_win.rs`). (`roaring` is a dev-only dependency; the
library itself stays pure std with zero runtime dependencies.)

Beyond that: `setops_oracle.rs` proves never-larger **after every set
operation** across an 8ร—8 density grid; `malformed.rs` fuzzes both
deserializers with random buffers, single-byte mutations of every container
kind, and every truncation point (refusal or provable self-consistency,
never a panic); `portable.rs` holds the interop format **byte-identical**
to roaring-rs's own output across eight shapes and round-trips both
directions. The full claimโ†’evidence map is `docs/CLAIMS.md`.

```
cargo test # correctness + win assertions
cargo test --test roaring_crosscheck -- --nocapture # vs real roaring-rs
cargo clippy --all-targets -- -D warnings # lint-clean
cargo run --release --example space_report # the space table above
cargo run --release --example speed_report # the honest cost table above
```

## ๐Ÿ”ฌ How it works

A value `v` splits into `high = v >> l` and `l` low bits. Low bits are packed;
high bits are a count-unary bitvector (`m + max_high + 1` bits) with a coarse
512-bit-block prefix-popcount directory for near-constant-time `select1`,
`select0` and `rank1`. With `l = floor(log2(U/m))` the structure sits within a
couple of bits per element of the Hโ‚€ floor. The complement variant captures the
high-density tail symmetrically.

## ๐Ÿ—บ๏ธ Scope

This started as an MVP proving the invention with exact, unfakeable numbers; it
now also ships the bitmap machinery built on top of it.

**Done in v0.2.0:**
* **Set operations** โ€” `and` / `or` / `xor` / `andnot` (+ `& | ^ -` operator
traits) on both `Container` and `Bitmap`, via materialize-to-bitset with the
result re-run through the full selector (so the never-larger guarantee holds
on results too โ€” proven per-op by `tests/setops_oracle.rs`).
* **Multi-chunk `Bitmap`** โ€” the Roaring-shaped `u32` wrapper: one container per
2ยนโถ chunk, with `contains` / `rank` / `select` / `min` / `max`, mutation
(`insert` / `remove` with automatic encoding re-selection), lazy iteration,
and the std traits (`FromIterator`, `Extend`, `IntoIterator`, `PartialEq`).
* **Native serialization** โ€” a compact, self-describing, versioned byte format
(magic `ALTH`) for both `Container` and `Bitmap`. Deserialization validates
every structural invariant and cross-checks the stored cardinality against
the payload; malformed input is refused with a typed `DecodeError`, never a
panic, and untrusted lengths never drive allocation (fuzz-proven).
* **Roaring-portable serialization** โ€” the official RoaringFormatSpec,
**byte-identical** to what roaring-rs writes (golden-tested) and readable by
every Roaring implementation; the validating reader re-selects each chunk
back into ALETHEIA's smallest encoding.
* **`SparseVec`** โ€” compressed `u32` indices paired with values, for sparse
workloads (see below). Optional `serde` / `serde_bincode` features (default
build stays zero-dependency).
* **Cross-checked** โ€” `Bitmap` and every set operation are validated against the
real `roaring` crate over the full `u32` universe, not just our own oracle.

**Done since v0.1.0:** a single-`select0` `contains` fast path (176 ns โ†’ ~73 ns);
a hardened `EliasFano::select` (bounds-checked rather than spinning on an
out-of-range index).

**Measured & rejected:**
* A BMI2 `PDEP` broadword `select_in_u64` โ€” 2.8ร— *slower* than the naive
clear-lowest-bit loop here (per-call feature dispatch plus the
`#[target_feature]` inlining barrier outweigh `PDEP`; within-word select is
only ~15 ns of a ~67 ns `select` โ€” the directory block search is the floor).
* An **RRR candidate** for the mid-band โ€” the math doesn't pay off. At dโ‰ˆ0.3,
15-bit RRR blocks cost ~9.4 KB (the 4-bit-per-block class header dominates),
*worse* than the flat 8 KB bitset; even 63-bit blocks reach only ~8.0 KB, a
~2 % win that a sampled rank/select directory erases. Where the bitset already
ties the Hโ‚€ floor (dโ‰ˆ0.5) RRR can't help at all. Not worth the complexity for a
break-even encoding โ€” revisit only with a fundamentally cheaper class coding.
Re-measured rigorously against a pre-registered rule (63-bit blocks,
combinadic offsets, a directory every 32 blocks; full uniform density
sweep, 3 seeds/step): win peaked at 12.7% (dโ‰ˆ0.76), but the widest
contiguous โ‰ฅ10%-win band was only 0.04 wide against the pre-registered
0.05 threshold โ€” rejected on the numbers; full sweep in `docs/DECISIONS.md`.

**Out of scope** (deliberately, with reasons in `docs/DECISIONS.md` and
`docs/AUDIT.md` ยง6): the Roaring 64-bit extension format, SIMD (`unsafe` is
forbidden), specialized non-materializing set-op kernels, in-library
parallelism.

## ๐Ÿง  Sparse indices for LLM / agent workloads

`SparseVec` pairs a compressed `Bitmap` index set with a parallel value
array โ€” positions compress toward the entropy floor, values stay contiguous:

```rust
use aletheia::SparseVec;

// pruned weights: (index, value) pairs in any order
let sv = SparseVec::from_pairs(vec![(7u32, 0.5f32), (1 << 20, 0.25), (42, 0.9)]);
assert_eq!(sv.len(), 3);
assert_eq!(sv.get(1), Some((42, &0.9))); // i-th pair, index order
let total: f32 = sv.iter().map(|(_, v)| v).sum(); // lazy iteration
```

Typical fits: pruned LLM weight matrices (>90 % sparse), sparse KV-cache
positions, MoE routing masks, large agent memory ID sets โ€” build once, then
`select`/`rank`/iterate on the compressed form.

## ๐Ÿ“ฆ Optional features

| Feature | Adds | Default |
|---|---|---|
| *(none)* | the whole library โ€” pure std, zero dependencies | โœ… |
| `serde` | `Serialize`/`Deserialize` for `Bitmap` + `SparseVec` (value-list representation; hostile input is validated, never trusted) | off |
| `serde_bincode` | `SparseVec::to_bytes` / `from_bytes` (both return `Result` โ€” no silent failure) | off |

## ๐Ÿ” Audit trail

Written to be walked file-by-file by an external reviewer:

| Document | Contents |
|---|---|
| [`docs/AUDIT.md`](docs/AUDIT.md) | the ~90-minute verification runbook, incl. a falsify-each-claim attack table |
| [`docs/CLAIMS.md`](docs/CLAIMS.md) | every claim โ†’ reproduction command โ†’ guarding test โ†’ last measured value |
| [`docs/ARCHITECTURE.md`](docs/ARCHITECTURE.md) | file-by-file walkthrough, exact byte layouts, data flow, cost model |
| [`docs/DECISIONS.md`](docs/DECISIONS.md) | every non-obvious choice with alternatives and evidence โ€” incl. the full RRR rejection experiment |

## ๐Ÿ“„ License

[PolyForm Noncommercial 1.0.0](LICENSE), ยฉ Ozan Kuesmez. In short: the
source is open; use, modify, and share freely for **any noncommercial
purpose** (personal projects, research, education, evaluation โ€” charities
and public institutions included). **Commercial use requires a separate
license โ€” just ask** (GitHub issue or profile contact). Copyright and
ownership remain with the author; required notices must be preserved.
Dual licensing: one codebase, free for the community, licensed for
business.

Built in Rust ๐Ÿฆ€ ยท zero runtime dependencies ยท #![forbid(unsafe_code)]