strided_basic/lib.rs
1#![doc = include_str!("../README.md")]
2
3//! Cache-optimized kernels for strided multidimensional array operations.
4//!
5//! This crate is a Rust port of Julia's [Strided.jl](https://github.com/Jutho/Strided.jl)
6//! and [StridedViews.jl](https://github.com/Jutho/StridedViews.jl) libraries, providing
7//! efficient operations on strided multidimensional array views.
8//!
9//! # Core Types
10//!
11//! - [`StridedView`] / [`StridedViewMut`]: Dynamic-rank strided views over existing data
12//! - [`StridedArray`]: Owned strided multidimensional array
13//! - [`ElementOp`] trait and implementations ([`Identity`], [`Conj`], [`Transpose`], [`Adjoint`]):
14//! Type-level element operations applied lazily on access
15//! - [`Exec`] / [`Pool`]: the placement token every fan-out entry takes as its
16//! last parameter (re-exported from `threadteam`)
17//!
18//! # Primary API (view-based, Julia-compatible)
19//!
20//! ## Map Operations
21//!
22//! - [`map_into`]: Apply a function element-wise from source to destination
23//! - [`zip_map2_into`], [`zip_map3_into`], [`zip_map4_into`]: Multi-array element-wise operations
24//!
25//! ## In-place Update Operations
26//!
27//! - [`map_update_into`], [`zip_update2_into`], [`zip_update3_into`]: `dest[i] = f(dest[i], inputs...)`,
28//! reading the old destination without a second view of it
29//!
30//! ## Reduce Operations
31//!
32//! - [`reduce`]: Full reduction with map function
33//! - [`zip_reduce`]: Two-input full reduction with a map function (the
34//! widening route, e.g. `f32` operands accumulated in `f64`)
35//! - [`reduce_axis`]: Reduce along a single axis
36//!
37//! A reduction that can fan out (`reduce`, `zip_reduce`, `sum`) gives a result
38//! that is independent of the token's budget only for a serial token; `dot`
39//! never enters a parallel branch, so its result does not depend on the token at
40//! all. See each entry's evaluation-order section.
41//!
42//! # Threading
43//!
44//! Every operation that can fan out takes `exec: Exec<'_>` by value as its last
45//! parameter. [`Exec::serial`] runs on the calling thread; a token minted from a
46//! [`Pool`] with [`Exec::new`] splits the work within its budget. Whether and how
47//! wide is decided by the token: the serial time of the region (elements times the
48//! throughput of its `execution::KernelClass`) against the dispatch cost of the
49//! sections it opens (`Exec::pays`, `Exec::width_for`), so a region too small to
50//! repay a fork stays on the calling thread whatever the budget. Without the
51//! `parallel` feature every token runs inline.
52//!
53//! ## Basic Operations
54//!
55//! - [`copy_into`]: Copy array contents
56//! - [`add`], [`mul`]: Element-wise arithmetic
57//! - [`axpy`]: y = alpha*x + y (array version)
58//! - [`sum`], [`dot`]: Reductions
59//! - [`symmetrize_into`], [`symmetrize_conj_into`]: Matrix symmetrization
60//!
61//! # Example
62//!
63//! ```rust
64//! use strided_basic::{StridedView, StridedViewMut, StridedArray, Identity, Exec, map_into};
65//!
66//! // Create a column-major array (Julia default)
67//! let src = StridedArray::<f64>::from_fn_col_major(&[2, 3], |idx| {
68//! (idx[0] * 10 + idx[1]) as f64
69//! });
70//! let mut dest = StridedArray::<f64>::col_major(&[2, 3]);
71//!
72//! // Map with view-based API
73//! map_into(&mut dest.view_mut(), &src.view(), |x| x * 2.0, Exec::serial()).unwrap();
74//! assert_eq!(dest.get(&[1, 2]), 24.0); // (1*10 + 2) * 2
75//! ```
76//!
77//! # Cache Optimization
78//!
79//! The library uses Julia's blocking strategy for cache efficiency:
80//! - Dimensions are sorted by stride magnitude for optimal memory access
81//! - Operations are blocked into tiles fitting L1 cache ([`BLOCK_MEMORY_SIZE`] = 32KB)
82//! - Contiguous arrays use fast paths bypassing the blocking machinery
83
84mod block;
85mod complex_div;
86mod copy_plan;
87mod cost;
88mod dense_update;
89mod erased;
90mod erased_common;
91pub mod execution;
92mod fuse;
93mod inline;
94mod kernel;
95mod layout_check;
96mod map_view;
97mod nan_select;
98mod ops_view;
99mod order;
100mod raw_ops;
101mod reduce_view;
102mod simd;
103mod threading;
104mod update_view;
105pub use complex_div::{robust_complex_divide_f32, robust_complex_divide_f64};
106pub use copy_plan::{CopyPlan, UpdatePlan};
107pub use dense_update::{
108 axpby_accum, embed_diagonal_into_uninit, embed_diagonal_view_into_uninit,
109 triangular_mask_into_uninit, triangular_mask_view_into_uninit,
110};
111pub use erased::{
112 ArgReduceOp, ErasedArgReducePlan, ErasedConcatenatePlan, ErasedCopyPlan, ErasedNormPlan,
113 ErasedReducePlan, ErasedScanPlan, ErasedUpdatePlan, NormKind, NormSpec, ReduceOp, ScanOp,
114 ScanOptions, UpdateOp,
115};
116pub use inline::{InlineVec, OperandVec, OPERAND_CAP};
117pub use map_view::{
118 broadcast_mul_into, broadcast_mul_into_uninit, compare_into, compare_into_uninit, map_into,
119 map_into_uninit_with_kernel, mul_into, mul_into_uninit, zip_map2_into, zip_map3_into,
120 zip_map4_into, Classed, CompareOp, MapFn,
121};
122pub use nan_select::{nan_propagating_maximum, nan_propagating_minimum};
123pub use ops_view::{
124 add, axpy, copy_conj, copy_into, copy_into_col_major, copy_into_uninit, copy_scale,
125 copy_transpose_scale_into, dot, fma, mul, sum, symmetrize_conj_into, symmetrize_into,
126};
127pub use raw_ops::{
128 axpy_conj_raw, axpy_raw, copy_scale_conj_raw, copy_scale_raw, RAW_FUSED_RANK_LIMIT,
129};
130pub use reduce_view::{reduce, reduce_axis, reduce_axis_into, zip_reduce};
131pub use simd::MaybeSimdOps;
132pub use strided_view::view;
133pub use strided_view::*;
134pub use threadteam::{Exec, Pool, PoolBuilder};
135pub use update_view::{map_update_into, zip_update2_into, zip_update3_into};
136/// Block memory size for cache-optimized iteration (L1 cache target).
137///
138/// Operations are blocked into tiles that fit within this size to maximize cache hits.
139/// Default: 32KB (typical L1 data cache size).
140pub const BLOCK_MEMORY_SIZE: usize = 32 * 1024;
141
142/// Cache line size in bytes.
143///
144/// Used for memory region calculations in block size computation.
145pub const CACHE_LINE_SIZE: usize = 64;
146
147mod gather_plan;
148mod outer_product;
149mod static_indexing_plan;
150pub use gather_plan::{
151 DynamicSlicePlan, DynamicUpdateSlicePlan, GatherIndex, GatherPlan, GatherSpec, ScatterPlan,
152 ScatterSpec,
153};
154pub use outer_product::{
155 batched_outer_product_into, batched_outer_product_into_uninit, plan_lazy_outer_product,
156 LazyOuterProductLayout,
157};
158pub use static_indexing_plan::{ConcatenatePlan, PadPlan, ReversePlan, SlicePlan};