Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 24 additions & 4 deletions .github/workflows/Github.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,14 @@ jobs:
- uses: actions/checkout@v4
- name: Install OpenBLAS / LAPACK
run: sudo apt-get update && sudo apt-get install -y libopenblas-dev liblapack-dev gfortran
- name: Build
- name: Build (OpenBLAS from source)
run: cargo build --verbose --features O3-openblas
- name: Run tests
- name: Run tests (OpenBLAS from source)
run: cargo test --verbose --features O3-openblas
- name: Build (system OpenBLAS via pkg-config)
run: cargo build --verbose --features O3-openblas-system
- name: Run tests (system OpenBLAS via pkg-config)
run: cargo test --verbose --features O3-openblas-system

pure-rust:
name: Pure-Rust feature set
Expand All @@ -45,6 +49,20 @@ jobs:
- name: Run tests
run: cargo test --verbose --features "arrow complex csv indexmap json num-complex parallel parquet rayon rkyv serde"

# The deterministic core (no `rand` stack) must keep building for sandboxed
# targets such as Typst / wasm plugins (#88).
no-rand-wasm:
name: No-rand core (wasm32)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Add wasm32 target
run: rustup target add wasm32-unknown-unknown
- name: Test without the rand stack
run: cargo test --verbose --no-default-features
- name: Build for wasm32
run: cargo build --verbose --no-default-features --target wasm32-unknown-unknown

feature-combinations:
name: Feature combinations (cargo-hack)
runs-on: ubuntu-latest
Expand All @@ -61,17 +79,19 @@ jobs:
# HDF5 features (nc / netcdf) are excluded because they need an external
# toolchain (vendor BLAS, HDF5 headers) or a non-Linux platform rather than
# being a code problem; plot / pyo3 are exercised by the dedicated plot job.
# openblas-src alone (default-features = false) has no TLS backend for its
# source download, so it is only meaningful through O3-openblas-system.
- name: Each feature builds on its own
run: >
cargo hack build --each-feature --optional-deps --keep-going
--exclude-features O3-accelerate,O3-mkl,O3-netlib,nc,netcdf,plot,pyo3,blas-src,lapack-src
--exclude-features O3-accelerate,O3-mkl,O3-netlib,nc,netcdf,plot,pyo3,blas-src,lapack-src,openblas-src
# Pairwise (depth 2) coverage over the pure-Rust / numerical features. The
# heavy compile units (arrow / parquet) and the backend / HDF5 / Python
# features are excluded so the target dir does not blow up on a CI runner.
- name: Pairwise feature powerset (pure-Rust / numerical)
run: >
cargo hack build --feature-powerset --depth 2 --optional-deps --keep-going
--exclude-features O3,O3-openblas,O3-accelerate,O3-mkl,O3-netlib,nc,netcdf,plot,pyo3,blas-src,lapack-src,arrow,parquet
--exclude-features O3,O3-openblas,O3-openblas-system,O3-accelerate,O3-mkl,O3-netlib,nc,netcdf,plot,pyo3,blas-src,lapack-src,openblas-src,arrow,parquet

plot:
name: plot (pyo3 + matplotlib)
Expand Down
17 changes: 2 additions & 15 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,21 +41,8 @@ Peroxide follows the [Gitflow workflow]. A few practical rules:

## Source layout

A high-level map of `src/`; see each module's `mod.rs` and the [API docs](https://docs.rs/peroxide) for details.

