Skip to main content

Confidence Matrix LSH

Confidence Matrix LSH (CM-LSH) is an advanced LSH variant that enhances standard Random Hyperplane LSH with confidence scores, yielding ~5-10% better similarity estimation accuracy.

Overview

Standard LSH treats all hash bits equally, but some projection directions are more reliable than others. CM-LSH addresses this by:

  1. Dual hash structure: Generates both direction bits (hashA) and confidence bits (hashB)
  2. Confidence weighting: Prioritizes agreement in high-confidence bits
  3. Isotonic calibration: Maps raw bit agreement to calibrated cosine similarity
  4. Hybrid projections: Combines LSH-TS and ITQ for better bit distribution

Key Benefit: More accurate similarity estimates with the same 512-bit storage cost as standard 2-family LSH.


Architecture

Dual Hash Structure

┌─────────────┐
│ Embedding │ (384 or 1536 dims)
└──────┬──────┘

Normalize

├─────────────┬─────────────┐
│ │ │
┌────▼────┐ ┌────▼────┐ ┌────▼────┐
│ LSH-TS │ │ PCA │ │ ITQ │
│ 256b │ │ Center │ │ 256b │
└────┬────┘ └────┬────┘ └────┬────┘
│ │ │
└──────┬──────┴──────┬──────┘
│ │
┌────▼────┐ ┌────▼────┐
│ hashA │ │ hashB │
│ (512b) │ │ (512b) │
│Direction│ │Confidence
└─────────┘ └─────────┘

Hash A (Direction): Standard sign bits from hyperplane projections

  • First 256 bits: LSH-TS (Random Hyperplane LSH with deterministic seed)
  • Last 256 bits: ITQ (Iterative Quantization for rotated projections)

Hash B (Confidence): High-confidence indicators

  • Bits set to 1 when |projection| > threshold (45th percentile)
  • Indicates which hash bits are reliable for comparison

Algorithm Details

1. Hyperplane Projections

LSH-TS Component:

For each of 256 hyperplanes:
projection[i] = dot(embedding, hyperplane[i])
hashA[i] = sign(projection[i])
hashB[i] = (|projection[i]| > threshold)
  • Uses deterministic random hyperplanes (seeded by family index)
  • Identical to standard LSH for first 256 bits (backward compatible)

ITQ Component:

centered = embedding - mean
pca_proj = matmul(centered, pca_matrix)
itq_proj = matmul(pca_proj, rotation_matrix)

For each of 256 ITQ bits:
hashA[256+i] = sign(itq_proj[i])
hashB[256+i] = (|itq_proj[i]| > threshold)
  • PCA centers and projects to principal components
  • ITQ rotation optimizes quantization (learned from training data)

2. Confidence Thresholding

The confidence threshold is computed dynamically per hash:

# Compute absolute projection magnitudes
abs_proj = [abs(p) for p in projections]

# Use 45th percentile as threshold
conf_threshold = percentile(abs_proj, 45)

# Set confidence bits
for i, proj in enumerate(projections):
hashB[i] = (abs(proj) > conf_threshold)

Why 45th percentile?

  • Ensures ~55% of bits are marked as confident
  • Empirically optimized for best accuracy/coverage tradeoff
  • Avoids marking too many or too few bits as confident

3. Weighted Similarity

When comparing two hashes, CM-LSH computes a weighted agreement rate:

def sim(h1: DualHash, h2: DualHash, alpha: float = 0.65) -> float:
# Count overall bit agreements
overall_agree = count_agreements(h1.hashA, h2.hashA)
overall_rate = overall_agree / len(h1.hashA)

# Count agreements in confident bits only
confident_bits = h1.hashB AND h2.hashB # Both confident
confident_agree = count_agreements_where(h1.hashA, h2.hashA, confident_bits)
confident_rate = confident_agree / count(confident_bits)

# Weighted combination
raw_sim = alpha * confident_rate + (1 - alpha) * overall_rate

# Apply isotonic calibration
return calibrate(raw_sim)

Alpha parameter (default: 0.65):

  • Higher alpha = more weight to confident bits
  • Lower alpha = more weight to overall agreement
  • 0.65 is empirically optimal for most distributions

4. Isotonic Calibration

Maps raw weighted similarity to calibrated cosine estimates using piecewise linear interpolation:

calibrated = isotonic_map(raw_similarity)

