Commit graph

4 commits

Author SHA1 Message Date
73e7e39b52 feat: SQ4 (4-bit) scalar quantization + native distance hook (2.5.0 #30)
Brainy now has a complete reference SQ4 (4-bit per dimension, 8× compression
vs float32) quantization layer in src/utils/vectorQuantization.ts: quantizeSQ4,
dequantizeSQ4, distanceSQ4Js, serializeSQ4, deserializeSQ4 — all byte-for-byte
identical to cortex's Rust quantize_sq4 / dequantize_sq4 / cosine_distance_sq4.

The pack format mirrors cortex exactly:
- Two nibbles per byte. High nibble = vector[2i], low nibble = vector[2i+1].
- Odd-dim vectors place the final value in the high nibble and pad the low
  nibble with 0. Packed length = ceil(dim / 2).
- Zero-range vectors (all values identical) map every nibble to 8 (midpoint
  of [0, 15]) — both reference impls produce 0x88 bytes.

The active-fn dispatch pattern matches SQ8: distanceSQ4Js is the pure-JS
reference; distanceSQ4 routes through a swappable activeSQ4Distance slot;
setSQ4DistanceImplementation(fn) swaps in cortex's SIMD Rust distance when the
distance:sq4 provider is registered. brainy.ts wires the provider in init,
same shape as the existing SQ8 wiring (~14 LOC). The dispatch path is the
single point of integration so HNSW search code never needs to know whether
it's running on JS or native.

Serialization adds a uint32 dim field after min/max (12-byte header total) —
SQ8 doesn't need it because the packed length equals dim, but SQ4's packed
length rounds up so dim must be recorded explicitly to disambiguate the
trailing pad nibble.

Tests (1462 total, +15):
- Pack format: high-nibble-first, odd-dim trailing pad = 0, ceil(dim/2) length
- Round-trip error envelope: every reconstructed value within half a quantum
  step of the original (verified across dims 1, 2, 3, 4, 16, 17, 384, 385, 1000)
- Edge cases: empty input throws, zero-range maps to 0x88, out-of-range
  clamping
- distanceSQ4Js agreement with dequantize-then-cosine baseline within 1e-9
- dispatch swap (setSQ4DistanceImplementation): swap in a sentinel fn, observe
  the active fn changes, restore the JS default, observe the revert
- serialize/deserialize round-trip preserves all four fields byte-for-byte for
  both even and odd dim

The HNSW SQ4 reranking path (bits === 4 routing in HNSWIndex's quantization
config) is wired to use distanceSQ4 — when cortex's distance:sq4 provider
is registered, that hot path immediately becomes native SIMD with zero brainy
change required. Cross-language byte-format parity tests run in the cortex
test suite (paired release brainy 7.28.0 + cortex 2.5.0).
2026-05-28 12:27:10 -07:00
6099101336 docs: remove stale distanceSQ8 JSDoc left by the SQ8 hook refactor
The native SQ8 distance hook renamed the original distanceSQ8 to distanceSQ8Js
and added a dispatcher in its place, but left the old function's doc block
orphaned above distanceSQ8Js (two consecutive comments, the first dangling).
Merge them into one accurate block on distanceSQ8Js with dash-notation params.
2026-05-27 15:21:46 -07:00
00d14cfa93 feat: hook native SQ8 distance provider into HNSW reranking
Makes distanceSQ8 swappable via setSQ8DistanceImplementation and wires brainy.ts to
install a registered 'distance:sq8' provider (e.g. cortex's Rust SIMD), with the JS
distanceSQ8Js as the default fallback. The provider signature is byte-compatible with
the native cosineDistanceSq8, so HNSW SQ8 reranking transparently uses native distance
when cortex is loaded. Native==JS numeric equivalence is asserted by the cross-language
parity suite.
2026-05-27 12:43:29 -07:00
0f3a88429d feat: add SQ8 vector quantization, lazy loading, and two-phase rerank to HNSW
- SQ8 scalar quantization (8-bit) for 4x vector storage reduction
- Lazy vector loading: evict float32 vectors after graph construction,
  load on-demand from storage via UnifiedCache
- Two-phase search: over-retrieve with SQ8 approximate distances,
  rerank top candidates with exact float32 distances
- Configuration surface: hnsw.quantization and hnsw.vectorStorage in BrainyConfig
- All features disabled by default (zero behavior change for existing users)
- 27 new tests covering quantization accuracy, lazy loading, reranking
- Remove GitHub Actions CI (build locally, cortex CI handles native builds)
2026-01-31 12:41:53 -08:00