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
3 changes: 3 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,9 @@ jobs:
- name: Run tests
run: cargo test

- name: Run facade README doctests
run: cargo test -p strided-rs --doc

coverage:
name: coverage
runs-on: ubuntu-latest
Expand Down
3 changes: 3 additions & 0 deletions .github/workflows/docs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,10 @@ jobs:
<!DOCTYPE html><html><head><meta charset="utf-8"><title>strided-rs docs</title>
<style>body{font-family:sans-serif;max-width:600px;margin:40px auto;padding:0 20px}a{display:block;margin:8px 0}</style>
</head><body><h1>strided-rs</h1>
<a href="strided_rs/">strided-rs</a>
<a href="strided_traits/">strided-traits</a>
<a href="strided_view/">strided-view</a>
<a href="strided_perm/">strided-perm</a>
<a href="strided_kernel/">strided-kernel</a>
<a href="strided_einsum2/">strided-einsum2</a>
<a href="strided_opteinsum/">strided-opteinsum</a>
Expand Down
48 changes: 47 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,3 +1,49 @@
[workspace]
members = ["strided-traits", "strided-view", "strided-perm", "strided-kernel", "strided-einsum2", "strided-opteinsum", "mdarray-opteinsum", "ndarray-opteinsum"]
members = [
"strided-rs",
"strided-traits",
"strided-view",
"strided-perm",
"strided-kernel",
"strided-einsum2",
"strided-opteinsum",
"mdarray-opteinsum",
"ndarray-opteinsum",
]
resolver = "2"

[workspace.package]
version = "0.1.0"
edition = "2021"
license = "MIT OR Apache-2.0"
authors = ["Satoshi Terasaki", "Hiroshi Shinaoka"]
repository = "https://github.com/tensor4all/strided-rs"

[workspace.dependencies]
strided-rs = { version = "0.1.0", path = "strided-rs" }
strided-traits = { version = "0.1.0", path = "strided-traits" }
strided-view = { version = "0.1.0", path = "strided-view" }
strided-perm = { version = "0.1.0", path = "strided-perm" }
strided-kernel = { version = "0.1.0", path = "strided-kernel" }
strided-einsum2 = { version = "0.1.0", path = "strided-einsum2", default-features = false }
strided-opteinsum = { version = "0.1.0", path = "strided-opteinsum", default-features = false }
mdarray-opteinsum = { version = "0.1.0", path = "mdarray-opteinsum", default-features = false }
ndarray-opteinsum = { version = "0.1.0", path = "ndarray-opteinsum", default-features = false }

