diff --git a/.jules/bolt.md b/.jules/bolt.md index 2ac6922..aa91c49 100644 --- a/.jules/bolt.md +++ b/.jules/bolt.md @@ -5,3 +5,7 @@ ## 2026-05-01 - Avoid High-Level Tensor Ops in Scalar Reductions **Learning:** High-level `Tensor` operations like `sub()` and `mul()` trigger intermediate heap allocations for shape and stride metadata. When computing scalar reductions (like MSE, distances, or loss functions), using these operations introduces severe memory overhead inside hot loops. Attempting to use `.min()` length truncation as a safeguard is an anti-pattern as it masks shape mismatch errors. **Action:** For scalar reductions, assert shape equality (`assert_eq!(a.shape, b.shape)`) and perform a single-pass iteration directly over the underlying borrowed data arrays (`a.data.borrow()`) to eliminate intermediate allocations and safely compute the result. + +## 2026-05-28 - O(N) Nearest Neighbor Selection +**Learning:** `KNNClassifier` uses a manual partial selection sort with $O(K \cdot N)$ complexity to find the $K$ nearest neighbors. This is highly inefficient in hot loops, especially when finding neighbors is a frequent operation. Finding $K$ nearest neighbors does not strictly require full sorting of the elements, only partitioning. +**Action:** Replace manual partial sorts with `select_nth_unstable_by` which provides $O(N)$ average time complexity. Use `partial_cmp().unwrap_or(core::cmp::Ordering::Equal)` to safely compare `f64` distances in the presence of `NaN` values without breaking the total ordering contract. diff --git a/crates/aether-core/src/aether.rs b/crates/aether-core/src/aether.rs index 0191d6e..c19c72b 100644 --- a/crates/aether-core/src/aether.rs +++ b/crates/aether-core/src/aether.rs @@ -27,7 +27,6 @@ // ═══════════════════════════════════════════════════════════════════════════════ // - #![allow(dead_code)] use libm::sqrt; diff --git a/crates/aether-core/src/governor.rs b/crates/aether-core/src/governor.rs index 491d872..2d7a8c6 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; diff --git a/crates/aether-core/src/lib.rs b/crates/aether-core/src/lib.rs index d73a357..78d7e4d 100644 --- a/crates/aether-core/src/lib.rs +++ b/crates/aether-core/src/lib.rs @@ -20,7 +20,6 @@ // ═══════════════════════════════════════════════════════════════════════════════ // - #![cfg_attr(not(feature = "std"), no_std)] #[cfg(feature = "alloc")] diff --git a/crates/aether-core/src/manifold.rs b/crates/aether-core/src/manifold.rs index 1bcc201..5607f2f 100644 --- a/crates/aether-core/src/manifold.rs +++ b/crates/aether-core/src/manifold.rs @@ -24,7 +24,6 @@ // ═══════════════════════════════════════════════════════════════════════════════ // - #![allow(dead_code)] use libm::sqrt; diff --git a/crates/aether-core/src/memory.rs b/crates/aether-core/src/memory.rs index 3034bec..7c790d7 100644 --- a/crates/aether-core/src/memory.rs +++ b/crates/aether-core/src/memory.rs @@ -21,7 +21,6 @@ // ═══════════════════════════════════════════════════════════════════════════════ // - #[cfg(not(feature = "std"))] use alloc::boxed::Box; #[cfg(not(feature = "std"))] diff --git a/crates/aether-core/src/ml/autograd.rs b/crates/aether-core/src/ml/autograd.rs index 3856cc5..db09b19 100644 --- a/crates/aether-core/src/ml/autograd.rs +++ b/crates/aether-core/src/ml/autograd.rs @@ -17,7 +17,6 @@ // ═══════════════════════════════════════════════════════════════════════════════ // - #[cfg(not(feature = "std"))] extern crate alloc; diff --git a/crates/aether-core/src/ml/benchmark.rs b/crates/aether-core/src/ml/benchmark.rs index b93ac14..ef5c8ad 100644 --- a/crates/aether-core/src/ml/benchmark.rs +++ b/crates/aether-core/src/ml/benchmark.rs @@ -19,7 +19,6 @@ // ═══════════════════════════════════════════════════════════════════════════════ // - #![allow(dead_code)] use crate::ml::convergence::{Answer, BettiNumbers, ConvergenceDetector, ResidualAnalyzer}; diff --git a/crates/aether-core/src/ml/classification.rs b/crates/aether-core/src/ml/classification.rs index 3f7a2cd..8aa6e21 100644 --- a/crates/aether-core/src/ml/classification.rs +++ b/crates/aether-core/src/ml/classification.rs @@ -13,7 +13,6 @@ // ═══════════════════════════════════════════════════════════════════════════════ // - #![allow(dead_code)] // use heapless::Vec as HVec; @@ -203,13 +202,12 @@ impl KNNClassifier { *dist = (self.distance(x, &self.x_train[i]), self.y_train[i]); } - // Sort by distance (simple bubble sort for small k) - for i in 0..self.k.min(self.n_train) { - for j in (i + 1)..self.n_train { - if distances[j].0 < distances[i].0 { - distances.swap(i, j); - } - } + // Select k nearest neighbors (O(N) on average) + let k_min = self.k.min(self.n_train); + if k_min > 0 { + distances[..self.n_train].select_nth_unstable_by(k_min - 1, |a, b| { + a.0.partial_cmp(&b.0).unwrap_or(core::cmp::Ordering::Equal) + }); } // Vote among k nearest diff --git a/crates/aether-core/src/ml/clustering.rs b/crates/aether-core/src/ml/clustering.rs index 7e043ad..36fe53c 100644 --- a/crates/aether-core/src/ml/clustering.rs +++ b/crates/aether-core/src/ml/clustering.rs @@ -13,7 +13,6 @@ // ═══════════════════════════════════════════════════════════════════════════════ // - #![allow(dead_code)] use libm::{fabs, sqrt}; diff --git a/crates/aether-core/src/ml/convergence.rs b/crates/aether-core/src/ml/convergence.rs index 1e412c5..7c7b7ec 100644 --- a/crates/aether-core/src/ml/convergence.rs +++ b/crates/aether-core/src/ml/convergence.rs @@ -19,7 +19,6 @@ // ═══════════════════════════════════════════════════════════════════════════════ // - #![allow(dead_code)] use heapless::Vec as HVec; diff --git a/crates/aether-core/src/ml/convolution.rs b/crates/aether-core/src/ml/convolution.rs index f749bc0..57d7169 100644 --- a/crates/aether-core/src/ml/convolution.rs +++ b/crates/aether-core/src/ml/convolution.rs @@ -13,7 +13,6 @@ // ═══════════════════════════════════════════════════════════════════════════════ // - #![allow(dead_code)] use crate::ml::neural::Activation; diff --git a/crates/aether-core/src/ml/gossip.rs b/crates/aether-core/src/ml/gossip.rs index 91e869f..91d08d3 100644 --- a/crates/aether-core/src/ml/gossip.rs +++ b/crates/aether-core/src/ml/gossip.rs @@ -23,7 +23,6 @@ // ═══════════════════════════════════════════════════════════════════════════════ // - #![allow(dead_code)] use crate::ml::clustering::{KMeans, KMeansResult}; diff --git a/crates/aether-core/src/ml/linalg.rs b/crates/aether-core/src/ml/linalg.rs index bd4125b..2ad115f 100644 --- a/crates/aether-core/src/ml/linalg.rs +++ b/crates/aether-core/src/ml/linalg.rs @@ -14,7 +14,6 @@ // ═══════════════════════════════════════════════════════════════════════════════ // - #![allow(dead_code)] #[cfg(feature = "alloc")] diff --git a/crates/aether-core/src/ml/mod.rs b/crates/aether-core/src/ml/mod.rs index 77ef291..dec455e 100644 --- a/crates/aether-core/src/ml/mod.rs +++ b/crates/aether-core/src/ml/mod.rs @@ -24,7 +24,6 @@ // ═══════════════════════════════════════════════════════════════════════════════ // - #![allow(dead_code)] // Core modules diff --git a/crates/aether-core/src/ml/neural.rs b/crates/aether-core/src/ml/neural.rs index 70ec2dc..90b253e 100644 --- a/crates/aether-core/src/ml/neural.rs +++ b/crates/aether-core/src/ml/neural.rs @@ -14,7 +14,6 @@ // ═══════════════════════════════════════════════════════════════════════════════ // - #![allow(dead_code)] #[cfg(feature = "alloc")] diff --git a/crates/aether-core/src/ml/regressor.rs b/crates/aether-core/src/ml/regressor.rs index 34640cf..f5ec299 100644 --- a/crates/aether-core/src/ml/regressor.rs +++ b/crates/aether-core/src/ml/regressor.rs @@ -16,7 +16,6 @@ // ═══════════════════════════════════════════════════════════════════════════════ // - #![allow(dead_code)] use heapless::Vec as HVec; diff --git a/crates/aether-core/src/ml/tensor.rs b/crates/aether-core/src/ml/tensor.rs index 2418110..33238f0 100644 --- a/crates/aether-core/src/ml/tensor.rs +++ b/crates/aether-core/src/ml/tensor.rs @@ -14,7 +14,6 @@ // ═══════════════════════════════════════════════════════════════════════════════ // - #[cfg(feature = "alloc")] use alloc::rc::Rc; #[cfg(feature = "alloc")] diff --git a/crates/aether-core/src/os.rs b/crates/aether-core/src/os.rs index dcc3b60..f7ef175 100644 --- a/crates/aether-core/src/os.rs +++ b/crates/aether-core/src/os.rs @@ -17,7 +17,6 @@ // ═══════════════════════════════════════════════════════════════════════════════ // - /// CPU Register Context /// /// This structure represents the state of the CPU registers. It is used for: diff --git a/crates/aether-core/src/state.rs b/crates/aether-core/src/state.rs index 1b2ab19..bd02d89 100644 --- a/crates/aether-core/src/state.rs +++ b/crates/aether-core/src/state.rs @@ -23,7 +23,6 @@ // ═══════════════════════════════════════════════════════════════════════════════ // - use core::ops::Sub; use libm::sqrt; diff --git a/crates/aether-core/src/topology.rs b/crates/aether-core/src/topology.rs index a75090f..895797f 100644 --- a/crates/aether-core/src/topology.rs +++ b/crates/aether-core/src/topology.rs @@ -23,7 +23,6 @@ // ═══════════════════════════════════════════════════════════════════════════════ // - #![allow(dead_code)] // use libm::fabs;