# iqdb-quantize v0.4.0 — Binary Quantization + Feature Freeze
**The last scheme lands, and the surface freezes.** v0.4.0 adds binary quantization (BQ, 32× compression), completing the three-scheme set behind the `Quantizer` trait. With SQ8, PQ, and BQ all present and asymmetric distance implemented for each, the public API is declared **feature frozen** — no new public items before 1.0.
## What is iqdb-quantize?
The memory-efficiency layer of the iQDB vector database — scalar (SQ8, 4×), product (PQ, up to 192×), and binary (BQ, 32×) quantization behind one `Quantizer` trait, with distance computed directly on the compressed form.
## What's new in 0.4.0
### `BinaryQuantizer` (BQ)
One bit per dimension, thresholded against a trained per-dimension mean: the bit is `1` when the component is at or above the mean, `0` otherwise. Bits pack into `Vec<u64>` words, and the unused high bits of the trailing word are always zero, so they cannot contribute to Hamming distance. BQ is the highest-compression scheme — 32× — and is scored directly on the packed words via XOR + popcount.
```rust
use iqdb_quantize::{BinaryQuantizer, Quantizer};
use iqdb_types::DistanceMetric;
let mut bq = BinaryQuantizer::new();
bq.train(&[&[0.0_f32, 1.0, 2.0][..], &[2.0_f32, 1.0, 0.0][..]]).expect("ok");
let code = bq.quantize(&[0.5_f32, 1.5, 2.5]).expect("dim matches");
assert_eq!(code.dim(), 3);
assert_eq!(code.as_words().len(), 1); // 3 bits fit in one u64 word
let d = bq
.distance(&[0.5_f32, 1.5, 2.5], &code, DistanceMetric::Hamming)
.expect("Hamming is supported");
assert!(d.is_finite());
```
BQ supports `DistanceMetric::Hamming` **only**; every other metric returns `IqdbError::InvalidMetric` — a one-bit code carries no magnitude for a Euclidean or dot-product comparison.
### `BqCode` — owned and immutable
The packed `u64` words plus the original dimension, produced only by `BinaryQuantizer::quantize`, with `dim`, `is_empty`, and `as_words` accessors and no public mutators.
## Feature freeze
The public surface is now **complete and frozen for 1.x** — additive, non-breaking changes remain allowed, anything else waits for 2.0:
- Trait: `Quantizer` (`Quantized`, `train`, `quantize`, `dequantize`, `distance`).
- Quantizers: `ScalarQuantizer`, `BinaryQuantizer`, `ProductQuantizer`.
- Codes: `Sq8Code`, `BqCode`, `PqCode`.
- Batch ADC: `PqAdcTables`, `ProductQuantizer::build_query_tables`.
- Constant: `VERSION`.
There is no `todo!` or `unimplemented!` anywhere in shipping code. PQ `Cosine` stays intentionally unsupported (no per-subvector global norm; L2-normalize and use `DotProduct`) — a settled decision, not a deferral.
## Breaking changes
**Pre-1.0 API churn.** Everything here is additive over 0.3.0. No existing item changed shape.
## Verification
BQ adds property tests asserting the packed-word Hamming distance matches a naive per-dimension popcount reference, and that distance is finite and non-negative for every valid pair. The full gate runs on the CI matrix on stable and the 1.87 MSRV:
```bash
cargo fmt --all -- --check
cargo clippy --all-targets --all-features -- -D warnings
cargo test --all-features
RUSTDOCFLAGS="-D warnings" cargo doc --no-deps --all-features
```
MSRV: Rust 1.87.
## What's next
- **v0.5.0 — recall validation + API freeze.** End-to-end recall measured against full-`f32` baselines, training instrumented through `tracing`, a criterion bench harness, and the public API locked for the 1.x series.
## Installation
```toml
[dependencies]
iqdb-quantize = "0.4"
```
## Documentation
- [README](https://github.com/jamesgober/iqdb-quantize/blob/main/README.md)
- [API reference](https://github.com/jamesgober/iqdb-quantize/blob/main/docs/API.md)
- [ROADMAP](https://github.com/jamesgober/iqdb-quantize/blob/main/dev/ROADMAP.md)
- [Standards (REPS)](https://github.com/jamesgober/iqdb-quantize/blob/main/REPS.md)
- [CHANGELOG](https://github.com/jamesgober/iqdb-quantize/blob/main/CHANGELOG.md)
---
**Full diff:** [`v0.3.0...v0.4.0`](https://github.com/jamesgober/iqdb-quantize/compare/v0.3.0...v0.4.0).
**Changelog:** [`CHANGELOG.md`](https://github.com/jamesgober/iqdb-quantize/blob/main/CHANGELOG.md).