Skip to main content

EagerRuntime

Struct EagerRuntime 

Source
pub struct EagerRuntime { /* private fields */ }
Expand description

Shared eager execution context for tensors on a backend.

Reusing one context lets eager tensors share backend state, extension runtime caches, and gradient storage across a computation.

§Examples

use tenferro_cpu::CpuBackend;
use tenferro_ad::{EagerRuntime, EagerTensor, Tensor};

let ctx = EagerRuntime::with_cpu_backend(CpuBackend::new());
let x = EagerTensor::from_tensor_in(Tensor::from_vec_col_major(vec![1], vec![1.0_f64]).unwrap(), ctx.clone()).unwrap();
let y = EagerTensor::from_tensor_in(Tensor::from_vec_col_major(vec![1], vec![2.0_f64]).unwrap(), ctx).unwrap();
let z = x.add(&y).unwrap();

assert_eq!(z.materialized().unwrap().as_slice::<f64>().unwrap(), &[3.0]);

Implementations§

Source§

impl EagerRuntime

Source

pub fn new() -> Arc<Self>

Create a shared CPU eager execution context.

§Examples
use tenferro_ad::EagerRuntime;

let ctx = EagerRuntime::new();
assert_eq!(std::sync::Arc::strong_count(&ctx), 1);
Source

pub fn with_cpu_backend(backend: CpuBackend) -> Arc<Self>

Create a shared eager execution context from a configured CPU backend.

§Examples
use tenferro_cpu::CpuBackend;
use tenferro_ad::{EagerRuntime};

let ctx = EagerRuntime::with_cpu_backend(CpuBackend::with_threads(1).unwrap());
assert_eq!(std::sync::Arc::strong_count(&ctx), 1);
Source

pub fn with_cpu_backend_and_ad_context( backend: CpuBackend, ad: &AdContext, ) -> Arc<Self>

Create a shared CPU eager context with explicit AD extension rules.

§Examples
use tenferro_cpu::CpuBackend;
use tenferro_ad::{AdContext, EagerRuntime};

let ad = AdContext::builder().build().unwrap();
let ctx = EagerRuntime::with_cpu_backend_and_ad_context(CpuBackend::new(), &ad);
assert_eq!(std::sync::Arc::strong_count(&ctx), 1);
Source

pub fn id(&self) -> ContextId

Return an opaque identifier for this context.

§Examples
use tenferro_cpu::CpuBackend;
use tenferro_ad::{EagerRuntime};

let ctx = EagerRuntime::with_cpu_backend(CpuBackend::new());
assert_ne!(ctx.id(), EagerRuntime::with_cpu_backend(CpuBackend::new()).id());
Source

pub fn no_grad(&self) -> EagerNoGradGuard

Disable eager operation recording on the current thread until the guard is dropped.

This is useful for optimizer updates, metric calculations, and other eager computations that should not become part of the AD tape.

§Examples
use tenferro_ad::{EagerRuntime, EagerTensor, Tensor};
use tenferro_cpu::CpuBackend;

let ctx = EagerRuntime::with_cpu_backend(CpuBackend::new());
let x = EagerTensor::requires_grad_in(
    Tensor::from_vec_col_major(vec![1], vec![3.0_f64]).unwrap(),
    ctx.clone(),
)?;
let y = {
    let _guard = ctx.no_grad();
    x.mul(&x)?
};
assert!(!y.tracks_grad());
Source

pub fn register_extension( &self, register: impl FnOnce(&mut ExtensionExecutor<EagerBackend>) -> Result<(), ExtensionRuntimeRegistryError>, ) -> Result<(), ExtensionRuntimeRegistryError>

Register one extension runtime on this eager context.

Source

pub fn clear_extension_caches(&self) -> Result<()>

Clear generic extension runtime cache entries.

§Examples
use tenferro_cpu::CpuBackend;
use tenferro_ad::{EagerRuntime};

