API migration guide
This page is the first stop when an older tenferro-rs example fails with cannot find module, cannot find function, or a changed-signature error. The current public API favors explicit extension traits, fallible constructors, and caller-held engines. Historical worklogs are not API documentation.
Removed modules and free functions
| Older spelling | Current spelling |
|---|---|
tenferro_einsum::eager_tensor |
Import tenferro_einsum::EagerSessionEinsumExt and call the trait method on a borrowed session: ctx.with_eager_session(\|s\| s.einsum(&[&a, &b], "ij,jk->ik"))?. |
tenferro_einsum::EagerEinsumExt ([&a, &b].einsum(...) on eager values), EagerTensorEinsumExt (a.tensordot(&b, axes)) |
EagerSessionEinsumExt on a borrowed session: s.einsum(&[&a, &b], "ij,jk->ik"), s.einsum_notation(...), s.einsum_subscripts(...), s.tensordot(&a, &b, axes). |
tenferro_linalg::eager_tensor |
Import tenferro_linalg::EagerTensorLinalgExt and call the trait method on the eager value. |
tenferro_runtime::traced_tensor |
Use the current traced tensor types and their extension traits, such as tenferro_linalg::TracedTensorLinalgExt. |
tenferro_einsum::einsum |
Use the current trait method, for example TraceContextEinsumExt::einsum or TracedTensorEinsumExt::einsum, for the receiver you have. |
tenferro_einsum::einsum_subscripts_with |
Import the owning einsum extension trait and call its session/context method. |
tenferro_linalg::svd, qr, eigh, solve |
Import TensorLinalgExt, TypedTensorLinalgExt, or TensorReadLinalgExt and call .svd(...), .qr(...), .eigh(...), or .solve(...) on the input. |
tenferro_tensor::HostTensor<T> / HostTensorView<'a, T> |
TypedTensor<T, DynRank, Host> (from_host_vec_col_major, as_slice, host_data_mut) and TypedTensorView<'a, T, DynRank, Host> (from_host_slice, as_host_slice). Scalar-set members and ErasedHostTensor payloads use the same types. |
tenferro_tensor::core::{DefaultScalars, HostTensor, ...} |
tenferro_tensor::core re-exports metadata only; import tensor types, including DefaultScalars, from the tenferro_tensor root. |
TypedTensorView::try_slice, try_slice_axis, try_reshape (and the TypedTensorViewMut forms) |
slice_view, slice_axis_view, reshape_view. |
Owner-side execution through a backend-owned copy/canonicalization (to_contiguous / copy_into, TensorFusion, reclaim_buffer, with_linalg_pool, and the CUDA/WebGPU equivalents) |
Call the method on the engine you hold: engine.to_contiguous_read(read)?. The CpuEngine / CudaEngine value replaces the old backend handle, and engine construction is CpuEngine::new(pool) / CpuEngine::serial() / CudaEngine::open(ordinal). |
| The removed backend-session host and its entry wrappers, held sessions and phase leases | Delete the wrapper and pass &mut engine to the operation. There is no entry protocol, no nested-entry error and no held-session type to hold. |
The removed compiled-run entry points on Runtime (the compiled, prepared and deferred run calls) |
let prepared = runtime.prepare(&program, &reads, &[engine.target()])?; then runtime.run(&mut [&mut engine], &prepared, &reads)?; turn each Output into a Tensor with output.into_tensor(&mut engine)?. |
| An eager runtime that owned its backend (backend-owning constructor, CPU placement, a raw execution-session entry) | EagerRuntime::new() stores no engine: call ctx.with_eager_session(&mut engine, \|s\| ...), and pass &mut engine to grad / vjp / jvp / backward / backward_with / to_tensor. |
| Fixed thread-count backends and CPU placement values (auto/all-allowed/NUMA-node), CPU-set and CPU-id selectors | Build the pool yourself: CpuEngine::new(tenferro_cpu::Pool::builder().threads(n).build()?), or CpuEngine::serial() for no pool. Pool is threadteam::Pool, re-exported by tenferro-cpu together with the threadteam crate; the old thread_pool_builder preset, CpuEngine::pool, CpuEngine::pool_stats and CpuEngineError::CallerInOwnPool no longer exist. tenferro no longer constructs pools, resolves placement or verifies affinity. |
| Cloneable backend handles that shared internal state | The engine is a value, not a handle; hold one and borrow it with &mut. Sharing work across threads means one engine per thread or per pool. |
The owning crate’s prelude re-exports the public operation traits. For a first direct CPU program, the usual imports are:
use tenferro_cpu::CpuEngine;
use tenferro_linalg::prelude::*;
use tenferro_runtime::prelude::*;Then borrow one engine for every call:
let mut engine = CpuEngine::serial();
let values = input.svdvals(&mut engine)?;Autodiff context changes
AdContextBuilder::with_core_rules() was removed. The core primitive rules are installed by the normal builder; start with:
let ad = tenferro_ad::AdContext::builder().build()?;When an operation family supplies semantic AD rules, install that family explicitly instead:
let ad = tenferro_ad::AdContext::builder()
.with_semantic_extension_rules(tenferro_linalg::semantic_ad_rules()?)?
.build()?;Fallible constructors and shape APIs
Constructors that validate storage, placement, or metadata return Result. Propagate the result instead of relying on an infallible constructor:
| Older assumption | Current spelling |
|---|---|
EagerTensor::from_tensor_in(tensor, ctx) returns a value |
EagerTensor::from_tensor_in(tensor, ctx)? |
EagerTensor::requires_grad_in(tensor, ctx) returns a value |
EagerTensor::requires_grad_in(tensor, ctx)? |
TracedTensor::input_concrete_shape(dtype, shape) is infallible |
TracedTensor::input_concrete_shape(dtype, shape)? |
TypedTensor::from_vec_col_major(shape, data) is infallible |
TypedTensor::from_vec_col_major(shape, data)? |
TypedTensor::zeros(shape) is infallible |
TypedTensor::zeros(shape)? |
reduce_sum uses an explicit optional axis list on eager values:
let total = value.reduce_sum(None)?; // all axes
let columns = value.reduce_sum(Some(&[0]))?; // selected axesAn empty slice remains distinct from None: use Some(&[]) when the API’s identity/no-axis behavior is what the program needs.
Changed signatures (2026-10)
| Older spelling | Current spelling |
|---|---|
ctx.with_eager_session(\|s\| s.neg(&x))?? (nested Result) |
ctx.with_eager_session(&mut engine, \|s\| s.neg(&x))?: the callback returns Result<T, E> with E: From<tenferro_ad::Error>, and an unregistered engine error arrives as E::from(..). Annotate Ok::<_, tenferro_ad::Error>(..) when the error type is not otherwise inferred; map tensor-level errors with .map_err(tenferro_ad::Error::from). |
ctx.with_eager_session(\|s\| ...) without an engine |
ctx.with_eager_session(&mut engine, \|s\| ...): EagerRuntime stores no engine, so the caller passes one. |
loss.backward(), y.backward_with(&seed), ctx.grad(&loss, &x), ctx.vjp(&y, &x, &seed), ctx.jvp(&y, &x, &tangent), value.to_tensor() |
Each takes the engine first: backward(&mut engine), backward_with(&mut engine, &seed), grad(&mut engine, &loss, &x), vjp(&mut engine, ...), jvp(&mut engine, ...), to_tensor(&mut engine). |
reduce_sum_squares(&x, &[0]) (eager), x.reduce_sum_squares(&[0]) (traced) |
Some(&[0]); None now reduces every axis, as for reduce_sum. |
x.reduce_sum(&[1], session) on Tensor / TypedTensor |
x.reduce_sum(Some(&[1]), session). |
session.gather(&x, &idx, &cfg) and other core ops only on the session |
Also x.gather(&idx, cfg, session) via TensorSessionOpsExt (see the session-surface notes in the guides). |
Tensor::from_vec_col_major with row-major data |
Tensor::from_vec_row_major(shape, data) reorders once into column-major storage. |
compile_with_input_specs with a placeholder the output does not use |
Rejected at compile time (InvalidArgument naming the binding); drop that binding. |
? on EagerFftInPlaceError in a tenferro_ad::Result function |
Works: From<EagerFftInPlaceError> for tenferro_ad::Error drops a rejected input. |
Finding the current method
- Choose the value tier: direct concrete tensor, eager tensor, or traced tensor.
- Import the
*Exttrait owned by the operation crate. - Check the method’s receiver and engine arity in the API cheatsheet.
- Use the linear algebra guide, einsum guide, or custom operations guide for the relevant workflow.
Do not add a compatibility alias for a removed API. If a current example or error message contradicts this page, report the documentation gap through the issue-intake procedure after obtaining maintainer/user approval.