approx = "0.5"
cblas-inject = "0.1"
cblas-sys = "0.2"
criterion = "0.5"
faer = "0.24"
faer-traits = "0.24"
mdarray = "0.8.0"
ndarray = "0.17"
num-complex = "0.4"
num-traits = "0.2"
omeco = "0.2"
pulp = "0.22"
rand = "0.8"
rand_distr = "0.4"
rayon = "1.10"
smallvec = "1"
thiserror = "1.0"
42 changes: 23 additions & 19 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,17 @@ It is inspired by Julia's [Strided.jl](https://github.com/Jutho/Strided.jl),
[StridedViews.jl](https://github.com/Jutho/StridedViews.jl), and
[OMEinsum.jl](https://github.com/under-Peter/OMEinsum.jl).

The recommended user-facing crate is [`strided-rs`](strided-rs/README.md).
Use individual crates such as `strided-perm`, `strided-view`, or
`strided-kernel` directly when you need a smaller dependency surface or a
lower-level API.

## Workspace Layout

- [`strided-rs`](strided-rs/README.md): facade crate that re-exports the main workspace APIs
- [`strided-traits`](strided-traits/): shared scalar and element-operation traits
- [`strided-view`](strided-view/README.md): core dynamic-rank strided view/array types and metadata ops
- [`strided-perm`](strided-perm/README.md): cache-efficient tensor permutation / transpose
- [`strided-kernel`](strided-kernel/README.md): cache-optimized elementwise/reduction kernels over strided views
- [`strided-einsum2`](strided-einsum2/README.md): binary einsum (`einsum2_into`) on strided tensors
- [`strided-opteinsum`](strided-opteinsum/README.md): N-ary einsum frontend with nested notation and contraction-order optimization
Expand All @@ -25,15 +33,20 @@ It is inspired by Julia's [Strided.jl](https://github.com/Jutho/Strided.jl),

## Installation

These crates are currently **not published to crates.io** (`publish = false`).
Use workspace path dependencies:
These crates are being prepared for crates.io publication, but this repository
does not publish them automatically. Until a release is published, use workspace
path dependencies:

```toml
[dependencies]
strided-view = { path = "../strided-rs/strided-view" }
strided-kernel = { path = "../strided-rs/strided-kernel" }
strided-einsum2 = { path = "../strided-rs/strided-einsum2" }
strided-opteinsum = { path = "../strided-rs/strided-opteinsum" }
strided-rs = { path = "../strided-rs/strided-rs" }
```

After publication, use:

```toml
[dependencies]
strided-rs = "0.1"
```

## Documentation
Expand All @@ -54,22 +67,13 @@ CI also builds rustdoc on PRs and deploys workspace docs to GitHub Pages on `mai

## Quick Start

```rust
use strided_kernel::{StridedArray, map_into};

// Create a row-major 2D array
let src = StridedArray::<f64>::from_fn_row_major(&[2, 3], |idx| {
(idx[0] * 10 + idx[1]) as f64
});
let mut dest = StridedArray::<f64>::row_major(&[2, 3]);

// Element-wise map: dest[i] = src[i] * 2
map_into(&mut dest.view_mut(), &src.view(), |x| x * 2.0).unwrap();
assert_eq!(dest.get(&[1, 2]), 24.0); // (1*10 + 2) * 2
```
See the [`strided-rs` Quick Start](strided-rs/README.md#quick-start). The Rust
example there is included in crate docs and verified by doctests in CI.

See each sub-crate README for detailed API examples and benchmarks:
- [`strided-rs`](strided-rs/README.md) — recommended facade crate and executable Quick Start
- [`strided-view`](strided-view/README.md) — types, view operations
- [`strided-perm`](strided-perm/README.md) — permutation and transpose kernels
- [`strided-kernel`](strided-kernel/README.md) — map/reduce/broadcast kernels, [benchmarks](strided-kernel/README.md#benchmarks)
- [`strided-einsum2`](strided-einsum2/README.md) — binary einsum with GEMM backend
- [`strided-opteinsum`](strided-opteinsum/README.md) — N-ary einsum, [benchmarks](strided-opteinsum/README.md#benchmarks)
Expand Down
62 changes: 62 additions & 0 deletions docs/plans/2026-05-12-strided-rs-publish-prep.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
# strided-rs Publish Preparation Implementation Plan

> **For Claude:** REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task.

**Goal:** Add a user-facing `strided-rs` facade crate and prepare the workspace metadata, dependencies, README examples, and CI checks for a future crates.io release without publishing anything.

**Architecture:** The workspace will continue to publish individual low-level crates, while `strided-rs` becomes the recommended entry point that re-exports the core APIs. README examples will live in `strided-rs/README.md` and be included in crate docs so `cargo test -p strided-rs --doc` verifies them.

**Tech Stack:** Rust workspace, Cargo workspace metadata/dependencies, rustdoc doctests, GitHub Actions.

---

### Task 1: Add the Facade Crate

**Files:**
- Create: `strided-rs/Cargo.toml`
- Create: `strided-rs/src/lib.rs`
- Create: `strided-rs/README.md`
- Modify: `Cargo.toml`

**Steps:**
1. Add `strided-rs` to `workspace.members`.
2. Create a package named `strided-rs` with library crate `strided_rs`.
3. Re-export core APIs from `strided-view`, `strided-kernel`, `strided-perm`, `strided-einsum2`, and `strided-opteinsum`.
4. Add optional `mdarray` and `ndarray` features that re-export `mdarray-opteinsum` and `ndarray-opteinsum`.
5. Include `README.md` as crate docs with `#![doc = include_str!("../README.md")]`.

### Task 2: Centralize Cargo Metadata and Dependencies

**Files:**
- Modify: `Cargo.toml`
- Modify: all workspace member `Cargo.toml` files

**Steps:**
1. Add `[workspace.package]` for version, authors, license, repository, and edition.
2. Add `[workspace.dependencies]` for shared external dependencies and internal crates with `version + path`.
3. Convert package metadata and dependency declarations to `workspace = true` where practical.
4. Keep explicit `rust-version` where current crates already need different MSRV values.
5. Do not run `cargo publish`.

### Task 3: Make README Examples Executable

**Files:**
- Modify: `README.md`
- Create/Modify: `strided-rs/README.md`
- Modify: `.github/workflows/ci.yml`

**Steps:**
1. Move the user-facing Quick Start to `strided-rs/README.md`.
2. Keep root README as workspace guidance and link to the facade crate README.
3. Ensure Rust examples in `strided-rs/README.md` are complete doctests.
4. Add an explicit CI step for `cargo test -p strided-rs --doc`.

### Task 4: Verify

**Commands:**
- `cargo fmt --check`
- `cargo test --workspace`
- `cargo test -p strided-rs --doc`
- `cargo publish --workspace --dry-run` only as a dry-run, never without `--dry-run`

**Expected Result:** Formatting and tests pass. Publish dry-run either passes or reports only issues that require actual registry state or final release decisions.
27 changes: 13 additions & 14 deletions mdarray-opteinsum/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,28 +1,27 @@
[package]
name = "mdarray-opteinsum"
version = "0.1.0"
version.workspace = true
edition = "2024"
rust-version = "1.89"
license = "MIT OR Apache-2.0"
authors = ["Satoshi Terasaki", "Hiroshi Shinaoka"]
repository = "https://github.com/tensor4all/strided-rs"
license.workspace = true
authors.workspace = true
repository.workspace = true
description = "N-ary einsum frontend for mdarray arrays, powered by strided-opteinsum."
publish = false

[dependencies]
mdarray = "0.8.0"
strided-opteinsum = { path = "../strided-opteinsum", default-features = false }
strided-view = { path = "../strided-view" }
strided-kernel = { path = "../strided-kernel" }
num-complex = "0.4"
num-traits = "0.2"
thiserror = "1.0"
mdarray.workspace = true
strided-opteinsum = { workspace = true, default-features = false }
strided-view.workspace = true
strided-kernel.workspace = true
num-complex.workspace = true
num-traits.workspace = true
thiserror.workspace = true

[features]
default = ["faer"]
faer = ["strided-opteinsum/faer"]
blas = ["strided-opteinsum/blas"]

[dev-dependencies]
approx = "0.5"
num-complex = "0.4"
approx.workspace = true
num-complex.workspace = true
29 changes: 14 additions & 15 deletions ndarray-opteinsum/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,28 +1,27 @@
[package]
name = "ndarray-opteinsum"
version = "0.1.0"
edition = "2021"
version.workspace = true
edition.workspace = true
rust-version = "1.64"
license = "MIT OR Apache-2.0"
authors = ["Satoshi Terasaki", "Hiroshi Shinaoka"]
repository = "https://github.com/tensor4all/strided-rs"
license.workspace = true
authors.workspace = true
repository.workspace = true
description = "N-ary einsum frontend for ndarray arrays, powered by strided-opteinsum."
publish = false

[dependencies]
ndarray = "0.17"
strided-opteinsum = { path = "../strided-opteinsum", default-features = false }
strided-view = { path = "../strided-view" }
strided-kernel = { path = "../strided-kernel" }
num-complex = "0.4"
num-traits = "0.2"
thiserror = "1.0"
ndarray.workspace = true
strided-opteinsum = { workspace = true, default-features = false }
strided-view.workspace = true
strided-kernel.workspace = true
num-complex.workspace = true
num-traits.workspace = true
thiserror.workspace = true

[features]
default = ["faer"]
faer = ["strided-opteinsum/faer"]
blas = ["strided-opteinsum/blas"]

[dev-dependencies]
approx = "0.5"
num-complex = "0.4"
approx.workspace = true
num-complex.workspace = true
43 changes: 21 additions & 22 deletions strided-einsum2/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,37 +1,36 @@
[package]
name = "strided-einsum2"
version = "0.1.0"
edition = "2021"
license = "MIT OR Apache-2.0"
authors = ["Satoshi Terasaki", "Hiroshi Shinaoka"]
repository = "https://github.com/tensor4all/strided-rs"
version.workspace = true
edition.workspace = true
license.workspace = true
authors.workspace = true
repository.workspace = true
description = "Binary einsum (pairwise tensor contraction) on strided views."
publish = false

[dependencies]
strided-traits = { path = "../strided-traits" }
strided-view = { path = "../strided-view" }
strided-kernel = { path = "../strided-kernel" }
strided-perm = { path = "../strided-perm" }
num-traits = "0.2"
thiserror = "1.0"
faer = { version = "0.24", optional = true }
faer-traits = { version = "0.24", optional = true }
cblas-sys = { version = "0.2", optional = true }
cblas-inject = { version = "0.1", optional = true }
num-complex = { version = "0.4", optional = true }
rayon = { version = "1.10", optional = true }
strided-traits.workspace = true
strided-view.workspace = true
strided-kernel.workspace = true
strided-perm.workspace = true
num-traits.workspace = true
thiserror.workspace = true
faer = { workspace = true, optional = true }
faer-traits = { workspace = true, optional = true }
cblas-sys = { workspace = true, optional = true }
cblas-inject = { workspace = true, optional = true }
num-complex = { workspace = true, optional = true }
rayon = { workspace = true, optional = true }

[features]
default = ["faer", "faer-traits"]
parallel = ["rayon", "strided-kernel/parallel", "strided-perm/parallel"]
parallel = ["dep:rayon", "strided-kernel/parallel", "strided-perm/parallel"]
blas = ["dep:cblas-sys", "dep:num-complex"]
blas-inject = ["dep:cblas-inject", "dep:num-complex"]

[dev-dependencies]
approx = "0.5"
num-complex = "0.4"
rand = "0.8"
approx.workspace = true
num-complex.workspace = true
rand.workspace = true

[lib]
bench = false
10 changes: 5 additions & 5 deletions strided-einsum2/src/backend.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
//! Backend abstraction for batched GEMM dispatch.
//!
//! This module defines the [`Backend`] trait, marker structs for each backend,
//! and the [`ActiveBackend`] type alias that serves as the single point of
//! and the `ActiveBackend` type alias that serves as the single point of
//! backend selection based on Cargo features.

/// Trait for backends that can execute batched GEMM on contiguous operands.
Expand Down Expand Up @@ -95,10 +95,10 @@ impl<T: crate::ScalarBase> Backend<T> for NaiveBackend {

/// The active GEMM backend, selected by Cargo features.
///
/// - `faer` (without blas/blas-inject) -> [`FaerBackend`]
/// - `blas` or `blas-inject` (without faer) -> [`BlasBackend`]
/// - no backend feature -> [`NaiveBackend`]
/// - invalid combos -> [`NaiveBackend`] (placeholder; `compile_error!` fires first)
/// - `faer` (without blas/blas-inject) -> `FaerBackend`
/// - `blas` or `blas-inject` (without faer) -> `BlasBackend`
/// - no backend feature -> `NaiveBackend`
/// - invalid combos -> `NaiveBackend` (placeholder; `compile_error!` fires first)
#[cfg(all(feature = "faer", not(any(feature = "blas", feature = "blas-inject"))))]
pub type ActiveBackend = FaerBackend;

Expand Down
Loading
Loading