# Agent Notes (rust-mlp) This file is for agentic coding tools operating in this repository. Repo snapshot: - Rust edition: 2024 (`Cargo.toml`) - Crate: `rust-mlp` (library-first; `src/main.rs` is a tiny helper binary) - Core focus: small MLP (dense layers + tanh), allocation-free per-sample hot path ## Commands (Build / Lint / Test) CI runs (see `.github/workflows/ci.yml`): ```bash cargo fmt --check cargo clippy --all-targets --all-features -- -D warnings cargo test --all-targets --all-features ``` Common local commands: ```bash # Fast compile check cargo check # Build cargo build cargo build --release # Format cargo fmt # Lint (match CI) cargo clippy --all-targets --all-features -- -D warnings # Tests cargo test # Docs cargo doc --open ``` Run a single unit test (recommended patterns): ```bash # Substring match (fastest to type) cargo test backward_matches_numeric_gradients # Exact match (best for disambiguation) cargo test mlp::tests::backward_matches_numeric_gradients -- --exact # Show stdout/stderr cargo test mlp::tests::backward_matches_numeric_gradients -- --exact --nocapture # Run tests matching a module/file cargo test layer::tests:: ``` Note: `cargo test --all-targets` will also build/run benches and examples as test targets. Use plain `cargo test` for the tight inner loop. Examples: `cargo run --example tanh_sum` Benchmarks (Criterion): ```bash cargo bench cargo bench --bench mlp -- mlp_forward ``` ## Code Style and Conventions ### Formatting - Use `rustfmt` (no custom config in this repo). Run `cargo fmt` before finalizing changes. - Keep lines readable; let rustfmt handle wrapping. ### Imports - Prefer grouping imports by origin (typical order): `std::...`, external crates, then `crate::...`. - Prefer `{}` import lists for multiple items: `use crate::{Error, Result};`. - `use super::*;` is fine inside `#[cfg(test)] mod tests`. ### Types and Numerics - Scalars are `f32` throughout the crate. - Dimensions/indices use `usize` (`in_dim`, `out_dim`, `input_dim`, `target_dim`, `len`). - Deterministic seeds use `u64` and `StdRng::seed_from_u64`. - Prefer `mul_add` in inner loops where it is already used (dot products). - Keep weight/data layout decisions consistent: - Layer weights: row-major `(out_dim, in_dim)` contiguous `Vec`. - Dataset/inputs: row-major contiguous buffers. ### Naming - Types: `PascalCase` (`Mlp`, `Layer`, `Scratch`, `Gradients`, `FitConfig`). - Methods/vars: `snake_case`. - Gradients use `d_` prefix (`d_weights`, `d_biases`, `d_input`, `d_output`). - Use `idx` for indices in loops; use `len()` for counts. ### API Layers (Panics vs Result) The crate intentionally has two layers of API: - Low-level, allocation-free hot path: - `Mlp::forward`, `Mlp::backward`, `Mlp::sgd_step` - `Layer::forward`, `Layer::backward`, `Layer::sgd_step` - loss helpers (e.g. `loss::mse_backward`) These treat shape mismatches as programmer error and MUST panic on misuse. Use `assert!` / `assert_eq!` with clear messages (expected vs actual). - High-level convenience APIs: - `Mlp::fit`, `Mlp::predict`, `Mlp::predict_inputs`, `Mlp::evaluate_mse` These validate inputs and return `Result` with `Error::InvalidData` / `Error::InvalidConfig`. Avoid adding duplicate "try_*" APIs; keep one obvious way to do things. ### Error Handling - Use the crate error types: `crate::Result` and `crate::Error` (`src/error.rs`). - Use: - `Error::InvalidConfig` for hyperparameters/model configuration (e.g. `epochs == 0`, `lr <= 0`). - `Error::InvalidData` for dataset/inputs issues (empty sets, dimension mismatch, bad shapes). - Prefer actionable error strings that include the offending values. ### Performance Guidelines - Hot paths should be allocation-free when buffers are reused. - Use `Scratch` and `Gradients` from `Mlp::scratch()` / `Mlp::gradients()`. - Avoid creating temporary `Vec`s inside per-sample loops. - Use `Vec::with_capacity` when building contiguous buffers. ### Tests - Keep tests deterministic (use fixed seeds). - Numerical gradient checks exist; keep tolerances reasonable and avoid flakiness. - Panic tests (`#[should_panic]`) should be minimal and fast. ### Documentation - Each module uses a short `//!` module doc at the top. - Public types/functions should have rustdoc comments, especially describing: - shape contracts - overwrite vs accumulation semantics - panic vs `Result` behavior ## Cursor / Copilot Instructions No Cursor rules were found (`.cursor/rules/` or `.cursorrules`). No Copilot instructions were found (`.github/copilot-instructions.md`).