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 depending on `tenferro-ad`. 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//! [`Runtime`] 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 through
15//! runtime engine registrations when compiled execution reaches those
16//! operations.
17//!
18//! User-facing guides live at
19//! <https://tensor4all.org/tenferro-rs/guides/choosing-an-api.html> and
20//! <https://tensor4all.org/tenferro-rs/guides/execution-models.html>.
21//!
22//! # Examples
23//!
24//! ```rust
25//! use tenferro_runtime::{GraphCompiler, Runtime, TracedTensor};
26//! use tenferro_cpu::CpuBackend;
27//!
28//! let x = TracedTensor::from_vec_col_major(vec![2], vec![1.0_f64, 2.0]).unwrap();
29//! let y = (&x + &x).unwrap();
30//! let mut compiler = GraphCompiler::new();
31//! let program = compiler.compile(&y).unwrap();
32//! let backend = CpuBackend::default();
33//! let mut builder = Runtime::builder();
34//! builder.register_engine(tenferro_cpu::runtime_engine_registration(&backend).unwrap()).unwrap();
35//! let runtime = builder.build().unwrap();
36//! let out = runtime.run_compiled(&program, &[]).unwrap().pop().unwrap();
37//! assert_eq!(out.as_slice::<f64>().unwrap(), &[2.0, 4.0]);
38//! ```
39
40#[doc(hidden)]
41pub mod ad_support;
42mod checkpoint;
43mod compiler;
44pub mod error;
45mod exec;
46pub mod extension;
47pub mod extension_cache;
48mod extension_execution_context;
49pub mod graph;
50mod metadata;
51pub mod prelude;
52pub mod program;
53pub mod runtime;
54#[doc(hidden)]
55pub mod scalar_semantics;
56mod segment;
57mod shape_constraint;
58mod shape_infer;
59mod shape_packing;
60pub mod sym_dim;
61mod tensor;
62mod trace;
63pub mod traced;
64mod typed_tensor;
65
66pub use compiler::{CompilerOptions, OptimizerConfig};
67pub use error::{
68 ContextId, Error, ErrorPhase, Result, RuntimeFailureReasonRef, ShapeConstraintEvalError,
69};
70pub use extension_cache::{
71 ExtensionCacheKey, ExtensionCacheLimits, ExtensionCacheSelector, ExtensionCacheStore,
72};
73pub use extension_execution_context::ExtensionExecutionContext;
74pub use graph::{CompiledGraph, GraphCompiler};
75pub use runtime::{
76 assemble_executable_engine_registration, assemble_preparation_only_engine_registration,
77 CacheInFlightBehavior, CacheOwnerError, CacheOwnerFailure, CacheOwnerId, CoreCapabilityBundle,
78 CoreCapabilityBundleBuilder, CoreCapabilityKind, CorePrepareContext, Determinism,
79 DotGeneralPreparation, DotGeneralPrepareRequest, ElementwisePrepareRequest, ElementwiseRuntime,
80 EngineExecutionContractError, EngineId, EngineRegistration, EngineRegistrationMetadata,
81 EngineSnapshotView, ErasedExecutionContext, EventDomainDriver, EventDomainError, EventDomainId,
82 EventDomainOperation, EventDomainRun, EventToken, ExecutableEngineRegistrationConfig,
83 ExecutionBundle, ExecutionContextIdentity, ExecutionContextMismatch, ExecutionHandle,
84 ExecutionInputs, ExecutionOutcome, ExecutionPolicy, ExecutionPolicyError, ExtensionEngine,
85 ExtensionModule, ExtensionModuleError, ExtensionModuleId, ExtensionModuleRegistrar,
86 ExtensionPlanningConfig, ExtensionPrepareRequest, HardwareClassId, IdentityError, IdentityKind,
87 ImmediateEventDomainDriver, IndexingPrepareRequest, IndexingRuntime, InputIngressContract,
88 InputIngressContractError, InputPlacementContract, InputSignature, InputSignatureContract,
89 InputSignatureEntry, InputSignatureError, InputSpecializationProjection,
90 InputSpecializationRequirements, InputSpecializationRequirementsBuilder,
91 InputSpecializationRequirementsError, LayoutClass, LayoutPrepareRequest, LayoutProjection,
92 LayoutRuntime, LayoutSpecialization, OutputAccessError, OutputExtractError, OutputMetadata,
93 OutputRef, PlacementConstraintError, PlacementProjection, PlacementSpecialization,
94 PreparationKeySummary, PreparationOnlyEngineRegistrationConfig, PrepareCapability,
95 PrepareError, PrepareOptions, PrepareOptionsKey, PreparedCompiledGraph, PreparedOperation,
96 PreparedOperationBinding, PreparedOperationExecutor, PreparedOperationExecutorHandle,
97 PreparedOperationHandle, PreparedOperationPlan, PreparedPlanCacheLimits,
98 PreparedPlanCacheStats, ProgramPlacementConstraint, ProviderContractError,
99 ProviderDeviceIdentity, ProviderId, RankRequirement, ReductionPrepareRequest, ReductionRuntime,
100 RegistrationIdentity, RegistrationKey, ResidentOutputContract, ResolvedPlanningConfig,
101 ResolvedPlanningKey, ResolvedProgramPlacement, Runtime, RuntimeCacheError, RuntimeCacheOwner,
102 RuntimeCacheStats, RuntimeConfigBuilder, RuntimeConfigError, RuntimeConfigSnapshot,
103 RuntimeEpoch, RuntimeId, RuntimeInputContract, RuntimeReconfiguration, RuntimeReconfigureError,
104 RuntimeStateError, ScopedExecutionBundle, ScopedExecutionOutcome, ScopedOutput,
105 ScopedOutputExtractError, ScopedReadBinding, ScopedReadInputs, ScopedSubmitRejected,
106 SpecializationError, SpecializationProjection, SpecializationRequirements, StorageClass,
107 SubmissionError, SubmitError, TransferEndpoint, TransferError, TransferProvider,
108 TransferProviderContractError, TransferRequest, UnsupportedReason,
109};
110#[doc(hidden)]
111pub use shape_constraint::ShapeGuard;
112pub use shape_packing::TracedSliceBuilder;
113pub use sym_dim::SymDim;
114pub use tenferro_ops::ShapeRelation;
115pub use tenferro_tensor::{
116 BackendSession, BackendSessionHost, CacheStats, CompareDir, DType, DotGeneralConfig,
117 GatherConfig, MemoryKind, PadConfig, ScatterConfig, SliceConfig, Tensor, TensorBackend,
118 TensorRead, TensorScalar, TensorValue, TensorView, TypedTensor, TypedTensorView,
119};
120pub use trace::{TraceContext, TraceValue, TracedGraph};
121
122pub trait TensorSessionOpsExt {
123 /// Elementwise addition with NumPy-style broadcasting inside a session.
124 ///
125 /// The broadcast (reshape + `broadcast_in_dim`, or a copy when shapes
126 /// already match) and the add itself all run in the caller's `session`;
127 /// this op never enters a session of its own.
128 ///
129 /// # Examples
130 ///
131 /// ```rust
132 /// use tenferro_cpu::CpuBackend;
133 /// use tenferro_runtime::{Tensor, TensorSessionOpsExt};
134 /// use tenferro_tensor::BackendSessionHost;
135 ///
136 /// let mut backend = CpuBackend::new();
137 /// let a = Tensor::from_vec_col_major(vec![2], vec![1.0_f64, 2.0]).unwrap();
138 /// let b = Tensor::from_vec_col_major(vec![2], vec![3.0_f64, 4.0]).unwrap();
139 /// let sum = backend.with_backend_session(|session| a.add(&b, session)).unwrap();
140 /// assert_eq!(sum.as_slice::<f64>().unwrap(), &[4.0, 6.0]);
141 /// ```
142 ///
143 /// # Errors
144 ///
145 /// Returns [`tenferro_tensor::Error::Validation`] with a
146 /// [`ShapeMismatch`](tenferro_tensor::ValidationError::ShapeMismatch) or
147 /// `DTypeMismatch` payload when operands are incompatible, or
148 /// [`tenferro_tensor::Error::BackendSource`] for a typed backend failure.
149 fn add(
150 &self,
151 rhs: &Tensor,
152 session: &mut dyn BackendSession,
153 ) -> tenferro_tensor::Result<Tensor>;
154 /// Elementwise multiplication with NumPy-style broadcasting inside a session.
155 ///
156 /// Like [`Self::add`], broadcast and multiply run in the one `session`.
157 ///
158 /// # Examples
159 ///
160 /// ```rust
161 /// use tenferro_cpu::CpuBackend;
162 /// use tenferro_runtime::{Tensor, TensorSessionOpsExt};
163 /// use tenferro_tensor::BackendSessionHost;
164 ///
165 /// let mut backend = CpuBackend::new();
166 /// let a = Tensor::from_vec_col_major(vec![1], vec![2.0_f64]).unwrap();
167 /// let b = Tensor::from_vec_col_major(vec![4], vec![3.0_f64; 4]).unwrap();
168 /// let product = backend.with_backend_session(|session| a.mul(&b, session)).unwrap();
169 /// assert_eq!(product.as_slice::<f64>().unwrap(), &[6.0; 4]);
170 /// ```
171 ///
172 /// # Errors
173 ///
174 /// Returns [`tenferro_tensor::Error::Validation`] with `ShapeMismatch` or
175 /// `DTypeMismatch` for incompatible operands, or
176 /// [`tenferro_tensor::Error::BackendSource`] for a typed backend failure.
177 fn mul(
178 &self,
179 rhs: &Tensor,
180 session: &mut dyn BackendSession,
181 ) -> tenferro_tensor::Result<Tensor>;
182 /// Elementwise exponential inside a session.
183 ///
184 /// # Examples
185 ///
186 /// ```rust
187 /// use tenferro_cpu::CpuBackend;
188 /// use tenferro_runtime::{Tensor, TensorSessionOpsExt};
189 /// use tenferro_tensor::BackendSessionHost;
190 ///
191 /// let mut backend = CpuBackend::new();
192 /// let x = Tensor::from_vec_col_major(vec![2], vec![0.0_f64, 1.0]).unwrap();
193 /// let y = backend.with_backend_session(|session| x.exp(session)).unwrap();
194 /// let y = y.as_slice::<f64>().unwrap();
195 /// assert!((y[0] - 1.0).abs() < 1.0e-12);
196 /// assert!((y[1] - std::f64::consts::E).abs() < 1.0e-12);
197 /// ```
198 ///
199 /// # Errors
200 ///
201 /// Returns [`tenferro_tensor::Error::Unsupported`] for an unsupported
202 /// dtype or [`tenferro_tensor::Error::BackendSource`] for a typed backend
203 /// failure.
204 fn exp(&self, session: &mut dyn BackendSession) -> tenferro_tensor::Result<Tensor>;
205 /// Sum over one or more axes inside a session.
206 ///
207 /// # Examples
208 ///
209 /// ```rust
210 /// use tenferro_cpu::CpuBackend;
211 /// use tenferro_runtime::{Tensor, TensorSessionOpsExt};
212 /// use tenferro_tensor::BackendSessionHost;
213 ///
214 /// let mut backend = CpuBackend::new();
215 /// let x = Tensor::from_vec_col_major(vec![2, 3], vec![1.0_f64; 6]).unwrap();
216 /// let sums = backend.with_backend_session(|session| x.reduce_sum(&[1], session)).unwrap();
217 /// assert_eq!(sums.as_slice::<f64>().unwrap(), &[3.0, 3.0]);
218 /// ```
219 ///
220 /// # Errors
221 ///
222 /// Returns [`tenferro_tensor::Error::Validation`] with `AxisOutOfBounds`
223 /// or `DuplicateAxis` for invalid reductions, or
224 /// [`tenferro_tensor::Error::BackendSource`] for a typed backend failure.
225 fn reduce_sum(
226 &self,
227 axes: &[usize],
228 session: &mut dyn BackendSession,
229 ) -> tenferro_tensor::Result<Tensor>;
230 /// Convert to a different dtype using the checked conversion lattice inside a session.
231 ///
232 /// # Examples
233 ///
234 /// ```rust
235 /// use tenferro_cpu::CpuBackend;
236 /// use tenferro_runtime::{DType, Tensor, TensorSessionOpsExt};
237 /// use tenferro_tensor::BackendSessionHost;
238 ///
239 /// let mut backend = CpuBackend::new();
240 /// let x = Tensor::from_vec_col_major(vec![2], vec![1.0_f64, 2.0]).unwrap();
241 /// let y = backend.with_backend_session(|session| x.convert(DType::C64, session)).unwrap();
242 /// assert_eq!(y.dtype(), DType::C64);
243 /// ```
244 ///
245 /// # Errors
246 ///
247 /// Returns [`tenferro_tensor::Error::UnsupportedDTypeConversion`] when the
248 /// conversion is outside the checked lattice,
249 /// [`tenferro_tensor::Error::Validation`] with `DTypeMismatch` or
250 /// `InvalidArgument` for invalid tensor metadata, or
251 /// [`tenferro_tensor::Error::BackendSource`] when the backend reports a
252 /// typed failure.
253 fn convert(
254 &self,
255 to: DType,
256 session: &mut dyn BackendSession,
257 ) -> tenferro_tensor::Result<Tensor>;
258 /// Cast to a different dtype using explicit lossy projection inside a session.
259 ///
260 /// # Examples
261 ///
262 /// ```rust
263 /// use tenferro_cpu::CpuBackend;
264 /// use tenferro_runtime::{DType, Tensor, TensorSessionOpsExt};
265 /// use tenferro_tensor::BackendSessionHost;
266 ///
267 /// let mut backend = CpuBackend::new();
268 /// let x = Tensor::from_vec_col_major(vec![2], vec![1.2_f64, -2.8]).unwrap();
269 /// let y = backend.with_backend_session(|session| x.cast(DType::I32, session)).unwrap();
270 /// assert_eq!(y.as_slice::<i32>().unwrap(), &[1, -2]);
271 /// ```
272 ///
273 /// # Errors
274 ///
275 /// Returns [`tenferro_tensor::Error::UnsupportedDTypeConversion`] when the
276 /// requested cast is unsupported, [`tenferro_tensor::Error::Validation`]
277 /// with `DTypeMismatch` or `InvalidArgument` for invalid tensor metadata,
278 /// or [`tenferro_tensor::Error::BackendSource`] for a typed backend
279 /// failure.
280 fn cast(&self, to: DType, session: &mut dyn BackendSession) -> tenferro_tensor::Result<Tensor>;
281 /// Elementwise subtraction with NumPy-style broadcasting inside a session.
282 ///
283 /// Like [`Self::add`], the broadcast and the subtraction run in the one
284 /// `session`.
285 ///
286 /// # Examples
287 ///
288 /// ```rust
289 /// use tenferro_cpu::CpuBackend;
290 /// use tenferro_runtime::{Tensor, TensorSessionOpsExt};
291 /// use tenferro_tensor::BackendSessionHost;
292 ///
293 /// let mut backend = CpuBackend::new();
294 /// let a = Tensor::from_vec_col_major(vec![2], vec![2.0_f64, 4.0]).unwrap();
295 /// let b = Tensor::from_vec_col_major(vec![2], vec![1.0_f64, 8.0]).unwrap();
296 /// let y = backend.with_backend_session(|session| a.sub(&b, session)).unwrap();
297 /// assert_eq!(y.as_slice::<f64>().unwrap(), &[1.0, -4.0]);
298 /// ```
299 ///
300 /// # Errors
301 ///
302 /// Returns [`tenferro_tensor::Error::Validation`] with `ShapeMismatch` or
303 /// `DTypeMismatch` for incompatible operands, or
304 /// [`tenferro_tensor::Error::BackendSource`] for a typed backend failure.
305 fn sub(
306 &self,
307 rhs: &Tensor,
308 session: &mut dyn BackendSession,
309 ) -> tenferro_tensor::Result<Tensor>;
310 /// Elementwise division with NumPy-style broadcasting inside a session.
311 ///
312 /// # Examples
313 ///
314 /// ```rust
315 /// use tenferro_cpu::CpuBackend;
316 /// use tenferro_runtime::{Tensor, TensorSessionOpsExt};
317 /// use tenferro_tensor::BackendSessionHost;
318 ///
319 /// let mut backend = CpuBackend::new();
320 /// let a = Tensor::from_vec_col_major(vec![2], vec![4.0_f64, 8.0]).unwrap();
321 /// let b = Tensor::from_vec_col_major(vec![2], vec![2.0_f64, 4.0]).unwrap();
322 /// let y = backend.with_backend_session(|session| a.div(&b, session)).unwrap();
323 /// assert_eq!(y.as_slice::<f64>().unwrap(), &[2.0, 2.0]);
324 /// ```
325 ///
326 /// # Errors
327 ///
328 /// Returns [`tenferro_tensor::Error::Validation`] with `ShapeMismatch` or
329 /// `DTypeMismatch` for shape/dtype incompatibility,
330 /// [`tenferro_tensor::Error::Extension`] with a numerical classification
331 /// for a detected zero divisor, or
332 /// [`tenferro_tensor::Error::BackendSource`] for a typed backend failure.
333 fn div(
334 &self,
335 rhs: &Tensor,
336 session: &mut dyn BackendSession,
337 ) -> tenferro_tensor::Result<Tensor>;
338 /// Elementwise remainder with NumPy-style broadcasting inside a session.
339 ///
340 /// # Examples
341 ///
342 /// ```rust
343 /// use tenferro_cpu::CpuBackend;
344 /// use tenferro_runtime::{Tensor, TensorSessionOpsExt};
345 /// use tenferro_tensor::BackendSessionHost;
346 ///
347 /// let mut backend = CpuBackend::new();
348 /// let a = Tensor::from_vec_col_major(vec![2], vec![5.0_f64, 7.0]).unwrap();
349 /// let b = Tensor::from_vec_col_major(vec![2], vec![2.0_f64, 4.0]).unwrap();
350 /// let y = backend.with_backend_session(|session| a.rem(&b, session)).unwrap();
351 /// assert_eq!(y.as_slice::<f64>().unwrap(), &[1.0, 3.0]);
352 /// ```
353 ///
354 /// # Errors
355 ///
356 /// Returns [`tenferro_tensor::Error::Validation`] with `ShapeMismatch` or
357 /// `DTypeMismatch` for shape/dtype incompatibility, a numerical
358 /// [`tenferro_tensor::Error::Extension`] for a detected zero divisor, or
359 /// [`tenferro_tensor::Error::BackendSource`] for a typed backend failure.
360 fn rem(
361 &self,
362 rhs: &Tensor,
363 session: &mut dyn BackendSession,
364 ) -> tenferro_tensor::Result<Tensor>;
365 /// Elementwise power with NumPy-style broadcasting inside a session.
366 ///
367 /// # Examples
368 ///
369 /// ```rust
370 /// use tenferro_cpu::CpuBackend;
371 /// use tenferro_runtime::{Tensor, TensorSessionOpsExt};
372 /// use tenferro_tensor::BackendSessionHost;
373 ///
374 /// let mut backend = CpuBackend::new();
375 /// let a = Tensor::from_vec_col_major(vec![2], vec![2.0_f64, 3.0]).unwrap();
376 /// let b = Tensor::from_vec_col_major(vec![2], vec![3.0_f64, 2.0]).unwrap();
377 /// let y = backend.with_backend_session(|session| a.pow(&b, session)).unwrap();
378 /// assert_eq!(y.as_slice::<f64>().unwrap(), &[8.0, 9.0]);
379 /// ```
380 ///
381 /// # Errors
382 ///
383 /// Returns [`tenferro_tensor::Error::Validation`] with `ShapeMismatch` or
384 /// `DTypeMismatch` for incompatible metadata, a numerical
385 /// [`tenferro_tensor::Error::Extension`] for a detected negative integer
386 /// exponent, or [`tenferro_tensor::Error::BackendSource`] for a typed
387 /// backend failure.
388 fn pow(
389 &self,
390 rhs: &Tensor,
391 session: &mut dyn BackendSession,
392 ) -> tenferro_tensor::Result<Tensor>;
393 /// Elementwise maximum with NumPy-style broadcasting inside a session.
394 ///
395 /// # Examples
396 ///
397 /// ```rust
398 /// use tenferro_cpu::CpuBackend;
399 /// use tenferro_runtime::{Tensor, TensorSessionOpsExt};
400 /// use tenferro_tensor::BackendSessionHost;
401 ///
402 /// let mut backend = CpuBackend::new();
403 /// let a = Tensor::from_vec_col_major(vec![2], vec![2.0_f64, 4.0]).unwrap();
404 /// let b = Tensor::from_vec_col_major(vec![2], vec![1.0_f64, 8.0]).unwrap();
405 /// let y = backend.with_backend_session(|session| a.maximum(&b, session)).unwrap();
406 /// assert_eq!(y.as_slice::<f64>().unwrap(), &[2.0, 8.0]);
407 /// ```
408 ///
409 /// # Errors
410 ///
411 /// Returns [`tenferro_tensor::Error::Validation`] with `ShapeMismatch` or
412 /// `DTypeMismatch` for incompatible operands, or
413 /// [`tenferro_tensor::Error::BackendSource`] for a typed backend failure.
414 fn maximum(
415 &self,
416 rhs: &Tensor,
417 session: &mut dyn BackendSession,
418 ) -> tenferro_tensor::Result<Tensor>;
419 /// Elementwise minimum with NumPy-style broadcasting inside a session.
420 ///
421 /// # Examples
422 ///
423 /// ```rust
424 /// use tenferro_cpu::CpuBackend;
425 /// use tenferro_runtime::{Tensor, TensorSessionOpsExt};
426 /// use tenferro_tensor::BackendSessionHost;
427 ///
428 /// let mut backend = CpuBackend::new();
429 /// let a = Tensor::from_vec_col_major(vec![2], vec![2.0_f64, 4.0]).unwrap();
430 /// let b = Tensor::from_vec_col_major(vec![2], vec![1.0_f64, 8.0]).unwrap();
431 /// let y = backend.with_backend_session(|session| a.minimum(&b, session)).unwrap();
432 /// assert_eq!(y.as_slice::<f64>().unwrap(), &[1.0, 4.0]);
433 /// ```
434 ///
435 /// # Errors
436 ///
437 /// Returns [`tenferro_tensor::Error::Validation`] with `ShapeMismatch` or
438 /// `DTypeMismatch` for incompatible operands, or
439 /// [`tenferro_tensor::Error::BackendSource`] for a typed backend failure.
440 fn minimum(
441 &self,
442 rhs: &Tensor,
443 session: &mut dyn BackendSession,
444 ) -> tenferro_tensor::Result<Tensor>;
445 /// Elementwise negation inside a session.
446 ///
447 /// # Examples
448 ///
449 /// ```rust
450 /// use tenferro_cpu::CpuBackend;
451 /// use tenferro_runtime::{Tensor, TensorSessionOpsExt};
452 /// use tenferro_tensor::BackendSessionHost;
453 ///
454 /// let mut backend = CpuBackend::new();
455 /// let x = Tensor::from_vec_col_major(vec![2], vec![1.0_f64, -2.0]).unwrap();
456 /// let y = backend.with_backend_session(|session| x.neg(session)).unwrap();
457 /// assert_eq!(y.as_slice::<f64>().unwrap(), &[-1.0, 2.0]);
458 /// ```
459 ///
460 /// # Errors
461 ///
462 /// Returns [`tenferro_tensor::Error::Unsupported`] when the dtype is not
463 /// supported by the operation, or [`tenferro_tensor::Error::BackendSource`]
464 /// for a typed backend failure.
465 fn neg(&self, session: &mut dyn BackendSession) -> tenferro_tensor::Result<Tensor>;
466 /// Elementwise absolute value inside a session.
467 ///
468 /// # Examples
469 ///
470 /// ```rust
471 /// use tenferro_cpu::CpuBackend;
472 /// use tenferro_runtime::{Tensor, TensorSessionOpsExt};
473 /// use tenferro_tensor::BackendSessionHost;
474 ///
475 /// let mut backend = CpuBackend::new();
476 /// let x = Tensor::from_vec_col_major(vec![2], vec![-1.0_f64, 2.0]).unwrap();
477 /// let y = backend.with_backend_session(|session| x.abs(session)).unwrap();
478 /// assert_eq!(y.as_slice::<f64>().unwrap(), &[1.0, 2.0]);
479 /// ```
480 ///
481 /// # Errors
482 ///
483 /// Returns [`tenferro_tensor::Error::Unsupported`] for an unsupported
484 /// dtype or [`tenferro_tensor::Error::BackendSource`] for a typed backend
485 /// failure.
486 fn abs(&self, session: &mut dyn BackendSession) -> tenferro_tensor::Result<Tensor>;
487 /// Elementwise sign inside a session.
488 ///
489 /// # Examples
490 ///
491 /// ```rust
492 /// use tenferro_cpu::CpuBackend;
493 /// use tenferro_runtime::{Tensor, TensorSessionOpsExt};
494 /// use tenferro_tensor::BackendSessionHost;
495 ///
496 /// let mut backend = CpuBackend::new();
497 /// let x = Tensor::from_vec_col_major(vec![2], vec![1.0_f64, -2.0]).unwrap();
498 /// let y = backend.with_backend_session(|session| x.sign(session)).unwrap();
499 /// assert_eq!(y.as_slice::<f64>().unwrap(), &[1.0, -1.0]);
500 /// ```
501 ///
502 /// # Errors
503 ///
504 /// Returns [`tenferro_tensor::Error::Unsupported`] for an unsupported
505 /// dtype or [`tenferro_tensor::Error::BackendSource`] for a typed backend
506 /// failure.
507 fn sign(&self, session: &mut dyn BackendSession) -> tenferro_tensor::Result<Tensor>;
508 /// Elementwise complex conjugate inside a session.
509 ///
510 /// For real dtypes the conjugate is the identity.
511 ///
512 /// # Examples
513 ///
514 /// ```rust
515 /// use tenferro_cpu::CpuBackend;
516 /// use tenferro_runtime::{Tensor, TensorSessionOpsExt};
517 /// use tenferro_tensor::BackendSessionHost;
518 ///
519 /// let mut backend = CpuBackend::new();
520 /// let x = Tensor::from_vec_col_major(vec![2], vec![1.0_f64, -2.0]).unwrap();
521 /// let y = backend.with_backend_session(|session| x.conj(session)).unwrap();
522 /// assert_eq!(y.as_slice::<f64>().unwrap(), &[1.0, -2.0]);
523 /// ```
524 ///
525 /// # Errors
526 ///
527 /// Returns [`tenferro_tensor::Error::Unsupported`] for an unsupported
528 /// dtype or [`tenferro_tensor::Error::BackendSource`] for a typed backend
529 /// failure.
530 fn conj(&self, session: &mut dyn BackendSession) -> tenferro_tensor::Result<Tensor>;
531 /// Elementwise natural logarithm inside a session.
532 ///
533 /// # Examples
534 ///
535 /// ```rust
536 /// use tenferro_cpu::CpuBackend;
537 /// use tenferro_runtime::{Tensor, TensorSessionOpsExt};
538 /// use tenferro_tensor::BackendSessionHost;
539 ///
540 /// let mut backend = CpuBackend::new();
541 /// let x = Tensor::from_vec_col_major(vec![2], vec![1.0_f64, std::f64::consts::E]).unwrap();
542 /// let y = backend.with_backend_session(|session| x.log(session)).unwrap();
543 /// let y = y.as_slice::<f64>().unwrap();
544 /// assert!(y[0].abs() < 1.0e-12);
545 /// assert!((y[1] - 1.0).abs() < 1.0e-12);
546 /// ```
547 ///
548 /// # Errors
549 ///
550 /// Returns [`tenferro_tensor::Error::Unsupported`] for an unsupported
551 /// dtype or [`tenferro_tensor::Error::BackendSource`] for a typed backend
552 /// failure.
553 fn log(&self, session: &mut dyn BackendSession) -> tenferro_tensor::Result<Tensor>;
554 /// Elementwise `exp(x) - 1` inside a session.
555 ///
556 /// # Examples
557 ///
558 /// ```rust
559 /// use tenferro_cpu::CpuBackend;
560 /// use tenferro_runtime::{Tensor, TensorSessionOpsExt};
561 /// use tenferro_tensor::BackendSessionHost;
562 ///
563 /// let mut backend = CpuBackend::new();
564 /// let x = Tensor::from_vec_col_major(vec![2], vec![0.0_f64, 1.0]).unwrap();
565 /// let y = backend.with_backend_session(|session| x.expm1(session)).unwrap();
566 /// let y = y.as_slice::<f64>().unwrap();
567 /// assert!(y[0].abs() < 1.0e-12);
568 /// assert!((y[1] - (std::f64::consts::E - 1.0)).abs() < 1.0e-12);
569 /// ```
570 ///
571 /// # Errors
572 ///
573 /// Returns [`tenferro_tensor::Error::Unsupported`] for an unsupported
574 /// dtype or [`tenferro_tensor::Error::BackendSource`] for a typed backend
575 /// failure.
576 fn expm1(&self, session: &mut dyn BackendSession) -> tenferro_tensor::Result<Tensor>;
577 /// Elementwise `log(1 + x)` inside a session.
578 ///
579 /// # Examples
580 ///
581 /// ```rust
582 /// use tenferro_cpu::CpuBackend;
583 /// use tenferro_runtime::{Tensor, TensorSessionOpsExt};
584 /// use tenferro_tensor::BackendSessionHost;
585 ///
586 /// let mut backend = CpuBackend::new();
587 /// let x = Tensor::from_vec_col_major(vec![2], vec![0.0_f64, std::f64::consts::E - 1.0]).unwrap();
588 /// let y = backend.with_backend_session(|session| x.log1p(session)).unwrap();
589 /// let y = y.as_slice::<f64>().unwrap();
590 /// assert!(y[0].abs() < 1.0e-12);
591 /// assert!((y[1] - 1.0).abs() < 1.0e-12);
592 /// ```
593 ///
594 /// # Errors
595 ///
596 /// Returns [`tenferro_tensor::Error::Unsupported`] for an unsupported
597 /// dtype or [`tenferro_tensor::Error::BackendSource`] for a typed backend
598 /// failure.
599 fn log1p(&self, session: &mut dyn BackendSession) -> tenferro_tensor::Result<Tensor>;
600 /// Elementwise sine inside a session.
601 ///
602 /// # Examples
603 ///
604 /// ```rust
605 /// use tenferro_cpu::CpuBackend;
606 /// use tenferro_runtime::{Tensor, TensorSessionOpsExt};
607 /// use tenferro_tensor::BackendSessionHost;
608 ///
609 /// let mut backend = CpuBackend::new();
610 /// let x = Tensor::from_vec_col_major(vec![2], vec![0.0_f64, std::f64::consts::FRAC_PI_2]).unwrap();
611 /// let y = backend.with_backend_session(|session| x.sin(session)).unwrap();
612 /// let y = y.as_slice::<f64>().unwrap();
613 /// assert!(y[0].abs() < 1.0e-12);
614 /// assert!((y[1] - 1.0).abs() < 1.0e-12);
615 /// ```
616 ///
617 /// # Errors
618 ///
619 /// Returns [`tenferro_tensor::Error::Unsupported`] for an unsupported
620 /// dtype or [`tenferro_tensor::Error::BackendSource`] for a typed backend
621 /// failure.
622 fn sin(&self, session: &mut dyn BackendSession) -> tenferro_tensor::Result<Tensor>;
623 /// Elementwise cosine inside a session.
624 ///
625 /// # Examples
626 ///
627 /// ```rust
628 /// use tenferro_cpu::CpuBackend;
629 /// use tenferro_runtime::{Tensor, TensorSessionOpsExt};
630 /// use tenferro_tensor::BackendSessionHost;
631 ///
632 /// let mut backend = CpuBackend::new();
633 /// let x = Tensor::from_vec_col_major(vec![2], vec![0.0_f64, std::f64::consts::PI]).unwrap();
634 /// let y = backend.with_backend_session(|session| x.cos(session)).unwrap();
635 /// let y = y.as_slice::<f64>().unwrap();
636 /// assert!((y[0] - 1.0).abs() < 1.0e-12);
637 /// assert!((y[1] + 1.0).abs() < 1.0e-12);
638 /// ```
639 ///
640 /// # Errors
641 ///
642 /// Returns [`tenferro_tensor::Error::Unsupported`] for an unsupported
643 /// dtype or [`tenferro_tensor::Error::BackendSource`] for a typed backend
644 /// failure.
645 fn cos(&self, session: &mut dyn BackendSession) -> tenferro_tensor::Result<Tensor>;
646 /// Elementwise hyperbolic tangent inside a session.
647 ///
648 /// # Examples
649 ///
650 /// ```rust
651 /// use tenferro_cpu::CpuBackend;
652 /// use tenferro_runtime::{Tensor, TensorSessionOpsExt};
653 /// use tenferro_tensor::BackendSessionHost;
654 ///
655 /// let mut backend = CpuBackend::new();
656 /// let x = Tensor::from_vec_col_major(vec![2], vec![0.0_f64, 1.0]).unwrap();
657 /// let y = backend.with_backend_session(|session| x.tanh(session)).unwrap();
658 /// let y = y.as_slice::<f64>().unwrap();
659 /// assert!(y[0].abs() < 1.0e-12);
660 /// assert!((y[1] - 0.7615941559557649).abs() < 1.0e-12);
661 /// ```
662 ///
663 /// # Errors
664 ///
665 /// Returns [`tenferro_tensor::Error::Unsupported`] for an unsupported
666 /// dtype or [`tenferro_tensor::Error::BackendSource`] for a typed backend
667 /// failure.
668 fn tanh(&self, session: &mut dyn BackendSession) -> tenferro_tensor::Result<Tensor>;
669 /// Elementwise square root inside a session.
670 ///
671 /// # Examples
672 ///
673 /// ```rust
674 /// use tenferro_cpu::CpuBackend;
675 /// use tenferro_runtime::{Tensor, TensorSessionOpsExt};
676 /// use tenferro_tensor::BackendSessionHost;
677 ///
678 /// let mut backend = CpuBackend::new();
679 /// let x = Tensor::from_vec_col_major(vec![2], vec![4.0_f64, 9.0]).unwrap();
680 /// let y = backend.with_backend_session(|session| x.sqrt(session)).unwrap();
681 /// assert_eq!(y.as_slice::<f64>().unwrap(), &[2.0, 3.0]);
682 /// ```
683 ///
684 /// # Errors
685 ///
686 /// Returns [`tenferro_tensor::Error::Unsupported`] for an unsupported
687 /// dtype or [`tenferro_tensor::Error::BackendSource`] for a typed backend
688 /// failure.
689 fn sqrt(&self, session: &mut dyn BackendSession) -> tenferro_tensor::Result<Tensor>;
690 /// Elementwise reciprocal square root inside a session.
691 ///
692 /// # Examples
693 ///
694 /// ```rust
695 /// use tenferro_cpu::CpuBackend;
696 /// use tenferro_runtime::{Tensor, TensorSessionOpsExt};
697 /// use tenferro_tensor::BackendSessionHost;
698 ///
699 /// let mut backend = CpuBackend::new();
700 /// let x = Tensor::from_vec_col_major(vec![2], vec![4.0_f64, 1.0]).unwrap();
701 /// let y = backend.with_backend_session(|session| x.rsqrt(session)).unwrap();
702 /// let y = y.as_slice::<f64>().unwrap();
703 /// assert!((y[0] - 0.5).abs() < 1.0e-12);
704 /// assert!((y[1] - 1.0).abs() < 1.0e-12);
705 /// ```
706 ///
707 /// # Errors
708 ///
709 /// Returns [`tenferro_tensor::Error::Unsupported`] for an unsupported
710 /// dtype or [`tenferro_tensor::Error::BackendSource`] for a typed backend
711 /// failure.
712 fn rsqrt(&self, session: &mut dyn BackendSession) -> tenferro_tensor::Result<Tensor>;
713 /// Elementwise comparison with NumPy-style broadcasting inside a session.
714 ///
715 /// The result is a bool tensor.
716 ///
717 /// # Examples
718 ///
719 /// ```rust
720 /// use tenferro_cpu::CpuBackend;
721 /// use tenferro_runtime::{CompareDir, Tensor, TensorSessionOpsExt};
722 /// use tenferro_tensor::BackendSessionHost;
723 ///
724 /// let mut backend = CpuBackend::new();
725 /// let a = Tensor::from_vec_col_major(vec![2], vec![2.0_f64, 4.0]).unwrap();
726 /// let b = Tensor::from_vec_col_major(vec![2], vec![1.0_f64, 8.0]).unwrap();
727 /// let y = backend.with_backend_session(|session| a.compare(&b, CompareDir::Gt, session)).unwrap();
728 /// assert_eq!(y.as_slice::<bool>().unwrap(), &[true, false]);
729 /// ```
730 ///
731 /// # Errors
732 ///
733 /// Returns [`tenferro_tensor::Error::Validation`] with `ShapeMismatch` or
734 /// `DTypeMismatch` for incompatible shape/dtype metadata, or
735 /// [`tenferro_tensor::Error::BackendSource`] for a typed backend failure.
736 fn compare(
737 &self,
738 rhs: &Tensor,
739 dir: CompareDir,
740 session: &mut dyn BackendSession,
741 ) -> tenferro_tensor::Result<Tensor>;
742 /// Select values from `on_true` or `on_false` using this tensor as condition inside a session.
743 ///
744 /// # Examples
745 ///
746 /// ```rust
747 /// use tenferro_cpu::CpuBackend;
748 /// use tenferro_runtime::{Tensor, TensorSessionOpsExt};
749 /// use tenferro_tensor::BackendSessionHost;
750 ///
751 /// let mut backend = CpuBackend::new();
752 /// let condition = Tensor::from_vec_col_major(vec![2], vec![true, false]).unwrap();
753 /// let on_true = Tensor::from_vec_col_major(vec![2], vec![1.0_f64, 2.0]).unwrap();
754 /// let on_false = Tensor::from_vec_col_major(vec![2], vec![3.0_f64, 4.0]).unwrap();
755 /// let y = backend.with_backend_session(|session| condition.where_select(&on_true, &on_false, session)).unwrap();
756 /// assert_eq!(y.as_slice::<f64>().unwrap(), &[1.0, 4.0]);
757 /// ```
758 ///
759 /// # Errors
760 ///
761 /// Returns [`tenferro_tensor::Error::Validation`] with `ShapeMismatch` or
762 /// `DTypeMismatch` when the condition and branches are incompatible, or
763 /// [`tenferro_tensor::Error::BackendSource`] for a typed backend failure.
764 fn where_select(
765 &self,
766 on_true: &Tensor,
767 on_false: &Tensor,
768 session: &mut dyn BackendSession,
769 ) -> tenferro_tensor::Result<Tensor>;
770 /// Clamp values elementwise between lower and upper bounds inside a session.
771 ///
772 /// # Examples
773 ///
774 /// ```rust
775 /// use tenferro_cpu::CpuBackend;
776 /// use tenferro_runtime::{Tensor, TensorSessionOpsExt};
777 /// use tenferro_tensor::BackendSessionHost;
778 ///
779 /// let mut backend = CpuBackend::new();
780 /// let x = Tensor::from_vec_col_major(vec![2], vec![-2.0_f64, 4.0]).unwrap();
781 /// let lower = Tensor::from_vec_col_major(vec![], vec![0.0_f64]).unwrap();
782 /// let upper = Tensor::from_vec_col_major(vec![], vec![3.0_f64]).unwrap();
783 /// let y = backend.with_backend_session(|session| x.clamp(&lower, &upper, session)).unwrap();
784 /// assert_eq!(y.as_slice::<f64>().unwrap(), &[0.0, 3.0]);
785 /// ```
786 ///
787 /// # Errors
788 ///
789 /// Returns [`tenferro_tensor::Error::Validation`] with `ShapeMismatch` or
790 /// `DTypeMismatch` when bounds are incompatible with the input, or
791 /// [`tenferro_tensor::Error::BackendSource`] for a typed backend failure.
792 fn clamp(
793 &self,
794 lower: &Tensor,
795 upper: &Tensor,
796 session: &mut dyn BackendSession,
797 ) -> tenferro_tensor::Result<Tensor>;
798 /// Rank-2 matrix multiplication inside a session.
799 ///
800 /// # Examples
801 ///
802 /// ```rust
803 /// use tenferro_cpu::CpuBackend;
804 /// use tenferro_runtime::{Tensor, TensorSessionOpsExt};
805 /// use tenferro_tensor::BackendSessionHost;
806 ///
807 /// let mut backend = CpuBackend::new();
808 /// let a = Tensor::from_vec_col_major(vec![2, 3], vec![1.0_f64; 6]).unwrap();
809 /// let b = Tensor::from_vec_col_major(vec![3, 2], vec![1.0_f64; 6]).unwrap();
810 /// let c = backend.with_backend_session(|session| a.matmul(&b, session)).unwrap();
811 /// assert_eq!(c.shape(), &[2, 2]);
812 /// ```
813 ///
814 /// # Errors
815 ///
816 /// Returns [`tenferro_tensor::Error::Validation`] with `RankMismatch`,
817 /// `ShapeMismatch`, or `DTypeMismatch` for incompatible matrices, or
818 /// [`tenferro_tensor::Error::BackendSource`] for a typed backend failure.
819 fn matmul(
820 &self,
821 rhs: &Tensor,
822 session: &mut dyn BackendSession,
823 ) -> tenferro_tensor::Result<Tensor>;
824 /// Reshape without changing element order inside a session.
825 ///
826 /// # Examples
827 ///
828 /// ```rust
829 /// use tenferro_cpu::CpuBackend;
830 /// use tenferro_runtime::{Tensor, TensorSessionOpsExt};
831 /// use tenferro_tensor::BackendSessionHost;
832 ///
833 /// let mut backend = CpuBackend::new();
834 /// let x = Tensor::from_vec_col_major(vec![2, 2], vec![1.0_f64, 2.0, 3.0, 4.0]).unwrap();
835 /// let y = backend.with_backend_session(|session| x.reshape(&[4], session)).unwrap();
836 /// assert_eq!(y.shape(), &[4]);
837 /// ```
838 ///
839 /// # Errors
840 ///
841 /// Returns [`tenferro_tensor::Error::Validation`] with
842 /// `ShapeMismatch`, `RankMismatch`, or `InvalidArgument` when element
843 /// counts or ranks are invalid, or
844 /// [`tenferro_tensor::Error::BackendSource`] for a typed backend failure.
845 fn reshape(
846 &self,
847 shape: &[usize],
848 session: &mut dyn BackendSession,
849 ) -> tenferro_tensor::Result<Tensor>;
850 /// Permute axes inside a session.
851 ///
852 /// # Examples
853 ///
854 /// ```rust
855 /// use tenferro_cpu::CpuBackend;
856 /// use tenferro_runtime::{Tensor, TensorSessionOpsExt};
857 /// use tenferro_tensor::BackendSessionHost;
858 ///
859 /// let mut backend = CpuBackend::new();
860 /// let x = Tensor::from_vec_col_major(vec![2, 3], vec![1.0_f64; 6]).unwrap();
861 /// let y = backend.with_backend_session(|session| x.transpose(&[1, 0], session)).unwrap();
862 /// assert_eq!(y.shape(), &[3, 2]);
863 /// ```
864 ///
865 /// # Errors
866 ///
867 /// Returns [`tenferro_tensor::Error::Validation`] with
868 /// `InvalidPermutationLength`, `AxisOutOfBounds`, or `DuplicateAxis` for
869 /// an invalid permutation, or
870 /// [`tenferro_tensor::Error::BackendSource`] for a typed backend failure.
871 fn transpose(
872 &self,
873 perm: &[usize],
874 session: &mut dyn BackendSession,
875 ) -> tenferro_tensor::Result<Tensor>;
876}
877
878pub trait TypedTensorSessionOpsExt<T: TensorScalar> {
879 /// Elementwise addition with NumPy-style broadcasting inside a session.
880 ///
881 /// # Examples
882 ///
883 /// ```rust
884 /// use tenferro_cpu::CpuBackend;
885 /// use tenferro_runtime::{TypedTensor, TypedTensorSessionOpsExt};
886 /// use tenferro_tensor::BackendSessionHost;
887 ///
888 /// let mut backend = CpuBackend::new();
889 /// let a = TypedTensor::<f64>::from_vec_col_major(vec![2], vec![1.0, 2.0]).unwrap();
890 /// let b = TypedTensor::<f64>::from_vec_col_major(vec![2], vec![3.0, 4.0]).unwrap();
891 /// let sum = backend.with_backend_session(|session| a.add(&b, session)).unwrap();
892 /// assert_eq!(sum.host_data().unwrap(), &[4.0, 6.0]);
893 /// ```
894 ///
895 /// # Errors
896 ///
897 /// Returns [`tenferro_tensor::Error::Validation`] with `ShapeMismatch` for
898 /// incompatible operands, or [`tenferro_tensor::Error::BackendSource`] for
899 /// a typed backend failure.
900 fn add(
901 &self,
902 rhs: &TypedTensor<T>,
903 session: &mut dyn BackendSession,
904 ) -> tenferro_tensor::Result<TypedTensor<T>>;
905 /// Elementwise multiplication with NumPy-style broadcasting inside a session.
906 ///
907 /// # Examples
908 ///
909 /// ```rust
910 /// use tenferro_cpu::CpuBackend;
911 /// use tenferro_runtime::{TypedTensor, TypedTensorSessionOpsExt};
912 /// use tenferro_tensor::BackendSessionHost;
913 ///
914 /// let mut backend = CpuBackend::new();
915 /// let a = TypedTensor::<f64>::from_vec_col_major(vec![1], vec![2.0]).unwrap();
916 /// let b = TypedTensor::<f64>::from_vec_col_major(vec![4], vec![3.0; 4]).unwrap();
917 /// let product = backend.with_backend_session(|session| a.mul(&b, session)).unwrap();
918 /// assert_eq!(product.host_data().unwrap(), &[6.0; 4]);
919 /// ```
920 ///
921 /// # Errors
922 ///
923 /// Returns [`tenferro_tensor::Error::Validation`] with `ShapeMismatch` for
924 /// incompatible operands, or [`tenferro_tensor::Error::BackendSource`] for
925 /// a typed backend failure.
926 fn mul(
927 &self,
928 rhs: &TypedTensor<T>,
929 session: &mut dyn BackendSession,
930 ) -> tenferro_tensor::Result<TypedTensor<T>>;
931 /// Elementwise exponential inside a session.
932 ///
933 /// # Examples
934 ///
935 /// ```rust
936 /// use tenferro_cpu::CpuBackend;
937 /// use tenferro_runtime::{TypedTensor, TypedTensorSessionOpsExt};
938 /// use tenferro_tensor::BackendSessionHost;
939 ///
940 /// let mut backend = CpuBackend::new();
941 /// let x = TypedTensor::<f64>::from_vec_col_major(vec![2], vec![0.0, 1.0]).unwrap();
942 /// let y = backend.with_backend_session(|session| x.exp(session)).unwrap();
943 /// let y = y.host_data().unwrap();
944 /// assert!((y[0] - 1.0).abs() < 1.0e-12);
945 /// assert!((y[1] - std::f64::consts::E).abs() < 1.0e-12);
946 /// ```
947 ///
948 /// # Errors
949 ///
950 /// Returns [`tenferro_tensor::Error::Unsupported`] for an unsupported
951 /// dtype or [`tenferro_tensor::Error::BackendSource`] for a typed backend
952 /// failure.
953 fn exp(&self, session: &mut dyn BackendSession) -> tenferro_tensor::Result<TypedTensor<T>>;
954 /// Sum over one or more axes inside a session.
955 ///
956 /// # Examples
957 ///
958 /// ```rust
959 /// use tenferro_cpu::CpuBackend;
960 /// use tenferro_runtime::{TypedTensor, TypedTensorSessionOpsExt};
961 /// use tenferro_tensor::BackendSessionHost;
962 ///
963 /// let mut backend = CpuBackend::new();
964 /// let x = TypedTensor::<f64>::from_vec_col_major(vec![2, 3], vec![1.0; 6]).unwrap();
965 /// let sums = backend.with_backend_session(|session| x.reduce_sum(&[1], session)).unwrap();
966 /// assert_eq!(sums.host_data().unwrap(), &[3.0, 3.0]);
967 /// ```
968 ///
969 /// # Errors
970 ///
971 /// Returns [`tenferro_tensor::Error::Validation`] with `AxisOutOfBounds`
972 /// for an axis outside the input rank or `DuplicateAxis` when `axes`
973 /// repeats an axis, or [`tenferro_tensor::Error::BackendSource`] for a
974 /// typed backend failure.
975 fn reduce_sum(
976 &self,
977 axes: &[usize],
978 session: &mut dyn BackendSession,
979 ) -> tenferro_tensor::Result<TypedTensor<T>>;
980 /// Elementwise subtraction with NumPy-style broadcasting inside a session.
981 ///
982 /// # Examples
983 ///
984 /// ```rust
985 /// use tenferro_cpu::CpuBackend;
986 /// use tenferro_runtime::{TypedTensor, TypedTensorSessionOpsExt};
987 /// use tenferro_tensor::BackendSessionHost;
988 ///
989 /// let mut backend = CpuBackend::new();
990 /// let a = TypedTensor::<f64>::from_vec_col_major(vec![2], vec![2.0, 4.0]).unwrap();
991 /// let b = TypedTensor::<f64>::from_vec_col_major(vec![2], vec![1.0, 8.0]).unwrap();
992 /// let y = backend.with_backend_session(|session| a.sub(&b, session)).unwrap();
993 /// assert_eq!(y.host_data().unwrap(), &[1.0, -4.0]);
994 /// ```
995 ///
996 /// # Errors
997 ///
998 /// Returns [`tenferro_tensor::Error::Validation`] with `ShapeMismatch` for
999 /// incompatible operands, or [`tenferro_tensor::Error::BackendSource`] for
1000 /// a typed backend failure.
1001 fn sub(
1002 &self,
1003 rhs: &TypedTensor<T>,
1004 session: &mut dyn BackendSession,
1005 ) -> tenferro_tensor::Result<TypedTensor<T>>;
1006 /// Elementwise division with NumPy-style broadcasting inside a session.
1007 ///
1008 /// # Examples
1009 ///
1010 /// ```rust
1011 /// use tenferro_cpu::CpuBackend;
1012 /// use tenferro_runtime::{TypedTensor, TypedTensorSessionOpsExt};
1013 /// use tenferro_tensor::BackendSessionHost;
1014 ///
1015 /// let mut backend = CpuBackend::new();
1016 /// let a = TypedTensor::<f64>::from_vec_col_major(vec![2], vec![4.0, 8.0]).unwrap();
1017 /// let b = TypedTensor::<f64>::from_vec_col_major(vec![2], vec![2.0, 4.0]).unwrap();
1018 /// let y = backend.with_backend_session(|session| a.div(&b, session)).unwrap();
1019 /// assert_eq!(y.host_data().unwrap(), &[2.0, 2.0]);
1020 /// ```
1021 ///
1022 /// # Errors
1023 ///
1024 /// Returns [`tenferro_tensor::Error::Validation`] with `ShapeMismatch` for
1025 /// incompatible shapes, a numerical [`tenferro_tensor::Error::Extension`]
1026 /// for a detected zero divisor, or [`tenferro_tensor::Error::BackendSource`]
1027 /// for a typed backend failure.
1028 fn div(
1029 &self,
1030 rhs: &TypedTensor<T>,
1031 session: &mut dyn BackendSession,
1032 ) -> tenferro_tensor::Result<TypedTensor<T>>;
1033 /// Elementwise remainder with NumPy-style broadcasting inside a session.
1034 ///
1035 /// # Examples
1036 ///
1037 /// ```rust
1038 /// use tenferro_cpu::CpuBackend;
1039 /// use tenferro_runtime::{TypedTensor, TypedTensorSessionOpsExt};
1040 /// use tenferro_tensor::BackendSessionHost;
1041 ///
1042 /// let mut backend = CpuBackend::new();
1043 /// let a = TypedTensor::<f64>::from_vec_col_major(vec![2], vec![5.0, 7.0]).unwrap();
1044 /// let b = TypedTensor::<f64>::from_vec_col_major(vec![2], vec![2.0, 4.0]).unwrap();
1045 /// let y = backend.with_backend_session(|session| a.rem(&b, session)).unwrap();
1046 /// assert_eq!(y.host_data().unwrap(), &[1.0, 3.0]);
1047 /// ```
1048 ///
1049 /// # Errors
1050 ///
1051 /// Returns [`tenferro_tensor::Error::Validation`] with `ShapeMismatch` for
1052 /// incompatible shapes, a numerical [`tenferro_tensor::Error::Extension`]
1053 /// for a detected zero divisor, or [`tenferro_tensor::Error::BackendSource`]
1054 /// for a typed backend failure.
1055 fn rem(
1056 &self,
1057 rhs: &TypedTensor<T>,
1058 session: &mut dyn BackendSession,
1059 ) -> tenferro_tensor::Result<TypedTensor<T>>;
1060 /// Elementwise power with NumPy-style broadcasting inside a session.
1061 ///
1062 /// # Examples
1063 ///
1064 /// ```rust
1065 /// use tenferro_cpu::CpuBackend;
1066 /// use tenferro_runtime::{TypedTensor, TypedTensorSessionOpsExt};
1067 /// use tenferro_tensor::BackendSessionHost;
1068 ///
1069 /// let mut backend = CpuBackend::new();
1070 /// let a = TypedTensor::<f64>::from_vec_col_major(vec![2], vec![2.0, 3.0]).unwrap();
1071 /// let b = TypedTensor::<f64>::from_vec_col_major(vec![2], vec![3.0, 2.0]).unwrap();
1072 /// let y = backend.with_backend_session(|session| a.pow(&b, session)).unwrap();
1073 /// assert_eq!(y.host_data().unwrap(), &[8.0, 9.0]);
1074 /// ```
1075 ///
1076 /// # Errors
1077 ///
1078 /// Returns [`tenferro_tensor::Error::Validation`] with `ShapeMismatch` for
1079 /// incompatible shapes, a numerical [`tenferro_tensor::Error::Extension`]
1080 /// for a detected negative integer exponent, or
1081 /// [`tenferro_tensor::Error::BackendSource`] for a typed backend failure.
1082 fn pow(
1083 &self,
1084 rhs: &TypedTensor<T>,
1085 session: &mut dyn BackendSession,
1086 ) -> tenferro_tensor::Result<TypedTensor<T>>;
1087 /// Elementwise maximum with NumPy-style broadcasting inside a session.
1088 ///
1089 /// # Examples
1090 ///
1091 /// ```rust
1092 /// use tenferro_cpu::CpuBackend;
1093 /// use tenferro_runtime::{TypedTensor, TypedTensorSessionOpsExt};
1094 /// use tenferro_tensor::BackendSessionHost;
1095 ///
1096 /// let mut backend = CpuBackend::new();
1097 /// let a = TypedTensor::<f64>::from_vec_col_major(vec![2], vec![2.0, 4.0]).unwrap();
1098 /// let b = TypedTensor::<f64>::from_vec_col_major(vec![2], vec![1.0, 8.0]).unwrap();
1099 /// let y = backend.with_backend_session(|session| a.maximum(&b, session)).unwrap();
1100 /// assert_eq!(y.host_data().unwrap(), &[2.0, 8.0]);
1101 /// ```
1102 ///
1103 /// # Errors
1104 ///
1105 /// Returns [`tenferro_tensor::Error::Validation`] with `ShapeMismatch` for
1106 /// incompatible operands, or [`tenferro_tensor::Error::BackendSource`] for
1107 /// a typed backend failure.
1108 fn maximum(
1109 &self,
1110 rhs: &TypedTensor<T>,
1111 session: &mut dyn BackendSession,
1112 ) -> tenferro_tensor::Result<TypedTensor<T>>;
1113 /// Elementwise minimum with NumPy-style broadcasting inside a session.
1114 ///
1115 /// # Examples
1116 ///
1117 /// ```rust
1118 /// use tenferro_cpu::CpuBackend;
1119 /// use tenferro_runtime::{TypedTensor, TypedTensorSessionOpsExt};
1120 /// use tenferro_tensor::BackendSessionHost;
1121 ///
1122 /// let mut backend = CpuBackend::new();
1123 /// let a = TypedTensor::<f64>::from_vec_col_major(vec![2], vec![2.0, 4.0]).unwrap();
1124 /// let b = TypedTensor::<f64>::from_vec_col_major(vec![2], vec![1.0, 8.0]).unwrap();
1125 /// let y = backend.with_backend_session(|session| a.minimum(&b, session)).unwrap();
1126 /// assert_eq!(y.host_data().unwrap(), &[1.0, 4.0]);
1127 /// ```
1128 ///
1129 /// # Errors
1130 ///
1131 /// Returns [`tenferro_tensor::Error::Validation`] with `ShapeMismatch` for
1132 /// incompatible operands, or [`tenferro_tensor::Error::BackendSource`] for
1133 /// a typed backend failure.
1134 fn minimum(
1135 &self,
1136 rhs: &TypedTensor<T>,
1137 session: &mut dyn BackendSession,
1138 ) -> tenferro_tensor::Result<TypedTensor<T>>;
1139 /// Elementwise negation inside a session.
1140 ///
1141 /// # Examples
1142 ///
1143 /// ```rust
1144 /// use tenferro_cpu::CpuBackend;
1145 /// use tenferro_runtime::{TypedTensor, TypedTensorSessionOpsExt};
1146 /// use tenferro_tensor::BackendSessionHost;
1147 ///
1148 /// let mut backend = CpuBackend::new();
1149 /// let x = TypedTensor::<f64>::from_vec_col_major(vec![2], vec![1.0, -2.0]).unwrap();
1150 /// let y = backend.with_backend_session(|session| x.neg(session)).unwrap();
1151 /// assert_eq!(y.host_data().unwrap(), &[-1.0, 2.0]);
1152 /// ```
1153 ///
1154 /// # Errors
1155 ///
1156 /// Returns [`tenferro_tensor::Error::Unsupported`] for an unsupported
1157 /// dtype or [`tenferro_tensor::Error::BackendSource`] for a typed backend
1158 /// failure.
1159 fn neg(&self, session: &mut dyn BackendSession) -> tenferro_tensor::Result<TypedTensor<T>>;
1160 /// Elementwise absolute value inside a session.
1161 ///
1162 /// # Examples
1163 ///
1164 /// ```rust
1165 /// use tenferro_cpu::CpuBackend;
1166 /// use tenferro_runtime::{TypedTensor, TypedTensorSessionOpsExt};
1167 /// use tenferro_tensor::BackendSessionHost;
1168 ///
1169 /// let mut backend = CpuBackend::new();
1170 /// let x = TypedTensor::<f64>::from_vec_col_major(vec![2], vec![-1.0, 2.0]).unwrap();
1171 /// let y = backend.with_backend_session(|session| x.abs(session)).unwrap();
1172 /// assert_eq!(y.host_data().unwrap(), &[1.0, 2.0]);
1173 /// ```
1174 ///
1175 /// # Errors
1176 ///
1177 /// Returns [`tenferro_tensor::Error::Unsupported`] for an unsupported
1178 /// dtype or [`tenferro_tensor::Error::BackendSource`] for a typed backend
1179 /// failure.
1180 fn abs(&self, session: &mut dyn BackendSession) -> tenferro_tensor::Result<TypedTensor<T>>;
1181 /// Elementwise sign inside a session.
1182 ///
1183 /// # Examples
1184 ///
1185 /// ```rust
1186 /// use tenferro_cpu::CpuBackend;
1187 /// use tenferro_runtime::{TypedTensor, TypedTensorSessionOpsExt};
1188 /// use tenferro_tensor::BackendSessionHost;
1189 ///
1190 /// let mut backend = CpuBackend::new();
1191 /// let x = TypedTensor::<f64>::from_vec_col_major(vec![2], vec![1.0, -2.0]).unwrap();
1192 /// let y = backend.with_backend_session(|session| x.sign(session)).unwrap();
1193 /// assert_eq!(y.host_data().unwrap(), &[1.0, -1.0]);
1194 /// ```
1195 ///
1196 /// # Errors
1197 ///
1198 /// Returns [`tenferro_tensor::Error::Unsupported`] for an unsupported
1199 /// dtype or [`tenferro_tensor::Error::BackendSource`] for a typed backend
1200 /// failure.
1201 fn sign(&self, session: &mut dyn BackendSession) -> tenferro_tensor::Result<TypedTensor<T>>;
1202 /// Elementwise complex conjugate inside a session.
1203 ///
1204 /// For real dtypes the conjugate is the identity.
1205 ///
1206 /// # Examples
1207 ///
1208 /// ```rust
1209 /// use tenferro_cpu::CpuBackend;
1210 /// use tenferro_runtime::{TypedTensor, TypedTensorSessionOpsExt};
1211 /// use tenferro_tensor::BackendSessionHost;
1212 ///
1213 /// let mut backend = CpuBackend::new();
1214 /// let x = TypedTensor::<f64>::from_vec_col_major(vec![2], vec![1.0, -2.0]).unwrap();
1215 /// let y = backend.with_backend_session(|session| x.conj(session)).unwrap();
1216 /// assert_eq!(y.host_data().unwrap(), &[1.0, -2.0]);
1217 /// ```
1218 ///
1219 /// # Errors
1220 ///
1221 /// Returns [`tenferro_tensor::Error::Unsupported`] for an unsupported
1222 /// dtype or [`tenferro_tensor::Error::BackendSource`] for a typed backend
1223 /// failure.
1224 fn conj(&self, session: &mut dyn BackendSession) -> tenferro_tensor::Result<TypedTensor<T>>;
1225 /// Elementwise natural logarithm inside a session.
1226 ///
1227 /// # Examples
1228 ///
1229 /// ```rust
1230 /// use tenferro_cpu::CpuBackend;
1231 /// use tenferro_runtime::{TypedTensor, TypedTensorSessionOpsExt};
1232 /// use tenferro_tensor::BackendSessionHost;
1233 ///
1234 /// let mut backend = CpuBackend::new();
1235 /// let x = TypedTensor::<f64>::from_vec_col_major(vec![2], vec![1.0, std::f64::consts::E]).unwrap();
1236 /// let y = backend.with_backend_session(|session| x.log(session)).unwrap();
1237 /// let y = y.host_data().unwrap();
1238 /// assert!(y[0].abs() < 1.0e-12);
1239 /// assert!((y[1] - 1.0).abs() < 1.0e-12);
1240 /// ```
1241 ///
1242 /// # Errors
1243 ///
1244 /// Returns [`tenferro_tensor::Error::Unsupported`] for an unsupported
1245 /// dtype or [`tenferro_tensor::Error::BackendSource`] for a typed backend
1246 /// failure.
1247 fn log(&self, session: &mut dyn BackendSession) -> tenferro_tensor::Result<TypedTensor<T>>;
1248 /// Elementwise `exp(x) - 1` inside a session.
1249 ///
1250 /// # Examples
1251 ///
1252 /// ```rust
1253 /// use tenferro_cpu::CpuBackend;
1254 /// use tenferro_runtime::{TypedTensor, TypedTensorSessionOpsExt};
1255 /// use tenferro_tensor::BackendSessionHost;
1256 ///
1257 /// let mut backend = CpuBackend::new();
1258 /// let x = TypedTensor::<f64>::from_vec_col_major(vec![2], vec![0.0, 1.0]).unwrap();
1259 /// let y = backend.with_backend_session(|session| x.expm1(session)).unwrap();
1260 /// let y = y.host_data().unwrap();
1261 /// assert!(y[0].abs() < 1.0e-12);
1262 /// assert!((y[1] - (std::f64::consts::E - 1.0)).abs() < 1.0e-12);
1263 /// ```
1264 ///
1265 /// # Errors
1266 ///
1267 /// Returns [`tenferro_tensor::Error::Unsupported`] for an unsupported
1268 /// dtype or [`tenferro_tensor::Error::BackendSource`] for a typed backend
1269 /// failure.
1270 fn expm1(&self, session: &mut dyn BackendSession) -> tenferro_tensor::Result<TypedTensor<T>>;
1271 /// Elementwise `log(1 + x)` inside a session.
1272 ///
1273 /// # Examples
1274 ///
1275 /// ```rust
1276 /// use tenferro_cpu::CpuBackend;
1277 /// use tenferro_runtime::{TypedTensor, TypedTensorSessionOpsExt};
1278 /// use tenferro_tensor::BackendSessionHost;
1279 ///
1280 /// let mut backend = CpuBackend::new();
1281 /// let x = TypedTensor::<f64>::from_vec_col_major(vec![2], vec![0.0, std::f64::consts::E - 1.0]).unwrap();
1282 /// let y = backend.with_backend_session(|session| x.log1p(session)).unwrap();
1283 /// let y = y.host_data().unwrap();
1284 /// assert!(y[0].abs() < 1.0e-12);
1285 /// assert!((y[1] - 1.0).abs() < 1.0e-12);
1286 /// ```
1287 ///
1288 /// # Errors
1289 ///
1290 /// Returns [`tenferro_tensor::Error::Unsupported`] for an unsupported
1291 /// dtype or [`tenferro_tensor::Error::BackendSource`] for a typed backend
1292 /// failure.
1293 fn log1p(&self, session: &mut dyn BackendSession) -> tenferro_tensor::Result<TypedTensor<T>>;
1294 /// Elementwise sine inside a session.
1295 ///
1296 /// # Examples
1297 ///
1298 /// ```rust
1299 /// use tenferro_cpu::CpuBackend;
1300 /// use tenferro_runtime::{TypedTensor, TypedTensorSessionOpsExt};
1301 /// use tenferro_tensor::BackendSessionHost;
1302 ///
1303 /// let mut backend = CpuBackend::new();
1304 /// let x = TypedTensor::<f64>::from_vec_col_major(vec![2], vec![0.0, std::f64::consts::FRAC_PI_2]).unwrap();
1305 /// let y = backend.with_backend_session(|session| x.sin(session)).unwrap();
1306 /// let y = y.host_data().unwrap();
1307 /// assert!(y[0].abs() < 1.0e-12);
1308 /// assert!((y[1] - 1.0).abs() < 1.0e-12);
1309 /// ```
1310 ///
1311 /// # Errors
1312 ///
1313 /// Returns [`tenferro_tensor::Error::Unsupported`] for an unsupported
1314 /// dtype or [`tenferro_tensor::Error::BackendSource`] for a typed backend
1315 /// failure.
1316 fn sin(&self, session: &mut dyn BackendSession) -> tenferro_tensor::Result<TypedTensor<T>>;
1317 /// Elementwise cosine inside a session.
1318 ///
1319 /// # Examples
1320 ///
1321 /// ```rust
1322 /// use tenferro_cpu::CpuBackend;
1323 /// use tenferro_runtime::{TypedTensor, TypedTensorSessionOpsExt};
1324 /// use tenferro_tensor::BackendSessionHost;
1325 ///
1326 /// let mut backend = CpuBackend::new();
1327 /// let x = TypedTensor::<f64>::from_vec_col_major(vec![2], vec![0.0, std::f64::consts::PI]).unwrap();
1328 /// let y = backend.with_backend_session(|session| x.cos(session)).unwrap();
1329 /// let y = y.host_data().unwrap();
1330 /// assert!((y[0] - 1.0).abs() < 1.0e-12);
1331 /// assert!((y[1] + 1.0).abs() < 1.0e-12);
1332 /// ```
1333 ///
1334 /// # Errors
1335 ///
1336 /// Returns [`tenferro_tensor::Error::Unsupported`] for an unsupported
1337 /// dtype or [`tenferro_tensor::Error::BackendSource`] for a typed backend
1338 /// failure.
1339 fn cos(&self, session: &mut dyn BackendSession) -> tenferro_tensor::Result<TypedTensor<T>>;
1340 /// Elementwise hyperbolic tangent inside a session.
1341 ///
1342 /// # Examples
1343 ///
1344 /// ```rust
1345 /// use tenferro_cpu::CpuBackend;
1346 /// use tenferro_runtime::{TypedTensor, TypedTensorSessionOpsExt};
1347 /// use tenferro_tensor::BackendSessionHost;
1348 ///
1349 /// let mut backend = CpuBackend::new();
1350 /// let x = TypedTensor::<f64>::from_vec_col_major(vec![2], vec![0.0, 1.0]).unwrap();
1351 /// let y = backend.with_backend_session(|session| x.tanh(session)).unwrap();
1352 /// let y = y.host_data().unwrap();
1353 /// assert!(y[0].abs() < 1.0e-12);
1354 /// assert!((y[1] - 0.7615941559557649).abs() < 1.0e-12);
1355 /// ```
1356 ///
1357 /// # Errors
1358 ///
1359 /// Returns [`tenferro_tensor::Error::Unsupported`] for an unsupported
1360 /// dtype or [`tenferro_tensor::Error::BackendSource`] for a typed backend
1361 /// failure.
1362 fn tanh(&self, session: &mut dyn BackendSession) -> tenferro_tensor::Result<TypedTensor<T>>;
1363 /// Elementwise square root inside a session.
1364 ///
1365 /// # Examples
1366 ///
1367 /// ```rust
1368 /// use tenferro_cpu::CpuBackend;
1369 /// use tenferro_runtime::{TypedTensor, TypedTensorSessionOpsExt};
1370 /// use tenferro_tensor::BackendSessionHost;
1371 ///
1372 /// let mut backend = CpuBackend::new();
1373 /// let x = TypedTensor::<f64>::from_vec_col_major(vec![2], vec![4.0, 9.0]).unwrap();
1374 /// let y = backend.with_backend_session(|session| x.sqrt(session)).unwrap();
1375 /// assert_eq!(y.host_data().unwrap(), &[2.0, 3.0]);
1376 /// ```
1377 ///
1378 /// # Errors
1379 ///
1380 /// Returns [`tenferro_tensor::Error::Unsupported`] for an unsupported
1381 /// dtype or [`tenferro_tensor::Error::BackendSource`] for a typed backend
1382 /// failure.
1383 fn sqrt(&self, session: &mut dyn BackendSession) -> tenferro_tensor::Result<TypedTensor<T>>;
1384 /// Elementwise reciprocal square root inside a session.
1385 ///
1386 /// # Examples
1387 ///
1388 /// ```rust
1389 /// use tenferro_cpu::CpuBackend;
1390 /// use tenferro_runtime::{TypedTensor, TypedTensorSessionOpsExt};
1391 /// use tenferro_tensor::BackendSessionHost;
1392 ///
1393 /// let mut backend = CpuBackend::new();
1394 /// let x = TypedTensor::<f64>::from_vec_col_major(vec![2], vec![4.0, 1.0]).unwrap();
1395 /// let y = backend.with_backend_session(|session| x.rsqrt(session)).unwrap();
1396 /// let y = y.host_data().unwrap();
1397 /// assert!((y[0] - 0.5).abs() < 1.0e-12);
1398 /// assert!((y[1] - 1.0).abs() < 1.0e-12);
1399 /// ```
1400 ///
1401 /// # Errors
1402 ///
1403 /// Returns [`tenferro_tensor::Error::Unsupported`] for an unsupported
1404 /// dtype or [`tenferro_tensor::Error::BackendSource`] for a typed backend
1405 /// failure.
1406 fn rsqrt(&self, session: &mut dyn BackendSession) -> tenferro_tensor::Result<TypedTensor<T>>;
1407 /// Elementwise comparison with NumPy-style broadcasting inside a session.
1408 ///
1409 /// The result is a bool typed tensor.
1410 ///
1411 /// # Examples
1412 ///
1413 /// ```rust
1414 /// use tenferro_cpu::CpuBackend;
1415 /// use tenferro_runtime::{CompareDir, TypedTensor, TypedTensorSessionOpsExt};
1416 /// use tenferro_tensor::BackendSessionHost;
1417 ///
1418 /// let mut backend = CpuBackend::new();
1419 /// let a = TypedTensor::<f64>::from_vec_col_major(vec![2], vec![2.0, 4.0]).unwrap();
1420 /// let b = TypedTensor::<f64>::from_vec_col_major(vec![2], vec![1.0, 8.0]).unwrap();
1421 /// let y = backend.with_backend_session(|session| a.compare(&b, CompareDir::Gt, session)).unwrap();
1422 /// assert_eq!(y.host_data().unwrap(), &[true, false]);
1423 /// ```
1424 ///
1425 /// # Errors
1426 ///
1427 /// Returns [`tenferro_tensor::Error::Validation`] with
1428 /// `ShapeMismatch::IncompatibleShapes` when broadcasting the operands is
1429 /// impossible, or [`tenferro_tensor::Error::BackendSource`] for a typed
1430 /// backend failure.
1431 fn compare(
1432 &self,
1433 rhs: &TypedTensor<T>,
1434 dir: CompareDir,
1435 session: &mut dyn BackendSession,
1436 ) -> tenferro_tensor::Result<TypedTensor<bool>>;
1437 /// Clamp values elementwise between lower and upper bounds inside a session.
1438 ///
1439 /// # Examples
1440 ///
1441 /// ```rust
1442 /// use tenferro_cpu::CpuBackend;
1443 /// use tenferro_runtime::{TypedTensor, TypedTensorSessionOpsExt};
1444 /// use tenferro_tensor::BackendSessionHost;
1445 ///
1446 /// let mut backend = CpuBackend::new();
1447 /// let x = TypedTensor::<f64>::from_vec_col_major(vec![2], vec![-2.0, 4.0]).unwrap();
1448 /// let lower = TypedTensor::<f64>::from_vec_col_major(vec![], vec![0.0]).unwrap();
1449 /// let upper = TypedTensor::<f64>::from_vec_col_major(vec![], vec![3.0]).unwrap();
1450 /// let y = backend.with_backend_session(|session| x.clamp(&lower, &upper, session)).unwrap();
1451 /// assert_eq!(y.host_data().unwrap(), &[0.0, 3.0]);
1452 /// ```
1453 ///
1454 /// # Errors
1455 ///
1456 /// Returns [`tenferro_tensor::Error::Validation`] with
1457 /// `ShapeMismatch::IncompatibleShapes` when a bound cannot broadcast to
1458 /// the input, or [`tenferro_tensor::Error::BackendSource`] for a typed
1459 /// backend failure.
1460 fn clamp(
1461 &self,
1462 lower: &TypedTensor<T>,
1463 upper: &TypedTensor<T>,
1464 session: &mut dyn BackendSession,
1465 ) -> tenferro_tensor::Result<TypedTensor<T>>;
1466 /// Rank-2 matrix multiplication inside a session.
1467 ///
1468 /// # Examples
1469 ///
1470 /// ```rust
1471 /// use tenferro_cpu::CpuBackend;
1472 /// use tenferro_runtime::{TypedTensor, TypedTensorSessionOpsExt};
1473 /// use tenferro_tensor::BackendSessionHost;
1474 ///
1475 /// let mut backend = CpuBackend::new();
1476 /// let a = TypedTensor::<f64>::from_vec_col_major(vec![2, 3], vec![1.0; 6]).unwrap();
1477 /// let b = TypedTensor::<f64>::from_vec_col_major(vec![3, 2], vec![1.0; 6]).unwrap();
1478 /// let c = backend.with_backend_session(|session| a.matmul(&b, session)).unwrap();
1479 /// assert_eq!(c.shape(), &[2, 2]);
1480 /// ```
1481 ///
1482 /// # Errors
1483 ///
1484 /// Returns [`tenferro_tensor::Error::Validation`] with `RankMismatch` when
1485 /// either operand is not rank two or `ShapeMismatch::ContractedDimensions`
1486 /// when the inner dimensions differ, or
1487 /// [`tenferro_tensor::Error::BackendSource`] for a typed backend failure.
1488 fn matmul(
1489 &self,
1490 rhs: &TypedTensor<T>,
1491 session: &mut dyn BackendSession,
1492 ) -> tenferro_tensor::Result<TypedTensor<T>>;
1493 /// Reshape through the backend structural operation inside a session.
1494 ///
1495 /// # Examples
1496 ///
1497 /// ```rust
1498 /// use tenferro_cpu::CpuBackend;
1499 /// use tenferro_runtime::{TypedTensor, TypedTensorSessionOpsExt};
1500 /// use tenferro_tensor::BackendSessionHost;
1501 ///
1502 /// let mut backend = CpuBackend::new();
1503 /// let x = TypedTensor::<f64>::from_vec_col_major(vec![2, 3], vec![1.0; 6]).unwrap();
1504 /// let y = backend.with_backend_session(|session| x.reshape(&[3, 2], session)).unwrap();
1505 /// assert_eq!(y.shape(), &[3, 2]);
1506 /// ```
1507 ///
1508 /// # Errors
1509 ///
1510 /// Returns [`tenferro_tensor::Error::Validation`] with
1511 /// `ShapeMismatch::ReshapeElementCount` when the element counts differ,
1512 /// `IntegerOverflow` when shape arithmetic overflows, or
1513 /// [`tenferro_tensor::Error::BackendSource`] for a typed backend failure.
1514 fn reshape(
1515 &self,
1516 shape: &[usize],
1517 session: &mut dyn BackendSession,
1518 ) -> tenferro_tensor::Result<TypedTensor<T>>;
1519 /// Permute axes through the backend structural operation inside a session.
1520 ///
1521 /// # Examples
1522 ///
1523 /// ```rust
1524 /// use tenferro_cpu::CpuBackend;
1525 /// use tenferro_runtime::{TypedTensor, TypedTensorSessionOpsExt};
1526 /// use tenferro_tensor::BackendSessionHost;
1527 ///
1528 /// let mut backend = CpuBackend::new();
1529 /// let x = TypedTensor::<f64>::from_vec_col_major(vec![2, 3], vec![1.0; 6]).unwrap();
1530 /// let y = backend.with_backend_session(|session| x.transpose(&[1, 0], session)).unwrap();
1531 /// assert_eq!(y.shape(), &[3, 2]);
1532 /// ```
1533 ///
1534 /// # Errors
1535 ///
1536 /// Returns [`tenferro_tensor::Error::Validation`] with
1537 /// `InvalidPermutationLength` when `perm` has the wrong length,
1538 /// `AxisOutOfBounds` for an invalid axis, or `DuplicateAxis` for a
1539 /// repeated axis, or [`tenferro_tensor::Error::BackendSource`] for a typed
1540 /// backend failure.
1541 fn transpose(
1542 &self,
1543 perm: &[usize],
1544 session: &mut dyn BackendSession,
1545 ) -> tenferro_tensor::Result<TypedTensor<T>>;
1546 /// Broadcast into a larger shape inside a session.
1547 ///
1548 /// # Examples
1549 ///
1550 /// ```rust
1551 /// use tenferro_cpu::CpuBackend;
1552 /// use tenferro_runtime::{TypedTensor, TypedTensorSessionOpsExt};
1553 /// use tenferro_tensor::BackendSessionHost;
1554 ///
1555 /// let mut backend = CpuBackend::new();
1556 /// let row = TypedTensor::<f64>::from_vec_col_major(vec![3], vec![1.0, 2.0, 3.0]).unwrap();
1557 /// let matrix = backend.with_backend_session(|session| row.broadcast_in_dim(&[2, 3], &[1], session)).unwrap();
1558 /// assert_eq!(matrix.shape(), &[2, 3]);
1559 /// ```
1560 ///
1561 /// # Errors
1562 ///
1563 /// Returns [`tenferro_tensor::Error::Validation`] with `RankMismatch` when
1564 /// `dims` does not match the input rank, `AxisOutOfBounds` or
1565 /// `DuplicateAxis` for an invalid mapping, or
1566 /// `ShapeMismatch::IncompatibleShapes` when known dimensions cannot
1567 /// broadcast. [`tenferro_tensor::Error::BackendSource`] reports a typed
1568 /// backend failure.
1569 fn broadcast_in_dim(
1570 &self,
1571 shape: &[usize],
1572 dims: &[usize],
1573 session: &mut dyn BackendSession,
1574 ) -> tenferro_tensor::Result<TypedTensor<T>>;
1575}
1576
1577/// Backend-explicit bool-mask session operations for typed tensors.
1578///
1579/// This trait keeps `where_select` available as a method on bool
1580/// `TypedTensor`s while preserving the crate-root extension-trait surface. It
1581/// is public because downstream users call it directly; the implementation
1582/// helper in the private `typed_tensor` module is not a compatibility API.
1583///
1584/// # Examples
1585///
1586/// ```rust
1587/// use tenferro_cpu::CpuBackend;
1588/// use tenferro_runtime::{TypedTensor, TypedTensorMaskSessionOpsExt};
1589/// use tenferro_tensor::BackendSessionHost;
1590///
1591/// let mut backend = CpuBackend::new();
1592/// let condition =
1593/// TypedTensor::<bool>::from_vec_col_major(vec![2], vec![true, false]).unwrap();
1594/// let on_true = TypedTensor::<f64>::from_vec_col_major(vec![2], vec![1.0, 2.0]).unwrap();
1595/// let on_false = TypedTensor::<f64>::from_vec_col_major(vec![2], vec![3.0, 4.0]).unwrap();
1596/// let selected = backend
1597/// .with_backend_session(|session| condition.where_select(&on_true, &on_false, session))
1598/// .unwrap();
1599/// assert_eq!(selected.host_data().unwrap(), &[1.0, 4.0]);
1600/// ```
1601pub trait TypedTensorMaskSessionOpsExt {
1602 /// Select typed values using this bool tensor as condition.
1603 ///
1604 /// # Errors
1605 ///
1606 /// Returns [`tenferro_tensor::Error::Validation`] with
1607 /// `ShapeMismatch::IncompatibleShapes` when the condition or either branch
1608 /// cannot broadcast to the other operands, or
1609 /// [`tenferro_tensor::Error::BackendSource`] for a typed backend failure.
1610 fn where_select<U: TensorScalar>(
1611 &self,
1612 on_true: &TypedTensor<U>,
1613 on_false: &TypedTensor<U>,
1614 session: &mut dyn BackendSession,
1615 ) -> tenferro_tensor::Result<TypedTensor<U>>;
1616}
1617
1618pub use traced::TracedTensor;