#![allow(private_bounds)]
use std::sync::Arc;
use crate::tensor::backend::{Backend, ComputeFor, DefaultBackend};
use crate::tensor::definitions::NumberLike;
use crate::tensor::errors::OpError;
use crate::tensor::graph::{NodeKind, TensorGraphCacheNode, TensorGraphNode};
use crate::tensor::mem_formats::layout::Layout;
use crate::tensor::ops::def_op::OpKind;
use crate::tensor::skeleton::{Clean, SkeletonSlot, Tainting};
use crate::tensor::tensor_interface::Tensor;
use crate::tensor::traits::{Composable, Dimension, Numeric, Operand, Promising};
pub struct TensorPromise<T, B: Backend = DefaultBackend> {
pub(crate) graph: Arc<TensorGraphNode<T, B>>,
}
impl<T: std::fmt::Debug, B: Backend> std::fmt::Debug for TensorPromise<T, B> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
std::fmt::Debug::fmt(&self.graph, f)
}
}
impl<T: Numeric, B: Backend> TensorPromise<T, B> {
pub(crate) fn new(op: OpKind<T>, inputs: Box<[NodeKind<T, B>]>) -> Result<Self, OpError> {
let node = TensorGraphNode::new(op, inputs);
match node {
Ok(node) => Ok(Self {
graph: Arc::new(node),
}),
Err(err) => Err(err),
}
}
pub(crate) fn with_layout(
op: OpKind<T>,
inputs: Box<[NodeKind<T, B>]>,
layout: Layout,
) -> Self {
Self {
graph: Arc::new(TensorGraphNode::with_layout(op, inputs, layout)),
}
}
pub fn cache(self) -> CachedTensorPromise<T, B> {
let base = unsafe {
TensorPromise::new(OpKind::AsContiguous, [NodeKind::Node(self.graph)].into())
.unwrap_unchecked()
};
unsafe {
CachedTensorPromise::new(OpKind::NoOp, [NodeKind::Node(base.graph)].into())
.unwrap_unchecked()
}
}
}
impl<T: NumberLike + ComputeFor<B>, B: Backend> TensorPromise<T, B> {
pub fn materialize(self) -> Tensor<T> {
Tensor::from_data(self.graph.compute())
}
pub fn clone_and_materialize(&self) -> Tensor<T> {
Tensor::from_data(self.graph.compute())
}
pub fn to_slot(&self) -> SkeletonSlot<T, B> {
SkeletonSlot::new(self.layout().clone())
}
}
impl<T, B: Backend> Operand<T, B> for TensorPromise<T, B> {
fn to_node(&self) -> NodeKind<T, B> {
NodeKind::Node(self.graph.clone())
}
}
impl<T, B: Backend> Tainting for TensorPromise<T, B> {
type Mark = Clean;
}
impl<T, B: Backend> Composable<T, B> for TensorPromise<T, B> {}
impl<T, B: Backend> Dimension for TensorPromise<T, B> {
#[inline]
fn layout(&self) -> &Layout {
self.graph.layout()
}
}
impl<T, B: Backend> Clone for TensorPromise<T, B> {
fn clone(&self) -> Self {
Self {
graph: self.graph.clone(),
}
}
}
pub struct CachedTensorPromise<T, B: Backend = DefaultBackend> {
pub(crate) graph: Arc<TensorGraphCacheNode<T, B>>,
}
impl<T: std::fmt::Debug, B: Backend> std::fmt::Debug for CachedTensorPromise<T, B> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
std::fmt::Debug::fmt(&self.graph, f)
}
}
impl<T: Numeric, B: Backend> CachedTensorPromise<T, B> {
pub(crate) fn new(op: OpKind<T>, inputs: Box<[NodeKind<T, B>]>) -> Result<Self, OpError> {
let node = TensorGraphCacheNode::new(op, inputs);
match node {
Ok(node) => Ok(Self {
graph: Arc::new(node),
}),
Err(err) => Err(err),
}
}
}
impl<T: NumberLike + ComputeFor<B>, B: Backend> CachedTensorPromise<T, B> {
pub fn get_cache(&self) -> Option<Tensor<T>> {
self.graph
.get_cache()
.map(|tensor| Tensor::from_data(tensor.clone()))
}
pub fn snapshot(&self) -> Tensor<T> {
if let Some(tensor) = self.graph.get_cache() {
Tensor::from_data(tensor.clone())
} else {
self.clone_and_materialize()
}
}
pub fn materialize(self) -> Tensor<T> {
Tensor::from_data(self.graph.compute())
}
pub fn clone_and_materialize(&self) -> Tensor<T> {
Tensor::from_data(self.graph.compute())
}
pub fn to_slot(&self) -> SkeletonSlot<T, B> {
SkeletonSlot::new(self.layout().clone())
}
}
impl<T, B: Backend> Operand<T, B> for CachedTensorPromise<T, B> {
fn to_node(&self) -> NodeKind<T, B> {
NodeKind::Cache(self.graph.clone())
}
}
impl<T, B: Backend> Tainting for CachedTensorPromise<T, B> {
type Mark = Clean;
}
impl<T, B: Backend> Composable<T, B> for CachedTensorPromise<T, B> {}
impl<T, B: Backend> Dimension for CachedTensorPromise<T, B> {
#[inline]
fn layout(&self) -> &Layout {
self.graph.layout()
}
}
impl<T, B: Backend> Clone for CachedTensorPromise<T, B> {
fn clone(&self) -> Self {
Self {
graph: self.graph.clone(),
}
}
}