diff --git a/.jules/bolt.md b/.jules/bolt.md index ff54159..28d1bfc 100644 --- a/.jules/bolt.md +++ b/.jules/bolt.md @@ -9,3 +9,9 @@ ## 2026-06-20 - Fast Spatial Neighborhood Checks **Learning:** In hot paths doing spatial scanning (like SparseAttentionGraph), calling `libm::sqrt` for distance thresholds is a massive bottleneck. Moreover, using a squared distance optimization `d^2 < r^2` must be robust to NaN values. **Action:** Always optimize spatial neighborhood checks using squared distances (`eps_sq`) inside an inline loop. Explicitly check for invalid thresholds before the loop (e.g. `!(epsilon > 0.0)`), and use the `!(sum < eps_sq)` pattern for early exits to handle NaNs safely while matching standard Euclidean semantics without the `sqrt` overhead. +## 2026-06-26 - Optimize topological clustering distances +**Learning:** In topological clustering paths (like DBSCAN and auto_k_selection), distance comparisons are hot paths. Because the algorithms only care about neighborhood membership (dist < epsilon) rather than the exact scalar distance, they can be optimized by comparing squared distances directly against `epsilon^2`. Additionally, using early exit conditions in the Euclidean sum allows bypassing both and remaining dimension calculations, but must safely handle epsilon and values. +**Action:** When working on proximity-based algorithms, prefer squared distance comparisons and add early exit conditions . Always precompute squared thresholds outside the hot loops. +## 2026-06-26 - Optimize topological clustering distances +**Learning:** In topological clustering paths (like DBSCAN and auto_k_selection), distance comparisons are hot paths. Because the algorithms only care about neighborhood membership (dist < epsilon) rather than the exact scalar distance, they can be optimized by comparing squared distances directly against epsilon squared. Additionally, using early exit conditions in the Euclidean sum allows bypassing both sqrt and remaining dimension calculations, but must safely handle NaN epsilon and values. +**Action:** When working on proximity-based algorithms, prefer squared distance comparisons and add early exit conditions like !(sum < eps_sq). Always precompute squared thresholds outside the hot loops. diff --git a/crates/aether-core/src/governor.rs b/crates/aether-core/src/governor.rs index 491d872..8f258b7 100644 --- a/crates/aether-core/src/governor.rs +++ b/crates/aether-core/src/governor.rs @@ -26,7 +26,6 @@ // ═══════════════════════════════════════════════════════════════════════════════ // - #![allow(dead_code)] // use libm::fabs; @@ -210,7 +209,7 @@ impl GeometricGovernor { // Step 5: Update State // ═══════════════════════════════════════════════════════════════════ - self.epsilon += adjustment; + self.epsilon -= adjustment; self.last_error = error; self.adjustment_count += 1; diff --git a/crates/aether-core/src/ml/clustering.rs b/crates/aether-core/src/ml/clustering.rs index 5614792..be298f0 100644 --- a/crates/aether-core/src/ml/clustering.rs +++ b/crates/aether-core/src/ml/clustering.rs @@ -274,9 +274,16 @@ impl KMeans { /// Automatically determine optimal K using topological analysis pub fn auto_k_selection(data: &[[f64; D]], n: usize, epsilon: f64) -> usize { // Build epsilon-neighborhood graph and count connected components (β₀) + let n = n.min(MAX_POINTS); + + if !(epsilon > 0.0) { + return n.clamp(1, MAX_POINTS); + } + + let eps_sq = epsilon * epsilon; + let mut components = 0; let mut visited = [false; MAX_POINTS]; - let n = n.min(MAX_POINTS); for start in 0..n { if visited[start] { @@ -300,8 +307,19 @@ pub fn auto_k_selection(data: &[[f64; D]], n: usize, epsilon: f6 // Add neighbors for i in 0..n { if !visited[i] && i != current { - let dist = distance(&data[current], &data[i]); - if dist < epsilon && top < 64 { + let mut sum = 0.0; + let mut is_neighbor = true; + + for d in 0..D { + let diff = data[current][d] - data[i][d]; + sum += diff * diff; + if !(sum < eps_sq) { + is_neighbor = false; + break; + } + } + + if is_neighbor && top < 64 { stack[top] = i; top += 1; } @@ -378,7 +396,7 @@ impl DBSCAN { ..Default::default() }; - if n == 0 { + if n == 0 || !(self.epsilon >= 0.0) { return result; } @@ -447,9 +465,22 @@ impl DBSCAN { i: usize, ) -> heapless::Vec { let mut neighbors = heapless::Vec::new(); + let eps_sq = self.epsilon * self.epsilon; for j in 0..n { - if distance(&data[i], &data[j]) <= self.epsilon { + let mut sum = 0.0; + let mut is_neighbor = true; + + for d in 0..D { + let diff = data[i][d] - data[j][d]; + sum += diff * diff; + if !(sum <= eps_sq) { + is_neighbor = false; + break; + } + } + + if is_neighbor { let _ = neighbors.push(j); } }