Skip to main content

tenferro_runtime/
lib.rs

1//! Traced graph runtime and extension dispatch infrastructure for tenferro.
2//!
3//! This crate owns graph construction, lowering to execution IR, graph
4//! execution, and backend-parametric extension runtime dispatch. Standard
5//! operations are lowered through the runtime's internal operation vocabulary;
6//! tensor storage and backend kernels live in `tenferro-tensor`.
7//!
8//! Use this crate directly when you want concrete tensor helpers or reusable
9//! traced graph execution without opting into autodiff. Start with
10//! [`TypedTensor`] when the scalar type is fixed in Rust, [`Tensor`] when dtype
11//! is selected at runtime, and [`TracedTensor`] plus [`GraphCompiler`] and
12//! [`GraphExecutor`] when the same expression should be compiled once and run
13//! repeatedly. Operation-family crates such as `tenferro-einsum`,
14//! `tenferro-linalg`, and `tenferro-fft` register extension runtimes with
15//! [`GraphExecutor`] when compiled execution reaches those operations.
16//!
17//! User-facing guides live at
18//! <https://tensor4all.org/tenferro-rs/guides/choosing-an-api.html> and
19//! <https://tensor4all.org/tenferro-rs/guides/execution-models.html>.
20//!
21//! # Examples
22//!
23//! ```rust
24//! use tenferro_runtime::{GraphCompiler, GraphExecutor, TracedTensor};
25//! use tenferro_cpu::CpuBackend;
26//!
27//! let x = TracedTensor::from_vec_col_major(vec![2], vec![1.0_f64, 2.0]).unwrap();
28//! let y = (&x + &x).unwrap();
29//! let mut compiler = GraphCompiler::new();
30//! let program = compiler.compile(&y).unwrap();
31//! let out = GraphExecutor::new(CpuBackend::default()).run(&program).unwrap();
32//! assert_eq!(out.as_slice::<f64>().unwrap(), &[2.0, 4.0]);
33//! ```
34
35#[doc(hidden)]
36pub mod ad_support;
37mod checkpoint;
38mod compiler;
39pub mod error;
40mod exec;
41pub mod extension;
42pub mod extension_cache;
43pub mod extension_runtime;
44pub mod graph;
45mod metadata;
46#[doc(hidden)]
47pub mod scalar_semantics;
48mod segment;
49mod shape_infer;
50mod shape_packing;
51pub mod sym_dim;
52mod tensor;
53pub mod traced;
54mod typed_tensor;
55
56pub use compiler::{CompilerOptions, OptimizerConfig};
57pub use error::{ContextId, Error, Result};
58pub use extension_cache::{
59    ExtensionCacheKey, ExtensionCacheLimits, ExtensionCacheSelector, ExtensionCacheStore,
60};
61pub use extension_runtime::{
62    ExtensionExecutionContext, ExtensionExecutor, ExtensionRegistry, ExtensionRuntime,
63    ExtensionRuntimeRegistryError, HostReferenceRuntime,
64};
65pub use graph::{
66    GraphCompiler, GraphCompilerCacheStats, GraphExecutor, GraphExecutorCacheStats,
67    GraphInstructionView, GraphOpView, GraphProgram, GraphProgramInput,
68    GraphProgramLoweringShapeError, GraphProgramLoweringView,
69};
70pub use shape_packing::TracedSliceBuilder;
71pub use sym_dim::SymDim;
72pub use tenferro_tensor::{
73    CacheStats, CompareDir, DType, DotGeneralConfig, GatherConfig, PadConfig, ScatterConfig,
74    SliceConfig, Tensor, TensorBackend, TensorRead, TensorScalar, TensorValue, TensorView,
75    TypedTensor, TypedTensorView,
76};
77
78/// Backend-explicit concrete tensor operations.
79///
80/// `Tensor` is owned by `tenferro-tensor`, so `tenferro-runtime` exposes these
81/// operations as a crate-root extension trait rather than as inherent methods.
82///
83/// # Public API rationale
84///
85/// This trait is intentionally public: it is the supported non-AD concrete
86/// tensor operation surface for downstream users who want to run operations on
87/// an explicit backend. The old public module/free-function surface was
88/// removed; the private `tensor` module now contains implementation helpers
89/// only and must not be treated as a compatibility API.
90///
91/// # Examples
92///
93/// ```rust
94/// use tenferro_cpu::CpuBackend;
95/// use tenferro_runtime::{Tensor, TensorOpsExt};
96///
97/// let mut backend = CpuBackend::new();
98/// let a = Tensor::from_vec_col_major(vec![2, 2], vec![1.0_f64; 4]).unwrap();
99/// let b = Tensor::from_vec_col_major(vec![2, 2], vec![2.0_f64; 4]).unwrap();
100/// let c = a.matmul(&b, &mut backend).unwrap();
101/// assert_eq!(c.shape(), &[2, 2]);
102/// ```
103pub trait TensorOpsExt {
104    /// Convert to a different dtype using the checked conversion lattice.
105    fn convert<B: TensorBackend>(
106        &self,
107        to: DType,
108        backend: &mut B,
109    ) -> tenferro_tensor::Result<Tensor>;
110    /// Cast to a different dtype using explicit lossy projection.
111    fn cast<B: TensorBackend>(&self, to: DType, backend: &mut B)
112        -> tenferro_tensor::Result<Tensor>;
113    /// Elementwise addition with NumPy-style broadcasting.
114    fn add<B: TensorBackend>(
115        &self,
116        rhs: &Tensor,
117        backend: &mut B,
118    ) -> tenferro_tensor::Result<Tensor>;
119    /// Elementwise subtraction with NumPy-style broadcasting.
120    fn sub<B: TensorBackend>(
121        &self,
122        rhs: &Tensor,
123        backend: &mut B,
124    ) -> tenferro_tensor::Result<Tensor>;
125    /// Elementwise multiplication with NumPy-style broadcasting.
126    fn mul<B: TensorBackend>(
127        &self,
128        rhs: &Tensor,
129        backend: &mut B,
130    ) -> tenferro_tensor::Result<Tensor>;
131    /// Elementwise division with NumPy-style broadcasting.
132    fn div<B: TensorBackend>(
133        &self,
134        rhs: &Tensor,
135        backend: &mut B,
136    ) -> tenferro_tensor::Result<Tensor>;
137    /// Elementwise remainder with NumPy-style broadcasting.
138    fn rem<B: TensorBackend>(
139        &self,
140        rhs: &Tensor,
141        backend: &mut B,
142    ) -> tenferro_tensor::Result<Tensor>;
143    /// Elementwise power with NumPy-style broadcasting.
144    fn pow<B: TensorBackend>(
145        &self,
146        rhs: &Tensor,
147        backend: &mut B,
148    ) -> tenferro_tensor::Result<Tensor>;
149    /// Elementwise maximum with NumPy-style broadcasting.
150    fn maximum<B: TensorBackend>(
151        &self,
152        rhs: &Tensor,
153        backend: &mut B,
154    ) -> tenferro_tensor::Result<Tensor>;
155    /// Elementwise minimum with NumPy-style broadcasting.
156    fn minimum<B: TensorBackend>(
157        &self,
158        rhs: &Tensor,
159        backend: &mut B,
160    ) -> tenferro_tensor::Result<Tensor>;
161    /// Elementwise negation.
162    fn neg<B: TensorBackend>(&self, backend: &mut B) -> tenferro_tensor::Result<Tensor>;
163    /// Elementwise absolute value.
164    fn abs<B: TensorBackend>(&self, backend: &mut B) -> tenferro_tensor::Result<Tensor>;
165    /// Elementwise sign.
166    fn sign<B: TensorBackend>(&self, backend: &mut B) -> tenferro_tensor::Result<Tensor>;
167    /// Elementwise complex conjugate.
168    fn conj<B: TensorBackend>(&self, backend: &mut B) -> tenferro_tensor::Result<Tensor>;
169    /// Elementwise exponential.
170    fn exp<B: TensorBackend>(&self, backend: &mut B) -> tenferro_tensor::Result<Tensor>;
171    /// Elementwise natural logarithm.
172    fn log<B: TensorBackend>(&self, backend: &mut B) -> tenferro_tensor::Result<Tensor>;
173    /// Elementwise sine.
174    fn sin<B: TensorBackend>(&self, backend: &mut B) -> tenferro_tensor::Result<Tensor>;
175    /// Elementwise cosine.
176    fn cos<B: TensorBackend>(&self, backend: &mut B) -> tenferro_tensor::Result<Tensor>;
177    /// Elementwise hyperbolic tangent.
178    fn tanh<B: TensorBackend>(&self, backend: &mut B) -> tenferro_tensor::Result<Tensor>;
179    /// Elementwise square root.
180    fn sqrt<B: TensorBackend>(&self, backend: &mut B) -> tenferro_tensor::Result<Tensor>;
181    /// Elementwise reciprocal square root.
182    fn rsqrt<B: TensorBackend>(&self, backend: &mut B) -> tenferro_tensor::Result<Tensor>;
183    /// Elementwise `exp(x) - 1`.
184    fn expm1<B: TensorBackend>(&self, backend: &mut B) -> tenferro_tensor::Result<Tensor>;
185    /// Elementwise `log(1 + x)`.
186    fn log1p<B: TensorBackend>(&self, backend: &mut B) -> tenferro_tensor::Result<Tensor>;
187    /// Elementwise comparison with NumPy-style broadcasting.
188    fn compare<B: TensorBackend>(
189        &self,
190        rhs: &Tensor,
191        dir: CompareDir,
192        backend: &mut B,
193    ) -> tenferro_tensor::Result<Tensor>;
194    /// Select values from `on_true` or `on_false` using this tensor as condition.
195    fn where_select<B: TensorBackend>(
196        &self,
197        on_true: &Tensor,
198        on_false: &Tensor,
199        backend: &mut B,
200    ) -> tenferro_tensor::Result<Tensor>;
201    /// Clamp values elementwise between lower and upper bounds.
202    fn clamp<B: TensorBackend>(
203        &self,
204        lower: &Tensor,
205        upper: &Tensor,
206        backend: &mut B,
207    ) -> tenferro_tensor::Result<Tensor>;
208    /// Rank-2 matrix multiplication.
209    fn matmul<B: TensorBackend>(
210        &self,
211        rhs: &Tensor,
212        backend: &mut B,
213    ) -> tenferro_tensor::Result<Tensor>;
214    /// Reshape without changing element order.
215    fn reshape<B: TensorBackend>(
216        &self,
217        shape: &[usize],
218        backend: &mut B,
219    ) -> tenferro_tensor::Result<Tensor>;
220    /// Permute axes.
221    fn transpose<B: TensorBackend>(
222        &self,
223        perm: &[usize],
224        backend: &mut B,
225    ) -> tenferro_tensor::Result<Tensor>;
226    /// Sum over one or more axes.
227    fn reduce_sum<B: TensorBackend>(
228        &self,
229        axes: &[usize],
230        backend: &mut B,
231    ) -> tenferro_tensor::Result<Tensor>;
232}
233
234/// Backend-explicit operations for dynamic-rank typed tensors.
235///
236/// `TypedTensor` is owned by `tenferro-tensor`, so `tenferro-runtime` exposes
237/// these operations as a crate-root extension trait rather than as inherent
238/// methods.
239///
240/// # Public API rationale
241///
242/// This trait is intentionally public for the same reason as [`TensorOpsExt`]:
243/// downstream users need a supported backend-explicit typed tensor surface, and
244/// `tenferro-runtime` cannot add inherent methods to a type owned by
245/// `tenferro-tensor`. The private `typed_tensor` module is implementation
246/// detail, not a retained module/free-function API.
247///
248/// # Examples
249///
250/// ```rust
251/// use tenferro_cpu::CpuBackend;
252/// use tenferro_runtime::{TypedTensor, TypedTensorOpsExt};
253///
254/// let mut backend = CpuBackend::new();
255/// let x = TypedTensor::<f64>::from_vec_col_major(vec![2], vec![1.0, 2.0]).unwrap();
256/// let y = TypedTensor::<f64>::from_vec_col_major(vec![2], vec![3.0, 4.0]).unwrap();
257/// let sum = x.add(&y, &mut backend).unwrap();
258/// assert_eq!(sum.host_data().unwrap(), &[4.0, 6.0]);
259/// ```
260pub trait TypedTensorOpsExt<T: TensorScalar> {
261    /// Elementwise addition with NumPy-style broadcasting.
262    fn add<B: TensorBackend>(
263        &self,
264        rhs: &TypedTensor<T>,
265        backend: &mut B,
266    ) -> tenferro_tensor::Result<TypedTensor<T>>;
267    /// Elementwise subtraction with NumPy-style broadcasting.
268    fn sub<B: TensorBackend>(
269        &self,
270        rhs: &TypedTensor<T>,
271        backend: &mut B,
272    ) -> tenferro_tensor::Result<TypedTensor<T>>;
273    /// Elementwise multiplication with NumPy-style broadcasting.
274    fn mul<B: TensorBackend>(
275        &self,
276        rhs: &TypedTensor<T>,
277        backend: &mut B,
278    ) -> tenferro_tensor::Result<TypedTensor<T>>;
279    /// Elementwise division with NumPy-style broadcasting.
280    fn div<B: TensorBackend>(
281        &self,
282        rhs: &TypedTensor<T>,
283        backend: &mut B,
284    ) -> tenferro_tensor::Result<TypedTensor<T>>;
285    /// Elementwise remainder with NumPy-style broadcasting.
286    fn rem<B: TensorBackend>(
287        &self,
288        rhs: &TypedTensor<T>,
289        backend: &mut B,
290    ) -> tenferro_tensor::Result<TypedTensor<T>>;
291    /// Elementwise power with NumPy-style broadcasting.
292    fn pow<B: TensorBackend>(
293        &self,
294        rhs: &TypedTensor<T>,
295        backend: &mut B,
296    ) -> tenferro_tensor::Result<TypedTensor<T>>;
297    /// Elementwise maximum with NumPy-style broadcasting.
298    fn maximum<B: TensorBackend>(
299        &self,
300        rhs: &TypedTensor<T>,
301        backend: &mut B,
302    ) -> tenferro_tensor::Result<TypedTensor<T>>;
303    /// Elementwise minimum with NumPy-style broadcasting.
304    fn minimum<B: TensorBackend>(
305        &self,
306        rhs: &TypedTensor<T>,
307        backend: &mut B,
308    ) -> tenferro_tensor::Result<TypedTensor<T>>;
309    /// Elementwise negation.
310    fn neg<B: TensorBackend>(&self, backend: &mut B) -> tenferro_tensor::Result<TypedTensor<T>>;
311    /// Elementwise absolute value.
312    fn abs<B: TensorBackend>(&self, backend: &mut B) -> tenferro_tensor::Result<TypedTensor<T>>;
313    /// Elementwise sign.
314    fn sign<B: TensorBackend>(&self, backend: &mut B) -> tenferro_tensor::Result<TypedTensor<T>>;
315    /// Elementwise complex conjugate.
316    fn conj<B: TensorBackend>(&self, backend: &mut B) -> tenferro_tensor::Result<TypedTensor<T>>;
317    /// Elementwise exponential.
318    fn exp<B: TensorBackend>(&self, backend: &mut B) -> tenferro_tensor::Result<TypedTensor<T>>;
319    /// Elementwise natural logarithm.
320    fn log<B: TensorBackend>(&self, backend: &mut B) -> tenferro_tensor::Result<TypedTensor<T>>;
321    /// Elementwise sine.
322    fn sin<B: TensorBackend>(&self, backend: &mut B) -> tenferro_tensor::Result<TypedTensor<T>>;
323    /// Elementwise cosine.
324    fn cos<B: TensorBackend>(&self, backend: &mut B) -> tenferro_tensor::Result<TypedTensor<T>>;
325    /// Elementwise hyperbolic tangent.
326    fn tanh<B: TensorBackend>(&self, backend: &mut B) -> tenferro_tensor::Result<TypedTensor<T>>;
327    /// Elementwise square root.
328    fn sqrt<B: TensorBackend>(&self, backend: &mut B) -> tenferro_tensor::Result<TypedTensor<T>>;
329    /// Elementwise reciprocal square root.
330    fn rsqrt<B: TensorBackend>(&self, backend: &mut B) -> tenferro_tensor::Result<TypedTensor<T>>;
331    /// Elementwise `exp(x) - 1`.
332    fn expm1<B: TensorBackend>(&self, backend: &mut B) -> tenferro_tensor::Result<TypedTensor<T>>;
333    /// Elementwise `log(1 + x)`.
334    fn log1p<B: TensorBackend>(&self, backend: &mut B) -> tenferro_tensor::Result<TypedTensor<T>>;
335    /// Elementwise comparison with NumPy-style broadcasting.
336    fn compare<B: TensorBackend>(
337        &self,
338        rhs: &TypedTensor<T>,
339        dir: CompareDir,
340        backend: &mut B,
341    ) -> tenferro_tensor::Result<TypedTensor<bool>>;
342    /// Clamp values elementwise between lower and upper bounds.
343    fn clamp<B: TensorBackend>(
344        &self,
345        lower: &TypedTensor<T>,
346        upper: &TypedTensor<T>,
347        backend: &mut B,
348    ) -> tenferro_tensor::Result<TypedTensor<T>>;
349    /// Rank-2 matrix multiplication.
350    fn matmul<B: TensorBackend>(
351        &self,
352        rhs: &TypedTensor<T>,
353        backend: &mut B,
354    ) -> tenferro_tensor::Result<TypedTensor<T>>;
355    /// Sum over one or more axes.
356    fn reduce_sum<B: TensorBackend>(
357        &self,
358        axes: &[usize],
359        backend: &mut B,
360    ) -> tenferro_tensor::Result<TypedTensor<T>>;
361    /// Reshape through the backend structural operation.
362    fn reshape<B: TensorBackend>(
363        &self,
364        shape: &[usize],
365        backend: &mut B,
366    ) -> tenferro_tensor::Result<TypedTensor<T>>;
367    /// Permute axes through the backend structural operation.
368    fn transpose<B: TensorBackend>(
369        &self,
370        perm: &[usize],
371        backend: &mut B,
372    ) -> tenferro_tensor::Result<TypedTensor<T>>;
373    /// Broadcast into a larger shape.
374    fn broadcast_in_dim<B: TensorBackend>(
375        &self,
376        shape: &[usize],
377        dims: &[usize],
378        backend: &mut B,
379    ) -> tenferro_tensor::Result<TypedTensor<T>>;
380}
381
382/// Backend-explicit bool-mask operations for typed tensors.
383///
384/// # Public API rationale
385///
386/// This trait keeps `where_select` available as a method on bool
387/// `TypedTensor`s while preserving the crate-root extension-trait surface. It
388/// is public because downstream users call it directly; the implementation
389/// helper in the private `typed_tensor` module is not a compatibility API.
390pub trait TypedTensorMaskOpsExt {
391    /// Select typed values using this bool tensor as condition.
392    fn where_select<T: TensorScalar, B: TensorBackend>(
393        &self,
394        on_true: &TypedTensor<T>,
395        on_false: &TypedTensor<T>,
396        backend: &mut B,
397    ) -> tenferro_tensor::Result<TypedTensor<T>>;
398}
399
400pub use traced::TracedTensor;