let ctx = EagerRuntime::with_cpu_backend(CpuBackend::new());
ctx.clear_extension_caches()?;
assert_eq!(ctx.cache_stats()?.extensions.entries, 0);
Source

pub fn clear_caches(&self) -> Result<()>

Clear every cache owned by this eager context.

§Examples
use tenferro_cpu::CpuBackend;
use tenferro_ad::{EagerRuntime};

let ctx = EagerRuntime::with_cpu_backend(CpuBackend::new());
ctx.clear_caches()?;
assert_eq!(ctx.cache_stats()?.extensions.entries, 0);
assert_eq!(ctx.cache_stats()?.ad_transforms.entries, 0);
Source

pub fn cache_stats(&self) -> Result<EagerRuntimeCacheStats>

Return eager runtime cache-entry and retained-byte stats.

§Examples
use tenferro_cpu::CpuBackend;
use tenferro_ad::{EagerRuntime};

let ctx = EagerRuntime::with_cpu_backend(CpuBackend::new());
let stats = ctx.cache_stats()?;
assert_eq!(stats.extensions.entries, 0);
assert_eq!(stats.ad_transforms.entries, 0);
Source

pub fn ad_transform_cache_limits(&self) -> Result<AdTransformCacheLimits>

Return the AD transform cache retention limits.

§Examples
use tenferro_ad::EagerRuntime;
use tenferro_cpu::CpuBackend;

let ctx = EagerRuntime::with_cpu_backend(CpuBackend::new());
assert!(ctx.ad_transform_cache_limits()?.max_entries().get() > 0);
Source

pub fn set_ad_transform_cache_limits( &self, limits: AdTransformCacheLimits, ) -> Result<()>

Replace AD transform cache retention limits.

§Examples
use std::num::NonZeroUsize;
use tenferro_ad::{AdTransformCacheLimits, EagerRuntime};
use tenferro_cpu::CpuBackend;

let ctx = EagerRuntime::with_cpu_backend(CpuBackend::new());
let limits = AdTransformCacheLimits::new(NonZeroUsize::new(1).unwrap());
ctx.set_ad_transform_cache_limits(limits)?;
assert_eq!(ctx.ad_transform_cache_limits()?, limits);
Source

pub fn clear_ad_transform_caches(&self) -> Result<()>

Clear AD transform cache entries visible through this eager runtime.

§Examples
use tenferro_ad::EagerRuntime;
use tenferro_cpu::CpuBackend;

let ctx = EagerRuntime::with_cpu_backend(CpuBackend::new());
ctx.clear_ad_transform_caches()?;
assert_eq!(ctx.cache_stats()?.ad_transforms.entries, 0);
Source

pub fn extension_cache_limits(&self) -> Result<ExtensionCacheLimits>

Return the extension cache retention limits.

Source

pub fn set_extension_cache_limits( &self, limits: ExtensionCacheLimits, ) -> Result<()>

Replace extension cache retention limits.

Source

pub fn with_extension_caches_mut<R>( &self, f: impl FnOnce(&mut ExtensionCacheStore) -> R, ) -> Result<R>

Mutably borrow generic extension runtime cache storage.

This hook is for standard extension crates that need cache entries owned by an eager runtime while preserving eager value semantics outside a registered extension execution boundary.

§Examples
use tenferro_ad::EagerRuntime;
use tenferro_cpu::CpuBackend;
use tenferro_runtime::ExtensionCacheKey;

let ctx = EagerRuntime::with_cpu_backend(CpuBackend::new());
let key = ExtensionCacheKey::new("example.cache.v1", "plans", 1);

ctx.with_extension_caches_mut(|caches| {
    caches.put(key, 7_usize, std::mem::size_of::<usize>());
});

assert_eq!(ctx.cache_stats().unwrap().extensions.entries, 1);
Source

pub fn with_backend_mut<R>( &self, f: impl FnOnce(&mut EagerBackend) -> R, ) -> Result<R>

