Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Compatibility and stability policy

Public API contract

matten exports the following public names from the crate root:

#![allow(unused)]
fn main() {
use matten::Tensor;                  // always
use matten::{MattenError, DataFormat}; // always
use matten::MattenLimits;            // always (RFC-018)
use matten::SliceBuilder;            // always; returned by Tensor::slice()
use matten::Element;                 // #[cfg(feature = "dynamic")]
use matten::NumericPolicy;           // #[cfg(feature = "dynamic")] (RFC-017)
}

SliceBuilder is returned by Tensor::slice() and is held by value; users do not need to import it by name in the common case.

IntoSliceRange and SliceConvert are hidden implementation plumbing for SliceBuilder::range. They are exported #[doc(hidden)] and use a private sealed::Sealed supertrait so downstream crates cannot meaningfully implement them. Users never need to name them in imports.

SliceSpecRepr is #[doc(hidden)]; it is a visibility-chain artefact and not part of the stable API.

Panic zone vs Result zone

This split is a permanent design decision and will not change:

ZoneWhenGuarantee
PanicLocal, trusted, literal constructionRich matten … error in …: message
ResultAny external boundary (parsing, files, user shapes)Result<Tensor, MattenError> — never panics on ordinary input

See Error model for the full list of each zone’s APIs.

Feature flags

FeatureDefaultStability
serdeyesstable
jsonyesstable
csvyesstable
dynamicnostable (dynamic ingestion)

Disabling default features is supported: default-features = false gives the lean core. Enabling dynamic does not rename or remove any numeric Tensor API.

v0.x compatibility