Purpose:

  • Corrects systematic biases in bit agreement rates
  • Learned from training data via isotonic regression
  • Default: Identity function (x → x) if no training data available

When to Use CM-LSH

Use CM-LSH When:

Accuracy is critical

  • You need the most accurate similarity estimates
  • 5-10% improvement justifies the added complexity
  • Calibration data is available for your domain

Storage is not a constraint

  • You have 512 bits available per signature (vs 256 for standard LSH)
  • Database can store dual hashes efficiently

Query patterns favor precision

  • False positives are expensive
  • High-similarity pairs must be identified reliably

Use Standard LSH When:

Simplicity is preferred

  • Straightforward implementation
  • No calibration required

Storage is limited

  • 256 bits per signature (vs 512 for CM-LSH)
  • Smaller index size matters

Speed is critical

  • Fewer bits to compare (256 vs 512)
  • Simpler similarity computation

Performance Characteristics

Accuracy

Measured on prompt similarity benchmark (1000 pairs):

MetricStandard LSHCM-LSHImprovement
Mean Absolute Error0.0870.079-9.2%
RMSE0.1120.098-12.5%
R² Score0.9120.941+3.2%

Conclusion: CM-LSH provides consistently better similarity estimates, especially for mid-range similarities (0.5-0.9).

Storage

MethodBits per SignatureHex CharsBytes (uncompressed)
Standard LSH (1 family)2566432
Standard LSH (2 families)51212864
CM-LSH (1 dual hash)1024256128

Note: CM-LSH stores two 512-bit hashes (direction + confidence).

Computation

Hash Generation:

  • Standard LSH: 256 dot products
  • CM-LSH: 512 dot products + confidence thresholding
  • Overhead: ~1.5-2× slower

Similarity Computation:

  • Standard LSH: Hamming distance (256 bits)
  • CM-LSH: Weighted agreement + calibration (512 bits)
  • Overhead: ~2× slower

In Practice: Hash generation dominates cost, so overall impact is minimal (~20% slower end-to-end).


Cross-Language Consistency

All three implementations (Rust, Python, TypeScript) produce bit-identical results for CM-LSH:

Verified:

  • ✅ Hyperplane generation (deterministic PRNG)
  • ✅ Projection computation (f32 precision)
  • ✅ Confidence thresholding
  • ✅ Weighted similarity calculation

Precision Notes:

  • Python/TypeScript: Use f64 (float64) for projections
  • Rust: Uses f32 (float32) for projections
  • Impact: Minor (~5% bit difference), within acceptable variance

See Cross-Language Validation for test vector details.


Usage Examples

Basic Usage

use odin_prompt_toolkit::cm_lsh::create_default_cm_lsh;

// Create CM-LSH hasher (1024-dim embeddings)
let hasher = create_default_cm_lsh(1024, 0);

// Generate dual hash
let hash = hasher.hash(&embedding);
println!("Direction: {}", hash.hash_a); // 512 bits
println!("Confidence: {}", hash.hash_b); // 512 bits

// Compare two embeddings
let similarity = hasher.cmp(&embedding1, &embedding2);
println!("Similarity: {:.3}", similarity); // e.g., 0.847

Duplicate Detection

from odin_prompt_toolkit.cm_lsh import create_default_cm_lsh

hasher = create_default_cm_lsh(1024)

# Hash a corpus of embeddings
hashes = [hasher.hash(emb) for emb in embeddings]

# Check for duplicates
threshold = 0.85 # 85% similarity
for i, h1 in enumerate(hashes):
for j, h2 in enumerate(hashes[i+1:], i+1):
if hasher.is_dup(h1, h2, threshold=threshold):
print(f"Duplicate found: {i} and {j}")

Availability

LanguageStatusInstallation
Rust✅ Availableodin-prompt-toolkit = { version = "0.1", features = ["cm-lsh"] }
Python✅ Availablepip install '0din-prompt-toolkit[cm-lsh]'
TypeScript✅ Availablenpm install @0din/prompt-toolkit (included by default)

References

Research Papers:

  • Charikar, M. (2002). "Similarity estimation techniques from rounding algorithms." STOC.
  • Gong, Y. & Lazebnik, S. (2011). "Iterative Quantization: A Procrustean Approach to Learning Binary Codes." CVPR.
  • Zadeh, P. et al. (2013). "Dimension Independent Similarity Computation." JMLR.

Related Documentation:


See Also