Mutably borrow this runtime’s backend.

This hook lets standard extension crates run a whole contraction program in a single backend session (instead of one eager op per step) while preserving eager value semantics for untracked tensors.

§Examples
use tenferro_ad::EagerRuntime;
use tenferro_cpu::CpuBackend;

let ctx = EagerRuntime::with_cpu_backend(CpuBackend::new());
// The closure receives `&mut EagerBackend`; standard extension crates
// use it to open one backend session for a whole contraction program.
let answer = ctx.with_backend_mut(|_backend| 42).unwrap();
assert_eq!(answer, 42);
Source

pub fn synchronize(&self) -> Result<()>

Block the current thread until backend work submitted by this eager runtime completes.

CPU runtimes return immediately. CUDA and WebGPU runtimes synchronize their current backend work queue.

§Examples
use tenferro_cpu::CpuBackend;
use tenferro_ad::EagerRuntime;

let ctx = EagerRuntime::with_cpu_backend(CpuBackend::new());
ctx.synchronize().unwrap();
Source

pub fn clear_grads(&self) -> Result<()>

Clear all live gradient slots tracked by this context.

This resets the stored gradients to None without unregistering the tensors, so future backward() calls can accumulate again.

§Examples
use tenferro_cpu::CpuBackend;
use tenferro_ad::{EagerRuntime, EagerTensor, Tensor};

let ctx = EagerRuntime::with_cpu_backend(CpuBackend::new());
let x = EagerTensor::requires_grad_in(Tensor::from_vec_col_major(vec![3], vec![1.0_f64, 2.0, 3.0]).unwrap(), ctx.clone()).unwrap();
let y = EagerTensor::requires_grad_in(Tensor::from_vec_col_major(vec![3], vec![4.0_f64, 5.0, 6.0]).unwrap(), ctx.clone()).unwrap();
let loss = x.mul(&y).unwrap().reduce_sum(&[0]).unwrap();
let _ = loss.backward().unwrap();

ctx.clear_grads()?;

assert!(x.grad()?.is_none());
assert!(y.grad()?.is_none());
Source

pub fn constant_from(self: &Arc<Self>, tensor: Tensor) -> Result<EagerTensor>

Import a concrete tensor into this context as an untracked constant.

The returned tensor does not participate in gradient tracking. Use this for fixed masks, quadrature weights, physical constants, and other data that should not receive gradients.

§Examples
use tenferro_cpu::CpuBackend;
use tenferro_ad::{EagerRuntime, EagerTensor, Tensor};

let ctx = EagerRuntime::with_cpu_backend(CpuBackend::new());
let c = ctx.constant_from(Tensor::from_vec_col_major(vec![2], vec![1.0_f64, 2.0]).unwrap())?;
let x = EagerTensor::requires_grad_in(Tensor::from_vec_col_major(vec![2], vec![3.0_f64, 4.0]).unwrap(), ctx)?;
let z = x.add(&c).unwrap();

assert_eq!(z.materialized()?.as_slice::<f64>().unwrap(), &[4.0, 6.0]);
Source

pub fn variable_from(self: &Arc<Self>, tensor: Tensor) -> Result<EagerTensor>

Import a concrete tensor into this context as a trainable variable.

The returned tensor participates in gradient tracking; its gradient slot is registered in this context.

§Examples
use tenferro_cpu::CpuBackend;
use tenferro_ad::{EagerRuntime, EagerTensor, Tensor};

let ctx = EagerRuntime::with_cpu_backend(CpuBackend::new());
let p = ctx.variable_from(Tensor::from_vec_col_major(vec![2], vec![1.0_f64, 2.0]).unwrap())?;
let loss = p.exp().unwrap().reduce_sum(&[0]).unwrap();
let _ = loss.backward().unwrap();

let grad = p.grad().unwrap().unwrap();
assert_eq!(grad.shape(), &[2]);
Source

pub fn grad( self: &Arc<Self>, output: &EagerTensor, wrt: &EagerTensor, ) -> Result<EagerTensor>

Gradient of a scalar eager output with respect to an eager tensor.

Functional eager gradients return ordinary eager tensors and do not write into grad() slots. The returned tensor keeps a trace when the derivative computation depends on tracked eager values.

§Examples
use tenferro_ad::{EagerRuntime, EagerTensor, Tensor};
use tenferro_cpu::CpuBackend;

let ctx = EagerRuntime::with_cpu_backend(CpuBackend::new());
let x = EagerTensor::requires_grad_in(
    Tensor::from_vec_col_major(vec![], vec![3.0_f64]).unwrap(),
    ctx.clone(),
)?;
let loss = x.mul(&x)?;
let dx = ctx.grad(&loss, &x)?;
assert_eq!(dx.materialized()?.as_slice::<f64>().unwrap(), &[6.0]);
Source

pub fn grad_optional( self: &Arc<Self>, output: &EagerTensor, wrt: &EagerTensor, ) -> Result<Option<EagerTensor>>

Gradient that returns None when wrt is inactive.

§Examples
use tenferro_ad::{EagerRuntime, EagerTensor, Tensor};
use tenferro_cpu::CpuBackend;

let ctx = EagerRuntime::with_cpu_backend(CpuBackend::new());
let x = EagerTensor::requires_grad_in(
    Tensor::from_vec_col_major(vec![], vec![3.0_f64]).unwrap(),
    ctx.clone(),
)?;
let y = EagerTensor::requires_grad_in(
    Tensor::from_vec_col_major(vec![], vec![4.0_f64]).unwrap(),
    ctx.clone(),
)?;
let loss = y.mul(&y)?;
assert!(ctx.grad_optional(&loss, &x)?.is_none());
Source

pub fn vjp( self: &Arc<Self>, output: &EagerTensor, wrt: &EagerTensor, cotangent: &EagerTensor, ) -> Result<EagerTensor>

Reverse-mode vector-Jacobian product for eager tensors.

§Examples
use tenferro_ad::{EagerRuntime, EagerTensor, Tensor};
use tenferro_cpu::CpuBackend;

let ctx = EagerRuntime::with_cpu_backend(CpuBackend::new());
let x = EagerTensor::requires_grad_in(
    Tensor::from_vec_col_major(vec![2], vec![2.0_f64, 3.0]).unwrap(),
    ctx.clone(),
)?;
let y = x.mul(&x)?;
let seed = EagerTensor::from_tensor_in(
    Tensor::from_vec_col_major(vec![2], vec![1.0_f64, 1.0]).unwrap(),
    ctx.clone(),
)?;
let dx = ctx.vjp(&y, &x, &seed)?;
assert_eq!(dx.materialized()?.as_slice::<f64>().unwrap(), &[4.0, 6.0]);
Source

pub fn vjp_optional( self: &Arc<Self>, output: &EagerTensor, wrt: &EagerTensor, cotangent: &EagerTensor, ) -> Result<Option<EagerTensor>>

Reverse-mode vector-Jacobian product that returns None for inactive inputs.

§Examples
use tenferro_ad::{EagerRuntime, EagerTensor, Tensor};
use tenferro_cpu::CpuBackend;

let ctx = EagerRuntime::with_cpu_backend(CpuBackend::new());
let x = EagerTensor::requires_grad_in(
    Tensor::from_vec_col_major(vec![1], vec![2.0_f64]).unwrap(),
    ctx.clone(),
)?;
let y = EagerTensor::requires_grad_in(
    Tensor::from_vec_col_major(vec![1], vec![4.0_f64]).unwrap(),
    ctx.clone(),
)?;
let seed = EagerTensor::from_tensor_in(
    Tensor::from_vec_col_major(vec![1], vec![1.0_f64]).unwrap(),
    ctx.clone(),
)?;
let loss = y.mul(&y)?;
assert!(ctx.vjp_optional(&loss, &x, &seed)?.is_none());
Source

pub fn jvp( self: &Arc<Self>, output: &EagerTensor, wrt: &EagerTensor, tangent: &EagerTensor, ) -> Result<EagerTensor>

Forward-mode Jacobian-vector product for eager tensors.

§Examples
use tenferro_ad::{EagerRuntime, EagerTensor, Tensor};
use tenferro_cpu::CpuBackend;

let ctx = EagerRuntime::with_cpu_backend(CpuBackend::new());
let x = EagerTensor::requires_grad_in(
    Tensor::from_vec_col_major(vec![1], vec![3.0_f64]).unwrap(),
    ctx.clone(),
)?;
let tangent = EagerTensor::from_tensor_in(
    Tensor::from_vec_col_major(vec![1], vec![1.0_f64]).unwrap(),
    ctx.clone(),
)?;
let y = x.mul(&x)?;
let dy = ctx.jvp(&y, &x, &tangent)?;
assert_eq!(dy.materialized()?.as_slice::<f64>().unwrap(), &[6.0]);
Source

pub fn jvp_optional( self: &Arc<Self>, output: &EagerTensor, wrt: &EagerTensor, tangent: &EagerTensor, ) -> Result<Option<EagerTensor>>

Forward-mode Jacobian-vector product that returns None for inactive outputs.

§Examples
use tenferro_ad::{EagerRuntime, EagerTensor, Tensor};
use tenferro_cpu::CpuBackend;

let ctx = EagerRuntime::with_cpu_backend(CpuBackend::new());
let x = EagerTensor::requires_grad_in(
    Tensor::from_vec_col_major(vec![1], vec![2.0_f64]).unwrap(),
    ctx.clone(),
)?;
let y = EagerTensor::requires_grad_in(
    Tensor::from_vec_col_major(vec![1], vec![4.0_f64]).unwrap(),
    ctx.clone(),
)?;
let tangent = EagerTensor::from_tensor_in(
    Tensor::from_vec_col_major(vec![1], vec![1.0_f64]).unwrap(),
    ctx.clone(),
)?;
let loss = y.mul(&y)?;
assert!(ctx.jvp_optional(&loss, &x, &tangent)?.is_none());

Trait Implementations§

Source§

impl Debug for EagerRuntime

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
§

impl<T> ByRef<T> for T

§

fn by_ref(&self) -> &T

§

impl<T> DistributionExt for T
where T: ?Sized,

§

fn rand<T>(&self, rng: &mut (impl Rng + ?Sized)) -> T
where Self: Distribution<T>,

Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self>

Converts self into a Left variant of Either<Self, Self> if into_left is true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
where F: FnOnce(&Self) -> bool,

Converts self into a Left variant of Either<Self, Self> if into_left(&self) returns true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
§

impl<T> Pointable for T

§

const ALIGN: usize

The alignment of pointer.
§

type Init = T

The type for initializers.
§

unsafe fn init(init: <T as Pointable>::Init) -> usize

Initializes a with the given initializer. Read more
§

unsafe fn deref<'a>(ptr: usize) -> &'a T

Dereferences the given pointer. Read more
§

unsafe fn deref_mut<'a>(ptr: usize) -> &'a mut T

Mutably dereferences the given pointer. Read more
§

unsafe fn drop(ptr: usize)

Drops the object pointed to by the given pointer. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

§

fn vzip(self) -> V

§

impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
where ST: ?Sized, DT: ?Sized,

§

impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
where ST: ?Sized, DT: ?Sized,

§

impl<T, U> Imply<T> for U
where T: ?Sized, U: ?Sized,

§

impl<T> MaybeSend for T
where T: Send,

§

impl<T> MaybeSendSync for T
where T: Send + Sync,

§

impl<T> MaybeSync for T
where T: Sync,

§

impl<T> Read<Exclusive, BecauseExclusive> for T
where T: ?Sized,