matten is on the v0.x line. The policy:

  • Breaking changes are allowed but must be documented in CHANGELOG.
  • Public API churn decreases after each minor release.
  • Feature-gated additions (new #[cfg] methods) are not breaking.
  • #[non_exhaustive] on MattenError and DataFormat means match arms must include a wildcard — new variants may be added without a semver break.

Family version and core dependency requirement

The published crates are released as one lock-step family (RFC-030): matching crate versions are the supported, documented set. Downstream examples therefore show explicit matched pins such as matten = "0.46.0" plus a companion at the same release.

Inside the workspace, companion crates inherit the core dependency from [workspace.dependencies] as a broad pre-1.0 requirement (matten = "0" plus a local path). This is a maintenance policy (RFC-064): it reduces version-line churn in member manifests while keeping release identity, maturity labels, and user-facing install guidance tied to the lock-step family.

matten-stats — a deliberate ddof divergence (RFC-078, RFC-083, RFC-084)

matten-stats is a companion crate at production-ready candidate maturity (RFC-084, promoted from Experimental once its six-function surface settled — no usage-history claim is made; that is what the candidate label is for). Its covariance and correlation functions use the sample estimator (ddof = 1, i.e. divide by n - 1), diverging deliberately from core matten’s population var/std (ddof = 0). This matches the near-universal default in inferential statistics (NumPy, R, pandas) and is the only behavioral divergence between a companion and core in the family. correlation is unaffected by the choice — the n - 1 factors cancel — so only covariance’s numeric output actually differs from what core’s population convention would produce. covariance_population (RFC-083) gives the population estimator explicitly, and skewness/kurtosis (RFC-083) each match their own ecosystem default rather than always bias-correcting. See RFC-078 §4.1 and RFC-083 §4.1 for the full rationale.

v1.0 requirements

v1.0.0 requires explicit maintainer confirmation. Before that can happen:

  • public API review must be complete;
  • cargo public-api snapshot must be taken and approved;
  • the panic/Result split must be finalised;
  • the serde canonical format must be declared stable;
  • limitations and non-goals must be clearly documented;
  • if any lock-step family crate remains production-ready candidate, the v1.0 release RFC must include the RFC-067 family maturity table and explicitly decide that crate’s inclusion without silently promoting its maturity label.

MSRV

rust-version = "1.85" (Rust 2024 edition). The MSRV may be relaxed in a future release; it will not be raised without a documented breaking change.

Formatting contract

Tensor implements Debug for compact, single-line inspection output, and — as of RFC-100 — Display for a human-facing rendering: rank 0/1/2 as a right-aligned grid, rank > 2 as a flat shape=... values=... list, truncated past 12 values/columns unless {:#} is used. See Display / formatting for the full contract. Both are now a documented compatibility surface — a change to either’s exact output is a breaking change to be treated with the same care as any other public API.

Deferred items

The following items were considered and explicitly deferred:

ItemStatusReason
Display for TensorImplementedRFC-100: rank ≤ 2 as a right-aligned grid, rank > 2 flat; see the Formatting contract section above.
is_empty()Implemented (RFC-108)len() == 0 is reachable via slicing to a zero-sized shape (e.g. t.slice().range(0..0).all().build()) and, since RFC-111, directly via any constructor (Tensor::try_new(vec![], &[0, 3]) now succeeds). is_empty() returns self.len() == 0; false for every scalar (len() == 1) and every ordinary tensor.
set_flatNot planned under that nameThe shipped spelling is get_flat_mut*t.get_flat_mut(i)? = v — mirroring get_flat rather than adding a set_* family; see the Mutable element API row below.
arange max elements1<<20 (~1 M)Lowered from 1<<28 in v0.12.0 for OOM safety.
get_flatImplementedTensor::get_flat(index) -> Option<f64> added in v0.11.0.
Negative slice indicesSupportedShipped in 0.41.0 (RFC-088). slice_str("-1,:") takes the last row; out-of-range errors rather than clamping. slice()’s builder does not accept them.
Step slicing ::2Supportedslice_str("0:10:2") grammar works.
Mutable element APISupportedRFC-104. get_mut(coord) / get_flat_mut(index) on numeric tensors, mirroring get/get_flat exactly (Option<&mut f64>, same panic-on-dynamic guard). get_element_mut(coord) on dynamic tensors (Option<&mut Element>) — the caller reads, changes, or replaces the variant; the library never chooses one, so there is no coercion question. This was previously deferred on the claim that mutation needs a representation change first — that claim was wrong: Tensor already owns its Vec<f64> outright, so &mut self is exclusive by the borrow checker and there is nothing to reconcile. On a dynamic tensor whose storage is shared (e.g. an RFC-102 slice), the first write materializes it — copying into a fresh allocation and detaching from the source, so the write can never reach a shared parent. This is a no-op when already uniquely owned. One side effect worth knowing: materializing a slice releases the source’s allocation it was otherwise keeping alive — RFC-102’s retention cost arriving here as an incidental escape hatch. IndexMut, iter_mut, as_mut_slice, and set/set_flat remain deliberately out of scope — see Mutable element access for the full contract.
Slicing on dynamic tensorsSupportedRFC-102. slice().build() and slice_str() work on dynamic tensors, returning a dynamic tensor with is_dynamic() == true. Storage is shared, not copied (Arc::clone, RFC-012’s copy-on-write model) — slicing selects positions; it does not interpret Element values, so Text, None, and Bool survive a slice unchanged alongside Int/Float. The slice grammar and every numeric result are unchanged. Sharing has a retention cost: a slice keeps its source’s entire allocation alive for as long as the slice lives, even after the source is dropped. Release it explicitly with Tensor::from_elements(slice.to_elements(), slice.shape()). See Slicing for details.
Batched matmul (rank > 2)Not plannedThe boundary is deliberate, not a gap: rank > 2 exists for shape manipulationreshape, transpose, swap_axes, stack all accept it — and arithmetic is rank ≤ 2. matmul/dot support [n]×[n], [m,n]×[n], [n]×[n,p] and [m,n]×[n,p]. A batched result would also be rank 3, which Display renders as a flat list by design (see the Formatting contract section), so the output would be less readable than looping over rank-2 multiplications.
Axis reductions on dynamicNot needed yetConvert with try_numeric() first.

Phase status

The v0.20 family completed the materialization phase: the core numeric comfort APIs (RFC-038 — elementwise, selection, creation, and shape helpers) and the 30_40_ famous-problem examples program (RFC-043–048). The matten-data CSV→tensor ingestion API first shipped in this family (RFC-034, RFC-035).

The v0.21 family delivered selective boundary implementation: shape composition (concatenate / stack), small statistics (var / std), linalg-lite helpers (norm / trace / outer), and the matten-data scope guard. These are additive under lock-step family versioning (RFC-030).

The v0.22 family promotes matten-data to Beta: the RFC-036 example suite (data_00data_05) plus an explicit malformed-CSV test complete the documented Beta gate (RFC-023 §9). Maturity is a per-crate Status label, not a separate version, under lock-step family versioning (RFC-030).

The v0.23 family adds the production migration guide (RFC-050–052): when to stay vs. migrate, per-target playbooks (ndarray, nalgebra, Polars/Pandas, Candle, NumPy), and the bridge conversion-contract template with the matten-ndarray reference contract. This is documentation only — no public API, runtime, or dependency change, and core matten gains no dependency.

The v0.24 family completes the reduction surface (RFC-055 / RFC-056): every scalar value reduction (try_sum / try_mean / try_min / try_max / try_norm) and every axis reduction (try_sum_axis / try_mean_axis / try_min_axis / try_max_axis) now has a non-panicking Result form, joining try_var / try_std and their axis variants. The panic forms are unchanged in behaviour and remain convenience wrappers. These are additive under lock-step family versioning (RFC-030); no existing signature, numeric result, output shape, NaN policy, or dependency changes, and core matten gains no dependency.

The v0.25 family opens the companion-maturity line by promoting matten-ndarray from production-ready candidate to production-ready (RFC-057). This is a maturity Status label only — no API, runtime, error-variant, dependency, copy-semantics, or ndarray-version change — and it does not imply v1.0, which still requires explicit maintainer confirmation. Under lock-step family versioning (RFC-030) the crate stays on the shared family version. matten-mlprep and matten-data remain at Beta pending their own maturity decisions.

The v0.26 family continues the companion-maturity line by promoting matten-mlprep from Beta to production-ready candidate (RFC-058). Label/docs only — no API, runtime, error-variant, or dependency change. The candidate rung reflects an honest limitation: train_test_split is ordered-only (no shuffle), acceptable if that documented limit is acceptable; full production-ready is deferred (RFC-058 §5.1). This does not imply v1.0. matten-ndarray remains production-ready; matten-data remains Beta pending its own maturity decision.

The v0.27 family completes the companion-maturity line by promoting matten-data from Beta to production-ready candidate (RFC-059), with two promotion-blocking hygiene fixes first (a maturity-neutral package description; required-features = ["csv"] on the data_0X examples). Label/docs/packaging only — no API, runtime, error-variant, or dependency change, and no scope expansion: the RFC-042 lock holds (still a CSV→tensor on-ramp, not a dataframe engine). Full production-ready is deferred to a separate future review. This does not imply v1.0. The ladder then read matten-ndarray production-ready, matten-mlprep and matten-data production-ready candidates.

matten-mlprep was subsequently promoted from production-ready candidate to production-ready (RFC-080), now that RFC-058 §5.1’s Option B exit criterion is satisfied: RFC-077 added train_test_split_seeded, closing the ordered-only-split caveat that held the promotion at candidate. Label/docs only — no API, runtime, error-variant, dependency, or version change, and no other crate’s maturity changes. matten-data was production-ready candidate at this point and was later promoted to production-ready as well (RFC-085), once RFC-059 §6’s deferred full-production review ran; matten-stats was Experimental at this point and was later promoted to production-ready candidate as well, once its surface settled (RFC-083, RFC-084).

The v0.28 family moves the matten-ndarray bridge to ndarray 0.17 (RFC-062): the supported requirement changes from the 0.16 minor to 0.17 (CI targets 0.17.2). Because to_arrayd/from_arrayd expose ndarray::ArrayD<f64>, the supported ndarray minor is part of the bridge’s public type identity — consumers build against ndarray 0.17. (ndarray 0.17.0 is yanked; use a non-yanked 0.17 patch.) RFC-062 first evaluated supporting 0.16 and 0.17 together via a bounded range; the maintainer chose the single-version requirement to keep Cargo.toml simple and readable — the architect ruling listed this as an acceptable alternative. No bridge API, behavior, copy-semantics, error, or zero-copy change, and core matten still carries no ndarray dependency. A public-dependency compatibility event handled as a lock-step family minor (RFC-030); it does not imply v1.0.

The v0.29 release family adds RFC-063 visual-understanding work: Markdown / ASCII diagrams for broadcasting, shape operations, matrix multiplication, axis reductions, statistics reductions, dynamic readiness, and the matten-data table-to-Tensor flow; canonical visual-summary examples; and the local-only tools/matten-report Markdown/plain-text report tool. This release does not change public API, published crate dependency graphs, core default features, runtime behavior, MSRV, maturity labels, or scope boundaries. Richer visualization/reporting work remains deferred and requires separate handoffs or RFC approval.

The v0.30 release family adds RFC-065 educational visualization and tensor-learning path work on top of the RFC-063 base: positioning guardrails, worked learner questions for shape/data meaning, and a local-only tools/matten-report --demo educational-path report. This release remains docs/examples/local-tool only: no public visualization/report crate, plotting dependency, expression tracer, autograd, public API change, published dependency change, runtime behavior change, MSRV change, or maturity-label change.

The v0.31 release family is an RFC-066/RFC-067 policy-cleanup release: the reviewed v1.0 readiness audit is recorded, BF-1 is remediated, RFC-067 resolves the MD-1 companion-maturity policy question, and the v1.0 gates now require the RFC-067 family maturity table for any future v1.0 release RFC with candidate-labeled companions. This release does not authorize v1.0 release preparation and does not change public API, published crate dependency graphs, runtime behavior, MSRV, feature flags, maturity labels, or companion scope.

The v0.36 release family adds the RFC-069 input-mode local HTML slice: tools/matten-report can write a bounded static self-contained HTML summary for --input <csv> --kind data-readiness --select <cols> when --format html --output <path> is explicit. Markdown/plain text remains the default report output, HTML still requires explicit --output, and generated artifacts remain local files rather than checked-in assets. The input-mode HTML report is summary-only: it escapes user-controlled strings and bounds column lists, long fields, conversion errors, and tensor previews. This release does not change public API, published crate dependency graphs, core runtime behavior, MSRV, feature flags, maturity labels, or companion scope. Public matten-report / matten-viz crates, core visualization APIs, expression tracing, autograd, SVG, Vega-Lite, JSON report output, notebook, GUI, browser-app scope, and general raw CSV HTML rendering remain deferred.

The v0.37 release family adds the RFC-071 fixed-demo private JSON slice: tools/matten-report can write deterministic private-local JSON artifacts for the five fixed demos when --format json --output <path> is explicit. Markdown remains the default report output, JSON remains local-file-only, and schema_version: 0 means the format is not a public compatibility contract. This release does not change public API, published crate dependency graphs, core runtime behavior, MSRV, feature flags, maturity labels, or companion scope. Public matten-report / matten-viz crates, public report schemas, core visualization APIs, expression tracing, autograd, input-mode JSON, SVG, Vega-Lite, notebook, GUI, browser-app scope, and general raw CSV JSON rendering remain deferred.

The v0.38 release family adds the RFC-073 private input-mode JSON slice: tools/matten-report can write a bounded private-local JSON artifact for the existing CSV data-readiness input path when --format json --output <path> is explicit, covering both successful strict numeric conversion and bounded conversion-error outcomes. input_mode: "csv" extends the schema_version: 0 envelope; the five fixed-demo JSON artifacts remain byte-identical. Every user-controlled string and list (paths, headers, column names, conversion-error text, tensor previews) is bounded with structured truncation metadata; raw CSV rows/cells and unselected cell values are never emitted; non-finite tensor values are rejected before any write. This release does not change public API, published crate dependency graphs, core runtime behavior, MSRV, feature flags, maturity labels, or companion scope. Public matten-report / matten-viz crates, public report schemas, input-mode JSON for other report kinds, raw CSV export, core visualization APIs, expression tracing, autograd, SVG, Vega-Lite, notebook, GUI, and browser-app scope remain deferred.