Skip to content

Phase 1: Sqrt-free metric layer — QuadranceGaussian as live default in k-NN and Laplacian kernel #14

Description

@Mec-iS

Parent macro-issue: #12
Depends on: #13 (Phase 0)

Goal

Make WiringMetric::QuadranceGaussian fully operational end-to-end: remove all sqrt calls from the k-NN hot path and the Laplacian kernel computation path. This is the first phase that changes runtime behaviour and becomes the live default.


Background

The current compute_bhattacharyya_weights() exponent is already (μ_i − μ_j)² / (σ_i² + σ_j²) — a squared distance — so no sqrt is analytically required. The only sqrt calls in the pipeline today are:

  1. k-NN gate: distance = sqrt(sum_sq) used for threshold comparisons.
  2. Normalisation steps: ‖x‖ computed to produce unit vectors before cosine.
  3. Logging/diagnostics: sqrt for human-readable distance display.

Since sqrt is monotone, d < rd² < r² — the substitution is mathematically exact for all ordering operations. The quadrance Gaussian kernel:

w_ij = exp( −Q(i,j) / 2σ² )
     = exp( −‖μ_i − μ_j‖² / 2σ² )

is the canonical heat-kernel form in the Graph Wiring / Laplace–Beltrami literature and carries identical convergence guarantees to the BC formulation.


Detailed changes

1. Kernel dispatcher in Stage C

let weights = match config.wiring_metric {
    WiringMetric::QuadranceGaussian { sigma_sq } =>
        compute_quadrance_weights(&centroids, sigma_sq),   // new default
    WiringMetric::QuadranceRational { .. } =>
        unimplemented!("Phase 4"),
    WiringMetric::BhattacharyyaCosine =>
        compute_bc_weights(&centroids),                    // legacy
};

compute_quadrance_weights() calls surfface_geometry::quadrance() — zero sqrt in the hot path.

2. k-NN gate audit

  • Audit every f32::sqrt / f64::sqrt call in surfface-core and arrowspace.
  • Replace sqrt(sum_sq) < r with sum_sq < r * r at every comparison site.
  • Logging/display: retain a single sqrt in the log formatter only, clearly labelled quadrance=; never in the comparison path.
  • Enforce via CI grep step: zero sqrt calls permitted in files matching **/wiring*.rs and **/knn*.rs.

3. sigma_sq auto-calibration

The BC kernel has implicit bandwidth from (μ_i−μ_j)²/(σ_i²+σ_j²). QuadranceGaussian needs σ² set to match. Implement:

/// Estimate sigma_sq for QuadranceGaussian from empirical mean quadrance
/// of k-NN pairs — Scott's rule adapted to quadrance.
/// Runs once at index build time; stored in serialised LaplacianConfig.
pub fn estimate_sigma_sq(knn_quadrances: &[f32]) -> f32 {
    knn_quadrances.iter().sum::<f32>() / (2.0 * knn_quadrances.len() as f32)
}

Benchmarks (CVE corpus, N = 313 841, F = 384)

Metric BC baseline QuadranceGaussian Target
k-NN build time baseline ≥ 10 % faster
Laplacian build time baseline ≥ 5 % faster
Serialised index size baseline ≤ baseline + 1 %
TauModeScore KS vs BC < 0.01
Cross-platform bit-exact no yes

Acceptance criteria

  • cargo bench shows ≥ 10 % speed improvement in k-NN build on CVE.
  • Zero sqrt calls in k-NN and kernel hot path (CI grep enforced).
  • estimate_sigma_sq() documented and tested on a synthetic Gaussian point cloud.
  • All Phase 0 regression tests still pass.
  • TauModeScore KS-statistic vs BC baseline < 0.01 on CVE.
  • Index built on x86-64 and Apple Silicon produces identical serialised bytes.

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions