pub trait Engine:
TensorBackendOps
+ SessionCachedDot
+ TensorDeviceTransfer {
// Provided methods
fn gather_read(
&mut self,
operand: TensorRead<'_>,
start_indices: TensorRead<'_>,
config: &GatherConfig,
) -> Result<Tensor, Error> { ... }
fn vdot_read(
&mut self,
_lhs: TensorRead<'_>,
_rhs: TensorRead<'_>,
) -> Result<Tensor, Error> { ... }
fn norm_squared_read(
&mut self,
_input: TensorRead<'_>,
) -> Result<Tensor, Error> { ... }
fn fused_activation_read(
&mut self,
op: ActivationOp,
input: TensorRead<'_>,
) -> Result<Option<Tensor>, Error> { ... }
fn softmax_read(
&mut self,
input: TensorRead<'_>,
axis: usize,
) -> Result<Option<Tensor>, Error> { ... }
fn axpby_read_into_accum(
&mut self,
_alpha: ContractionScalar,
_x: TensorRead<'_>,
_beta: ContractionScalar,
_y: TensorWrite<'_>,
) -> Result<(), Error> { ... }
fn native_engine(&mut self) -> Option<NativeSessionRef<'_>> { ... }
}Expand description
The execution trait every tensor operation runs on.
An engine is a caller-held value (a CPU engine owns a Rayon pool and a
workspace; a GPU engine owns a stream and a workspace). Operations take
&mut of the engine, so one computation uses an engine at a time without
any runtime lock. There is no separate session object.
§Examples
use tenferro_tensor::{Engine, Tensor, TensorRead};
fn add_on(engine: &mut dyn Engine, a: &Tensor, b: &Tensor) -> tenferro_tensor::Result<Tensor> {
engine.add_read(TensorRead::from_tensor(a), TensorRead::from_tensor(b))
}The operation one-shot spelling is gone; an engine only answers to the read form:
use tenferro_tensor::{Engine, Tensor};
fn add_on(engine: &mut dyn Engine, a: &Tensor, b: &Tensor) {
let _ = engine.add(a, b);
}Provided Methods§
Sourcefn gather_read(
&mut self,
operand: TensorRead<'_>,
start_indices: TensorRead<'_>,
config: &GatherConfig,
) -> Result<Tensor, Error>
fn gather_read( &mut self, operand: TensorRead<'_>, start_indices: TensorRead<'_>, config: &GatherConfig, ) -> Result<Tensor, Error>
Gather with both operands taken as reads.
The default stages each borrowed view (an owned tensor is passed
through) and delegates to TensorIndexing::gather; a backend whose gather kernel consumes the
operand’s strides overrides this so a borrowed operand needs no copy
(invariant I1: the runtime must not materialize by default).
§Errors
Returns crate::Error::Validation with a typed ValidationError
source for invalid shapes, ranks, axes, dtypes or output metadata, and
crate::Error::BackendFailure or crate::Error::BackendSource when
backend execution or storage access cannot provide the requested result.
The default implementation stages a view first, so it also returns
whatever TensorStructural::to_contiguous_read reports for a view the backend
cannot materialize.
Sourcefn vdot_read(
&mut self,
_lhs: TensorRead<'_>,
_rhs: TensorRead<'_>,
) -> Result<Tensor, Error>
fn vdot_read( &mut self, _lhs: TensorRead<'_>, _rhs: TensorRead<'_>, ) -> Result<Tensor, Error>
Compute the all-axis conjugating dot product without transferring either input.
The result is a rank-0 tensor with the input dtype and has the value
sum(conj(lhs) * rhs). Borrowed views remain borrowed through the
backend’s existing same-placement planning boundary.
§Examples
use tenferro_tensor::{Engine, TensorRead};
fn vdot(session: &mut dyn Engine, x: TensorRead<'_>, y: TensorRead<'_>)
-> tenferro_tensor::Result<tenferro_tensor::Tensor>
{
session.vdot_read(x, y)
}§Errors
Returns Error::Unsupported when the backend does not override this
capability or the dtype is unsupported; Error::Validation with
DTypeMismatch, ShapeMismatch, or InvalidArgument when dtype, shape,
or placement differs; Error::RuntimeState for inaccessible backend
storage; or Error::BackendSource when provider execution fails.
Sourcefn norm_squared_read(&mut self, _input: TensorRead<'_>) -> Result<Tensor, Error>
fn norm_squared_read(&mut self, _input: TensorRead<'_>) -> Result<Tensor, Error>
Compute the all-axis sum of squared magnitudes without taking a square root.
The result is rank 0 and is F32 for F32/C32 input or F64 for F64/C64 input. No transfer or full-size algebra temporary is implied by this session contract.
§Examples
use tenferro_tensor::{Engine, TensorRead};
fn norm_squared(session: &mut dyn Engine, x: TensorRead<'_>)
-> tenferro_tensor::Result<tenferro_tensor::Tensor>
{
session.norm_squared_read(x)
}§Errors
Returns Error::Unsupported when the backend does not override this
capability or the dtype is unsupported, Error::RuntimeState when
backend storage is not host-accessible, or Error::BackendSource when
reduction execution fails.
Sourcefn fused_activation_read(
&mut self,
op: ActivationOp,
input: TensorRead<'_>,
) -> Result<Option<Tensor>, Error>
fn fused_activation_read( &mut self, op: ActivationOp, input: TensorRead<'_>, ) -> Result<Option<Tensor>, Error>
Compute a fused activation in one pass, or decline with Ok(None).
This is an optional fast path. A backend that returns Ok(None) keeps
the shared composite formulation of the same function, so declining is
always correct. A backend that returns Ok(Some(output)) must produce
the value
defined by ActivationOp for an F32/F64 input in one elementwise
traversal.
§Examples
use tenferro_tensor::{ActivationOp, Engine, TensorRead};
fn fused(session: &mut dyn Engine, x: TensorRead<'_>)
-> tenferro_tensor::Result<Option<tenferro_tensor::Tensor>>
{
session.fused_activation_read(ActivationOp::Sigmoid, x)
}§Errors
Returns a typed validation error for an unsupported dtype, a backend
error when storage cannot be read, or a kernel error from the fused
traversal. Returning Ok(None) declines the fast path.
Sourcefn softmax_read(
&mut self,
input: TensorRead<'_>,
axis: usize,
) -> Result<Option<Tensor>, Error>
fn softmax_read( &mut self, input: TensorRead<'_>, axis: usize, ) -> Result<Option<Tensor>, Error>
Fused real-float softmax along axis.
This is an optional fast path for the shared runtime composite
formulation. A backend that returns Ok(Some(output)) must produce the
same value as the composite: a max-subtracted softmax over axis, with
an all--inf slice yielding zeros and NaN propagating.
§Examples
use tenferro_tensor::{Engine, TensorRead};
fn softmax(session: &mut dyn Engine, x: TensorRead<'_>, axis: usize)
-> tenferro_tensor::Result<Option<tenferro_tensor::Tensor>>
{
session.softmax_read(x, axis)
}§Errors
Returns a typed validation error for an invalid axis or unsupported
dtype, a backend error when storage cannot be read, or a kernel error.
Returning Ok(None) declines the fast path.
Sourcefn axpby_read_into_accum(
&mut self,
_alpha: ContractionScalar,
_x: TensorRead<'_>,
_beta: ContractionScalar,
_y: TensorWrite<'_>,
) -> Result<(), Error>
fn axpby_read_into_accum( &mut self, _alpha: ContractionScalar, _x: TensorRead<'_>, _beta: ContractionScalar, _y: TensorWrite<'_>, ) -> Result<(), Error>
Apply y <- alpha * x + beta * y in one pass into caller-owned storage.
Scalars must have the exact tensor dtype; real coefficients for complex
vectors are represented as complex values with zero imaginary part. The
destination must be write-injective and disjoint from x; any x/y
storage overlap is rejected before mutation. A strided or offset
destination view is accepted, so a caller can accumulate into a region
of a larger allocation.
§Examples
use tenferro_tensor::{Engine, ContractionScalar, TensorRead, TensorWrite};
fn axpby(session: &mut dyn Engine, x: TensorRead<'_>, y: TensorWrite<'_>)
-> tenferro_tensor::Result<()>
{
session.axpby_read_into_accum(
ContractionScalar::F64(1.0), x, ContractionScalar::F64(0.0), y,
)
}§Errors
Returns Error::Unsupported when the backend does not override this
capability or the dtype is unsupported; Error::Validation with
DTypeMismatch, ShapeMismatch, or InvalidArgument for scalar/dtype,
shape, placement, injectivity, or overlap failures; or
Error::RuntimeState for inaccessible backend storage. Invalid
requests leave the destination unchanged.
Sourcefn native_engine(&mut self) -> Option<NativeSessionRef<'_>>
fn native_engine(&mut self) -> Option<NativeSessionRef<'_>>
Return this engine’s backend-leaf native capability, if it has one.
The standard engines return a token that their own safe visitors
(with_cpu_engine, with_cuda_engine) recover. The default is None:
a custom engine has no native services unless it forwards the token of a
standard engine it owns. A wrapper that overrides operation dispatch
(for example a custom GEMM) should keep the default, because an
operation family that finds a native token may call the delegate’s
native services directly and so bypass the wrapper’s override.
§Examples
use tenferro_tensor::Engine;
fn native_services_available(session: &mut dyn Engine) -> bool {
session.native_engine().is_some()
}Dyn Compatibility§
This trait is dyn compatible.
In older versions of Rust, dyn compatibility was called "object safety".