Skip to main content

Skeleton

Struct Skeleton 

Source
pub struct Skeleton<T, B: Backend = DefaultBackend> { /* private fields */ }
Expand description

A precompiled execution plan, built once and run many times against new inputs.

§Examples

use candela::Tensor;
use std::error::Error;

// Creates tensors
let a = Tensor::from_scalar(0.3, &[4]);
let b = Tensor::from_scalar(0.3, &[8]);

// Creates a slot for a tensor with the same shape as a
let slot = a.to_slot();

// Create a skeleton with that slot
let skeleton = (&slot * 2.0 + 1.0).log2().into_skeleton(&[slot]).unwrap();

// Running the skeleton
let output_a = skeleton.run(&[&a]);

// Running the skeleton for an invalid shape
let output_b = skeleton.run(&[&b]);

// Check the output is ok
assert!(output_a.is_ok());

// Check the output is an error
assert!(output_b.is_err());

Implementations§

Source§

impl<T: Clone + PartialEq + ComputeFor<B>, B: Backend> Skeleton<T, B>

Source

pub fn run(&self, inputs: &[&Tensor<T, B>]) -> Result<Tensor<T, B>, OpError>

Executes the compiled plan against inputs and returns the result.

Runs the stored plan on the provided inputs without re-planning. The inputs must be supplied in the same order they were declared to into_skeleton.

§Errors

Returns OpError::IncorrectSlotAmount if inputs.len() differs from the number of declared slots, or OpError::NotSameLayoutAtSlot if an input’s Layout does not match the layout its slot was declared with.

§Examples
use candela::skeleton::SkeletonSlot;
use candela::{Layout, Tensor};

// The same compiled plan, executed against two different inputs.
let slot = SkeletonSlot::new(Layout::new(&[4]));
let skeleton = (&slot * 2.0 + 1.0).into_skeleton(std::slice::from_ref(&slot))?;

let a = skeleton.run(&[&Tensor::from_slice(&[0.0, 1.0, 2.0, 3.0], &[4])])?;
let b = skeleton.run(&[&Tensor::from_scalar(5.0, &[4])])?;
assert_eq!(a.data(), &[1.0, 3.0, 5.0, 7.0]);
assert_eq!(b.data(), &[11.0; 4]);
Source

pub fn compose<C: Composable<T, B>>( &self, inputs: &[&C], ) -> Result<BakedPromise<T, B>, OpError>

Embeds the compiled plan as a node in a larger graph.

Embeds the Skeleton’s plan into a promise that must still be planned and materialized to produce a Tensor. Unlike run, its inputs may be any Composable operand except a slot - Tensor, TensorPromise, or BakedPromise.

For all practical purposes, treat the output of this function as a compressed representation of a TensorPromise.

§Errors

Returns OpError::IncorrectSlotAmount if inputs.len() differs from the number of declared slots, or OpError::NotSameLayoutAtSlot if an input’s Layout does not match the layout its slot was declared with.

§Examples
use candela::skeleton::SkeletonSlot;
use candela::{Layout, Tensor};

let lhs = Tensor::from_slice(&[1.0, 2.0, 3.0, 4.0], &[4]);
let rhs = Tensor::from_scalar(10.0, &[4]);

// Compile `a + b` over two slots, then splice it into a bigger expression.
let a = SkeletonSlot::new(Layout::new(&[4]));
let b = a.deep_clone();
let sum = (&a + &b).into_skeleton(&[a, b])?;

let baked = sum.compose(&[&lhs, &rhs])?;
// `baked` slots into a normal promise expression.
let result = (baked * 2.0).materialize();
assert_eq!(result.data(), &[22.0, 24.0, 26.0, 28.0]);
Source§

impl<T, B: Backend> Skeleton<T, B>

Source

pub fn memory_report(&self) -> MemoryMetrics

Reports memory allocations

Reports the memory that will be allocated during the execution of the Skeleton. The report is correct at the moment this function was called, but changes to cache state (filled vs empty) after it was run will change the metrics.

For the most accurate results rerun this function every time a cache part of this Skeleton is changed (even by itself on the first run).

§Examples
use candela::skeleton::SkeletonSlot;

let slot = SkeletonSlot::from_shape(&[8]);
let skeleton = (&slot * 2.0).into_skeleton(&[slot])?;

let report = skeleton.memory_report();
assert!(report.total_number_of_allocations >= 1);
assert_eq!(report.output_memory_usage, 64); // [8] f64 = 64 bytes

Trait Implementations§

Source§

impl<T, B: Backend> Debug for Skeleton<T, B>

Source§

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

Formats the value using the given formatter. Read more
Source§

impl<T, B: Backend> Dimension for Skeleton<T, B>

Source§

fn layout(&self) -> &Layout

Source§

fn shape(&self) -> &[usize]

Source§

fn stride(&self) -> &[i32]

Source§

fn adj_stride(&self) -> &[i32]

Source§

fn len(&self) -> usize

Source§

fn is_empty(&self) -> bool

Source§

fn offset(&self) -> usize

Source§

fn is_contiguous(&self) -> bool

Source§

fn is_contiguous_at_axis(&self, axis: usize) -> bool

Source§

fn is_transposed(&self) -> bool

Source§

fn is_transposed_at_axis(&self, axis: usize) -> bool

Auto Trait Implementations§

§

impl<T, B> Freeze for Skeleton<T, B>

§

impl<T, B> RefUnwindSafe for Skeleton<T, B>

§

impl<T, B> Send for Skeleton<T, B>
where B: Sync + Send, T: Sync + Send,

§

impl<T, B> Sync for Skeleton<T, B>
where B: Sync + Send, T: Sync + Send,

§

impl<T, B> Unpin for Skeleton<T, B>

§

impl<T, B> UnsafeUnpin for Skeleton<T, B>

§

impl<T, B> UnwindSafe for Skeleton<T, B>

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
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, 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.