baselines 0.1.1

Baseline correction algorithms for signals, spectra, and images
Documentation
# baselines

<p align="center">
  <img src="https://raw.githubusercontent.com/Ameyanagi/baselines/main/docs/assets/branding/baselines-icon-midnight-hex-v2.png" alt="baselines logo" width="220">
</p>

`baselines` is a Rust crate for baseline correction of signals, spectra, and
row-major two-dimensional surfaces. It is an independent Rust implementation
inspired by the baseline correction literature and by the public behavior of
[`pybaselines`](https://pybaselines.readthedocs.io/).

```rust
use baselines::prelude::*;

let y = vec![1.0, 1.1, 4.2, 1.2, 1.0];
let estimated = baseline(&y)?;
let corrected = correct(&y)?;
# Ok::<(), baselines::BaselineError>(())
```

Select one of the common methods without configuring parameters:

```rust
use baselines::prelude::*;

let estimated = baseline_with(&y, Method::Arpls)?;
# Ok::<(), baselines::BaselineError>(())
```

## Scope

The crate starts with CPU `f64` implementations and public entry points for
the current one-dimensional `pybaselines.Baseline` algorithm families:
polynomial, Whittaker, morphology, penalized spline, smoothing,
classification, optimizer, and miscellaneous methods. Two-dimensional support
is staged under `baselines::two_d`; all pinned `pybaselines.Baseline2D` 1.2.1
families now have first-pass native Rust implementations.

Algorithms are organized by family module. Core data types such as `Fit1D`,
`Fit2D`, and row-major matrix views are available at the crate root. The
smallest Rust API is `baseline(&y)` or `correct(&y)`. Use
`baseline_with(&y, Method::Arpls)` to select a common algorithm with its
documented defaults. For parameter tuning, start from `Baseline::new(&y)` for
1D data or `Baseline2D::row_major(&data, rows, cols)` for row-major 2D data.
The explicit family modules and parameter structs remain public for advanced
workflows and for users who prefer free functions.

Golden fixtures generated from a pinned `pybaselines` release check the
one-dimensional algorithms with algorithm-specific tolerances. GPU support is
feature-gated behind `gpu-wgpu`; the experimental WGPU path provides batched
`f32` morphology kernels for moving minimum, moving maximum, opening, and the
top-hat baseline primitive.

See `docs/PARITY.md` for the current pybaselines parity matrix, 2D tolerance
ledger, and known limits.

See `docs/performance/` for checked-in benchmark records, including the
2026-05-24 full Criterion baseline and the measured BEADS optimization result.

## Visual examples

The crate includes `ruviz` examples for inspecting generated baselines as PNGs:

```console
cargo run --example ruviz_1d
cargo run --example ruviz_2d
cargo run --example ruviz_lam_effects
```

The examples write images to `docs/assets/ruviz/`. The generated PNGs are
tracked for Markdown preview and excluded from Cargo packages. The 1D example plots
observed spectra, AsLS/arPLS baselines, and corrected signals. The 2D example
writes heatmaps for the observed surface, fitted AsLS baseline, true synthetic
baseline, and corrected surface.

`ruviz_lam_effects` mirrors the upstream Whittaker gallery example from
pybaselines for arPLS lambda selection, using the same synthetic signal,
exponential baseline, noise scale, and lambda values. The noise is generated by
a small deterministic Rust generator rather than NumPy's bit generator, so the
shape and parameters match the gallery example but the exact noise samples do
not.

See `docs/GALLERY.md` for the generated-output index and runnable source files,
or open the `gallery` page in generated Rust docs. See
`docs/PYBASELINES_EXAMPLES.md` or the `reference_examples` rustdoc page for
the upstream gallery coverage matrix.

## API style

Use the method-chain API when you need to tune a fit:

```rust
use baselines::prelude::*;

let fit = Baseline::new(&y)
    .arpls()
    .lambda(1.0e6)
    .max_iter(50)
    .tol(1.0e-3)
    .fit()?;
# Ok::<(), baselines::BaselineError>(())
```

Use `Baseline::new_xy(&x, &y)?` for nonuniform x grids or x-coordinate masks:

```rust
use baselines::prelude::*;

let fit = Baseline::new_xy(&x, &y)?
    .asls()
    .lambda(1.0e6)
    .exclude_range(125.0, 180.0)
    .baseline_mask(&trusted_baseline_points)?
    .fit()?;
# Ok::<(), baselines::BaselineError>(())
```

Use the lower-level family modules when you want to pass a complete params
struct, reuse workspaces, or compare directly against existing code:

```rust
use baselines::whittaker::{AslsParams, asls};

let fit = asls(&y, AslsParams::default())?;
# Ok::<(), baselines::BaselineError>(())
```

See `docs/API.md` for more examples.

## Python and WebAssembly

The repository contains thin bindings over the same simple API:

```python
import numpy as np
import baselines_rs

y = np.array([1.0, 1.1, 4.2, 1.2, 1.0])
corrected = baselines_rs.correct(y, method="arpls")
```

Build the Python wheel with `maturin build --release` from `bindings/python`.
Build the browser package with `wasm-pack build --target web` from
`bindings/wasm`. The planned distribution names are `baselines-rs` on PyPI and
`baselines-wasm` on npm.

## Feature flags

- `gpu-wgpu` enables the experimental CubeCL/WGPU morphology backend.
- `rayon` parallelizes supported batch CPU operations, currently
  `backend::cpu::snip_batch_into`.
- `faer` exposes the reserved faer backend boundary; the public algorithms
  still use the in-crate solvers in this release.
- `std` is retained for feature compatibility. The crate currently requires
  the standard library even when default features are disabled.

## Attribution

This project does not copy implementation code from `pybaselines`. The Python
project is used as a documentation and behavioral reference, and golden
fixtures should record the pybaselines version that generated them.

Please cite the original algorithm papers as appropriate. See `NOTICE.md` and
`CITATION.cff` for project-level attribution.