use std::fmt;
use std::ops::{Add, Div, Mul, Neg, Sub};
use crate::{Element, Recordable, Shape, Tensor};
use super::Value;
pub struct Trace<'tape, E> {
value: Value<'tape, E>,
}
impl<'tape, E: Element> Trace<'tape, E> {
pub fn of(value: Value<'tape, E>) -> Self {
Self { value }
}
pub fn value(&self) -> Value<'tape, E> {
self.value
}
fn filled_like(&self, element: E) -> Self {
Self::of(
self.value
.literal(Tensor::filled(self.value.shape(), element)),
)
}
}
impl<E> Clone for Trace<'_, E> {
fn clone(&self) -> Self {
*self
}
}
impl<E> Copy for Trace<'_, E> {}
impl<E> fmt::Debug for Trace<'_, E> {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
formatter.debug_struct("Trace").finish_non_exhaustive()
}
}
impl<'tape, E: Element> Add for Trace<'tape, E> {
type Output = Self;
fn add(self, rhs: Self) -> Self {
Self::of(self.value + rhs.value)
}
}
impl<'tape, E: Element> Sub for Trace<'tape, E> {
type Output = Self;
fn sub(self, rhs: Self) -> Self {
Self::of(self.value - rhs.value)
}
}
impl<'tape, E: Element> Mul for Trace<'tape, E> {
type Output = Self;
fn mul(self, rhs: Self) -> Self {
Self::of(self.value * rhs.value)
}
}
impl<'tape, E: Element> Div for Trace<'tape, E> {
type Output = Self;
fn div(self, rhs: Self) -> Self {
Self::of(self.value / rhs.value)
}
}
impl<'tape, E: Element> Neg for Trace<'tape, E> {
type Output = Self;
fn neg(self) -> Self {
Self::of(-self.value)
}
}
impl<'tape, E: Element> Recordable for Trace<'tape, E> {
fn shape(&self) -> Shape {
self.value.shape()
}
fn zero_like(&self) -> Self {
self.filled_like(E::zero())
}
fn one_like(&self) -> Self {
self.filled_like(E::one())
}
fn exp(&self) -> Self {
Self::of(self.value.exp())
}
fn ln(&self) -> Self {
Self::of(self.value.ln())
}
fn sqrt(&self) -> Self {
Self::of(self.value.sqrt())
}
fn tanh(&self) -> Self {
Self::of(self.value.tanh())
}
fn sin(&self) -> Self {
Self::of(self.value.sin())
}
fn cos(&self) -> Self {
Self::of(self.value.cos())
}
fn log1p(&self) -> Self {
Self::of(self.value.log1p())
}
fn expm1(&self) -> Self {
Self::of(self.value.expm1())
}
fn erf(&self) -> Self {
Self::of(self.value.erf())
}
fn erf_derivative(&self) -> Self {
Self::of(self.value.erf_derivative())
}
fn powf(&self, exponent: Self) -> Self {
Self::of(self.value.powf(exponent.value))
}
fn maximum(&self, other: &Self) -> Self {
Self::of(self.value.maximum(other.value))
}
fn step(&self, threshold: &Self) -> Self {
Self::of(self.value.step(threshold.value))
}
fn matmul(&self, rhs: &Self) -> Self {
Self::of(self.value.matmul(rhs.value))
}
fn sum(&self) -> Self {
Self::of(self.value.sum())
}
fn sum_along(&self, axis: usize) -> Self {
Self::of(self.value.sum_along(axis))
}
fn logsumexp(&self, axis: usize) -> Self {
Self::of(self.value.logsumexp(axis))
}
fn log_softmax(&self, axis: usize) -> Self {
Self::of(self.value.log_softmax(axis))
}
fn broadcast(&self, shape: Shape) -> Self {
Self::of(self.value.broadcast(shape))
}
fn broadcast_along(&self, axis: usize, extent: usize) -> Self {
Self::of(self.value.broadcast_along(axis, extent))
}
fn reshape(&self, shape: Shape) -> Self {
Self::of(self.value.reshape(shape))
}
fn permute(&self, order: &[usize]) -> Self {
Self::of(self.value.permute(order.iter().copied()))
}
fn narrow(&self, axis: usize, start: usize, len: usize) -> Self {
Self::of(self.value.narrow(axis, start, len))
}
fn pad(&self, axis: usize, start: usize, full_extent: usize) -> Self {
Self::of(self.value.pad(axis, start, full_extent))
}
fn unfold(&self, axis: usize, size: usize, step: usize, dilation: usize) -> Self {
Self::of(self.value.unfold(axis, size, step, dilation))
}
fn fold(&self, axis: usize, size: usize, step: usize, dilation: usize, extent: usize) -> Self {
Self::of(self.value.fold(axis, size, step, dilation, extent))
}
fn gather(&self, selection: &Self) -> Self {
Self::of(self.value.gather(selection.value))
}
fn scatter(&self, selection: &Self) -> Self {
Self::of(self.value.scatter(selection.value))
}
}