| Module | Purpose |
| ------------------ | ------------------------------------------------------------------ |
| [`structure`](src/structure) | Core data structures: `Matrix`, `Vec<f64>` extensions, `DataFrame`, `Polynomial`, `Jet<N>` forward AD |
| [`numerical`](src/numerical) | Numerical algorithms: ODE solvers, integration, interpolation, splines, root finding, optimization, eigenvalues |
| [`statistics`](src/statistics) | Probability distributions, RNG wrappers, ordered statistics |
| [`complex`](src/complex) | Complex vectors, matrices, and integrals (`complex` feature) |
| [`special`](src/special) | Special functions (wrapper of `puruspe`) |
| [`traits`](src/traits) | Shared trait definitions (math, functional programming, pointers) |
| [`macros`](src/macros) | R / MATLAB / Julia style macros |
| [`fuga`](src/fuga), [`prelude`](src/prelude) | The two user-facing import styles (explicit vs simple) |
| [`util`](src/util) | Constructors, printing, plotting, low-level helpers |
| [`ml`](src/ml) | Basic machine learning tools (beta) |
| [`grave`](src/grave) | Retired implementations kept for reference; not compiled |
The directories under `src/` map one-to-one to the public modules, so the module index in the [API docs](https://docs.rs/peroxide) doubles as the source map; start from a module's documentation and its `mod.rs`.
The only exception is `src/grave/`, which holds retired implementations kept for reference and is excluded from compilation.

## Code of conduct

Expand Down
40 changes: 35 additions & 5 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "peroxide"
version = "0.42.0"
version = "0.43.0"
authors = ["axect <axect@outlook.kr>"]
edition = "2018"
description = "Rust comprehensive scientific computation library contains linear algebra, numerical analysis, statistics and machine learning tools with familiar syntax"
Expand Down Expand Up @@ -30,8 +30,8 @@ criterion = { version = "0.5.1", features = ["html_reports"] }

[dependencies]
csv = { version = "1.3", optional = true, default-features = false }
rand = { version = "0.9", features = ["small_rng"] }
rand_distr = "0.5"
rand = { version = "0.9", features = ["small_rng"], optional = true }
rand_distr = { version = "0.5", optional = true }
order-stat = "0.1"
puruspe = "0.4"
matrixmultiply = { version = "0.3", features = ["threading"] }
Expand All @@ -47,13 +47,17 @@ blas = { version = "0.22", optional = true }
lapack = { version = "0.19", optional = true }
blas-src = { version = "0.14", optional = true, default-features = false }
lapack-src = { version = "0.13", optional = true, default-features = false }
# Only used to forward the `system` feature to the `openblas-src` instance
# that `blas-src` / `lapack-src` already pull in (see `O3-openblas-system`).
openblas-src = { version = "0.10", optional = true, default-features = false }
serde = { version = "1.0", features = ["derive"], optional = true }
rkyv = { version = "0.8", optional = true }
json = { version = "0.12", optional = true }
parquet = { version = "55", features = ["arrow", "snap"], optional = true }
arrow = { version = "55", optional = true }
indexmap = { version = "1", optional = true }
num-complex = { version = "0.4", optional = true }
num-traits = { version = "0.2", optional = true }
rayon = { version = "1.10", optional = true }

[package.metadata.docs.rs]
Expand All @@ -75,18 +79,44 @@ features = [
"serde",
]

# Examples that exercise the random sampling stack are skipped when the
# `rand` feature is disabled.
[[example]]
name = "dist"
required-features = ["rand"]

[[example]]
name = "matmul"
required-features = ["rand"]

[[example]]
name = "optim"
required-features = ["rand"]

[[example]]
name = "clippy_verify"
required-features = ["rand"]

[features]
default = []
default = ["rand"]
# Random sampling stack (`rand` / `rand_distr`): probability distributions,
# RNG wrappers, and random constructors. Enabled by default; disable with
# `default-features = false` for the deterministic core (ODE, integration,
# splines, linear algebra), e.g. for wasm32 sandboxes without IO.
rand = ["dep:rand", "dep:rand_distr"]
# Bare BLAS / LAPACK FFI; downstream binary must also pull in a
# `blas-src` / `lapack-src` backend to resolve the link symbols.
O3 = ["blas", "lapack"]
# Convenience flags that bundle a backend choice for `O3`.
O3-openblas = ["O3", "blas-src/openblas", "lapack-src/openblas"]
# Same as `O3-openblas`, but links the OpenBLAS already installed on the
# system (found via pkg-config) instead of compiling OpenBLAS from source.
O3-openblas-system = ["O3-openblas", "openblas-src/system"]
O3-accelerate = ["O3", "blas-src/accelerate", "lapack-src/accelerate"]
O3-mkl = ["O3", "blas-src/intel-mkl-dynamic-parallel", "lapack-src/intel-mkl-dynamic-parallel"]
O3-netlib = ["O3", "blas-src/netlib", "lapack-src/netlib"]
plot = ["pyo3"]
nc = ["netcdf"]
parquet = ["dep:parquet", "arrow", "indexmap"]
complex = ["num-complex", "matrixmultiply/cgemm"]
complex = ["num-complex", "num-traits", "matrixmultiply/cgemm"]
parallel = ["rayon"]
37 changes: 21 additions & 16 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ For accelerated linear algebra, plotting, or DataFrame I/O, enable the matching
Peroxide provides various features.

- `default` - Pure Rust (No dependencies of architecture - Perfect cross compilation)
- `O3` - BLAS & LAPACK (Perfect performance but little bit hard to set-up - Strongly recommend to look [Peroxide with BLAS](https://github.com/Axect/Peroxide_BLAS))
- `O3-openblas` / `O3-openblas-system` / `O3-accelerate` / `O3-mkl` / `O3-netlib` - BLAS & LAPACK accelerated linear algebra; pick one backend flag (see [Pre-requisite](#pre-requisite))
- `plot` - With matplotlib of python, we can draw any plots.
- `complex` - With complex numbers (vector, matrix and integral)
- `parallel` - With some parallel functions
Expand All @@ -76,7 +76,7 @@ Peroxide provides various features.
- `serde` - serialization with [Serde](https://serde.rs/).
- `rkyv` - serialization with [rkyv](https://rkyv.org).

If you want to do high performance computation and more linear algebra, then choose `O3` feature.
If you want to do high performance computation and more linear algebra, then choose one of the `O3-*` backend features.
If you don't want to depend C/C++ or Fortran libraries, then choose `default` feature.
If you want to draw plot with some great templates, then choose `plot` feature.

Expand Down Expand Up @@ -267,25 +267,27 @@ The three groups below depend on external libraries or runtimes; install the rel
Those crates only provide function signatures, so the link backend that supplies the actual `dgemv_` / `dpotrf_` / ... symbols must be selected separately.
The simplest path is to enable one of the convenience flags below; each pulls in [`blas-src`](https://crates.io/crates/blas-src) and [`lapack-src`](https://crates.io/crates/lapack-src) with the matching backend.

| Convenience flag | Backend | Typical platform / use case |
| ----------------- | ------------------ | --------------------------------------- |
| `O3-openblas` | OpenBLAS | Linux, Windows, macOS via Homebrew |
| `O3-accelerate` | Apple Accelerate | macOS (no extra system install) |
| `O3-mkl` | Intel MKL | Intel CPUs, vendor-tuned performance |
| `O3-netlib` | Netlib reference | Portability, lowest performance |
| Convenience flag | Backend | Build-time requirements |
| -------------------- | ----------------------------- | ------------------------------------------------ |
| `O3-openblas` | OpenBLAS, compiled from source | C + Fortran toolchain, `make`, network access |
| `O3-openblas-system` | System-installed OpenBLAS | `pkg-config` + the OpenBLAS system package |
| `O3-accelerate` | Apple Accelerate | macOS only (no extra system install) |
| `O3-mkl` | Intel MKL | Intel's redistributable (fetched automatically) |
| `O3-netlib` | Netlib reference, compiled from source | `cmake` + Fortran toolchain (lowest performance) |

If you need a backend not in the list above (for example BLIS or R's BLAS), enable the bare `O3` flag and add `blas-src` / `lapack-src` to your downstream binary's `Cargo.toml` with the appropriate features yourself.
`O3-openblas` does **not** use a system-installed OpenBLAS: the [`openblas-src`](https://crates.io/crates/openblas-src) crate downloads the OpenBLAS source tarball during the cargo build and compiles it, so it needs `gcc`, `gfortran`, `make`, and network access, but no BLAS system package.
The download happens over HTTPS through `openblas-src`'s default `rustls` TLS backend; if you depend on `openblas-src` directly with `default-features = false` (as some older guides suggest), you must re-enable one of its `rustls` / `native-tls` features yourself or the build will fail.

System libraries still need to be present on the host for `O3-openblas` and `O3-netlib`; install them with:
`O3-openblas-system` skips the source build and links the OpenBLAS already installed on the host, discovered via `pkg-config`:

| Platform | Install |
| --------------------- | ---------------------------------------------------- |
| Debian / Ubuntu | `sudo apt install libopenblas-dev liblapack-dev` |
| Fedora / RHEL | `sudo dnf install openblas-devel lapack-devel` |
| Arch Linux | `sudo pacman -S openblas lapack` |
| macOS (Homebrew) | `brew install openblas lapack` |
| Debian / Ubuntu | `sudo apt install libopenblas-dev` |
| Fedora / RHEL | `sudo dnf install openblas-devel` |
| Arch Linux | `sudo pacman -S openblas` |
| macOS (Homebrew) | `brew install openblas` |

`O3-accelerate` and `O3-mkl` ship their own backend (Apple's framework and Intel's redistributable, respectively), so they need no further system packages.
If you need a backend not in the list above (for example BLIS or R's BLAS), enable the bare `O3` flag and add `blas-src` / `lapack-src` to your downstream binary's `Cargo.toml` with the appropriate features yourself.

> **Note:** `O3-accelerate` only builds on Apple targets. Enabling it on Linux or Windows fails while compiling `accelerate-src` with ``error: library kind `framework` is only supported on Apple targets``; pick `O3-openblas`, `O3-mkl`, or `O3-netlib` instead. For the same reason, exclude `O3-accelerate` (and `O3-mkl` / `O3-netlib` unless their toolchains are installed) when running tools like `cargo hack --each-feature` on Linux.

Expand Down Expand Up @@ -335,6 +337,7 @@ cargo add peroxide --features "<FEATURES>" # opt-in features
| Goal | Command |
| ------------------------------------------------- | ------------------------------------------------------------------------- |
| Linear algebra on Linux / Windows | `cargo add peroxide --features O3-openblas` |
| Linear algebra with system OpenBLAS | `cargo add peroxide --features O3-openblas-system` |
| Linear algebra on macOS | `cargo add peroxide --features O3-accelerate` |
| Plotting via Python / matplotlib | `cargo add peroxide --features plot` |
| DataFrame + Parquet I/O | `cargo add peroxide --features parquet` |
Expand All @@ -350,7 +353,8 @@ The remaining single-crate flags exist so advanced users can pull in just one op

| Flag | Requires | Purpose |
| ---------------- | ----------------------- | ------------------------------------------------------------- |
| `O3-openblas` | OpenBLAS | BLAS / LAPACK accelerated linear algebra (Linux / Windows) |
| `O3-openblas` | OpenBLAS (from source) | BLAS / LAPACK accelerated linear algebra (Linux / Windows) |
| `O3-openblas-system` | OpenBLAS (system) | Same, linking the system-installed OpenBLAS via pkg-config |
| `O3-accelerate` | Apple Accelerate | Same, using the Accelerate framework on macOS |
| `O3-mkl` | Intel MKL | Same, using Intel MKL |
| `O3-netlib` | Netlib | Same, using the reference Netlib BLAS |
Expand All @@ -363,6 +367,7 @@ The remaining single-crate flags exist so advanced users can pull in just one op
| `json` | (pure Rust) | JSON I/O for `DataFrame` |
| `serde` | (pure Rust) | `serde` (de)serialization |
| `rkyv` | (pure Rust) | `rkyv` zero-copy (de)serialization |
| `rand` | (pure Rust) | Random sampling stack: distributions, RNG wrappers, `rand()` constructors. **On by default**; disable with `default-features = false` to get the deterministic core (ODE, integration, splines, linear algebra) for sandboxed targets like wasm32 |

<details>
<summary><b>Advanced: single-crate flags</b></summary>
Expand Down
25 changes: 25 additions & 0 deletions RELEASES.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,28 @@
# Release 0.43.0 (2026-07-11)

## Breaking changes

- Make the `rand` / `rand_distr` sampling stack optional behind the default-on `rand` feature ([#88](https://github.com/Axect/Peroxide/issues/88), [#104](https://github.com/Axect/Peroxide/pull/104))
- Existing default-feature users are unchanged.
- `default-features = false` now provides a deterministic core without RNG dependencies; sampling APIs require the `rand` feature.
- This is a breaking change for users who already disabled default features and relied on sampling APIs.

## New features

- Add the `Dirichlet(α)` probability distribution ([#95](https://github.com/Axect/Peroxide/pull/95))
- Add `O3-openblas-system` for linking a system-installed OpenBLAS through `pkg-config` ([#98](https://github.com/Axect/Peroxide/issues/98), [#107](https://github.com/Axect/Peroxide/pull/107))

## Documentation

- Clarify BLAS/LAPACK backend selection, OpenBLAS source versus system builds, TLS prerequisites, and HDF5 constraints ([#98](https://github.com/Axect/Peroxide/issues/98))
- Remove the stale `Peroxide_BLAS` setup link from the main README; the archived repository is retained for historical reference
- Replace the hand-maintained source-layout table with module-level docs.rs pointers and improve module descriptions ([#99](https://github.com/Axect/Peroxide/issues/99), [#108](https://github.com/Axect/Peroxide/pull/108))

## CI / Lint

- Add cargo-hack coverage for individual features and pairwise pure-Rust feature combinations ([#98](https://github.com/Axect/Peroxide/issues/98))
- Add dedicated CI coverage for system/source OpenBLAS, no-rand `wasm32`, plotting, formatting, and clippy

# Release 0.42.0 (2026-07-06)

## Breaking changes
Expand Down
2 changes: 1 addition & 1 deletion TODO.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
- [x] Bernoulli
- [x] Beta
- [x] Binomial
- [ ] Dirichlet
- [x] Dirichlet
- [x] Gamma
- [x] Student's t
- [x] Uniform
Expand Down
2 changes: 1 addition & 1 deletion src/complex/matrix.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ use std::{
use anyhow::{bail, Result};
use matrixmultiply::CGemmOption;
use num_complex::Complex;
use num_traits::{One, Zero};
use peroxide_num::{ExpLogOps, PowOps, TrigOps};
use rand_distr::num_traits::{One, Zero};

use crate::{
complex::C64,
Expand Down
2 changes: 2 additions & 0 deletions src/complex/mod.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
//! Complex vectors, matrices, and integrals, enabled by the `complex` feature

use num_complex::Complex;

pub type C64 = Complex<f64>;
Expand Down
12 changes: 10 additions & 2 deletions src/fuga/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -183,10 +183,17 @@ pub use crate::complex::{integral::*, matrix::*, vector::*, C64};
#[allow(ambiguous_glob_reexports)]
pub use crate::structure::{ad::*, dataframe::*, matrix::*, polynomial::*, vector::*};

pub use crate::util::{api::*, low_level::*, non_macro::*, print::*, useful::*, wrapper::*};
pub use crate::util::{api::*, low_level::*, non_macro::*, print::*, useful::*};

#[cfg(feature = "rand")]
pub use crate::util::wrapper::*;

#[allow(unused_imports)]
pub use crate::statistics::{ops::*, stat::*};

#[cfg(feature = "rand")]
#[allow(unused_imports)]
pub use crate::statistics::{dist::*, ops::*, rand::*, stat::*};
pub use crate::statistics::{dist::*, rand::*};

#[allow(unused_imports)]
pub use crate::special::function::*;
Expand All @@ -205,6 +212,7 @@ pub use crate::util::plot::*;

pub use anyhow;
pub use paste;
#[cfg(feature = "rand")]
pub use rand::prelude::*;

// =============================================================================
Expand Down
Loading
Loading