brain2qwerty 0.0.1

Brain2Qwerty V1/V2 MEG neural decoding inference in Rust (parity-tested vs Python)
Documentation
//! # brain2qwerty
//!
//! Rust inference for [Brain2Qwerty](https://github.com/facebookresearch/brain2qwerty):
//! MEG/EEG neural decoding to text, with numeric parity against the official Python
//! reference implementation.
//!
//! ## Pipelines
//!
//! | Version | Paper | Rust entry point |
//! |---------|-------|------------------|
//! | **V1** | [Nature Neuroscience 2026](https://www.nature.com/articles/s41593-026-02303-2) — keystroke-aligned windows + sentence transformer | [`V1Pipeline`] |
//! | **V2** | Sentence-level CTC + TinyLlama beam search | [`Pipeline`] |
//!
//! ## V2 quick start
//!
//! ```no_run
//! use brain2qwerty::pipeline::{InferenceInput, Pipeline};
//!
//! let mut pipeline = Pipeline::from_paths(
//!     "data/config.yaml",
//!     "data/encoder.safetensors",
//!     Some("data/llm"),
//! )?;
//! let input = InferenceInput {
//!     neuros: /* (B, T, C) tensor */,
//!     subject_ids: vec![0],
//!     chan_pos: None,
//! };
//! let out = pipeline.run(&input)?;
//! println!("{}", out.pred_text);
//! # Ok::<(), anyhow::Error>(())
//! ```
//!
//! ## V1 quick start
//!
//! V1 expects keystroke windows shaped `(N, channels, time)` — see [`V1Input`].
//!
//! ```no_run
//! use brain2qwerty::{V1Input, V1Pipeline};
//!
//! let pipeline = V1Pipeline::from_tiny_weights("data/encoder_v1.safetensors")?;
//! let out = pipeline.run(&V1Input {
//!     neuros: /* (N, C, T) */,
//!     subject_ids: vec![0],
//!     chan_pos: None,
//! })?;
//! println!("{}", out.pred_text);
//! # Ok::<(), anyhow::Error>(())
//! ```
//!
//! ## Features
//!
//! - **`rlx-encoder`** (default): RLX-accelerated Conformer tail for V2.
//! - **`pure-rust`**: disable RLX; use the reference CPU encoder only.
//! - Backend features: `rlx-cpu`, `rlx-metal`, `rlx-cuda`, `rlx-mlx`, `rlx-coreml`, …
//!
//! ## Parity tests
//!
//! Generate Python references, then run `bash scripts/run_all_parity.sh` or individual
//! `cargo test --test *_parity` targets. Continuous tensors must reach Pearson r ≥ 0.999999.

pub mod config;
pub mod data_paths;
pub mod decode;
pub mod llm;
pub mod model;
#[cfg(feature = "rlx-encoder")]
pub mod model_rlx;
pub mod pipeline;
#[cfg(feature = "rlx-encoder")]
pub mod rlx_device;
pub mod tensor;
pub mod v1;
pub mod weights;

pub use config::{Brain2QwertyConfig, BuildArgs, EncoderConfig};
pub use decode::{ctc_greedy_decode, CTCSpaceSegmenter, IntraWordPooler};
pub use model::conv_conformer::{ConvConformer, ConvConformerOutput};
pub use pipeline::{InferenceInput, Pipeline, PipelineOptions, PipelineOutput};
pub use tensor::Tensor;
pub use v1::{Brain2QwertyV1, V1Config, V1Input, V1Output, V1Pipeline};

/// Root data directory (`BRAIN2QWERTY_DATA_DIR` or `./data`).
pub fn data_dir() -> std::path::PathBuf {
    data_paths::data_dir()
}

/// Tiny V2 parity reference tensors (`data/parity_refs/`).
pub fn parity_refs_dir() -> std::path::PathBuf {
    data_paths::parity_refs_dir()
}

/// Whether `data/encoder.safetensors` exists.
pub fn weights_available() -> bool {
    data_paths::encoder_weights_available()
}

/// Whether tiny V2 parity refs are present.
pub fn parity_refs_available() -> bool {
    data_paths::parity_refs_available()
}

/// Production-scale V2 parity refs (`data/parity_refs_v2/`).
pub fn parity_refs_v2_dir() -> std::path::PathBuf {
    data_paths::parity_refs_v2_dir()
}

pub fn parity_refs_v2_available() -> bool {
    data_paths::parity_refs_v2_available()
}

pub fn encoder_v2_weights_available() -> bool {
    data_paths::encoder_v2_weights_available()
}

/// V1 parity refs (`data/parity_refs_v1/`).
pub fn parity_refs_v1_dir() -> std::path::PathBuf {
    data_paths::parity_refs_v1_dir()
}

pub fn parity_refs_v1_available() -> bool {
    data_paths::parity_refs_v1_available()
}

pub fn encoder_v1_weights_available() -> bool {
    data_paths::encoder_v1_weights_available()
}