use std::fmt;
use std::ops::{Add, Div, Mul, Neg, Sub};
use crate::{Differentiable, Elementary, Shape, Tensorial};
use super::Value;
pub(crate) struct Trace<'network, Data> {
value: Value<'network, Data>,
}
impl<'network, Data: Differentiable> Trace<'network, Data> {
pub(crate) fn of(value: Value<'network, Data>) -> Self {
Self { value }
}
pub(crate) fn value(&self) -> Value<'network, Data> {
self.value
}
fn counted_like(&self, count: usize) -> Self {
Self::of(self.value.literal(Data::counted(self.value.shape(), count)))
}
}
impl<Data> Clone for Trace<'_, Data> {
fn clone(&self) -> Self {
*self
}
}
impl<Data> Copy for Trace<'_, Data> {}
impl<Data> fmt::Debug for Trace<'_, Data> {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
formatter.debug_struct("Trace").finish_non_exhaustive()
}
}
impl<'network, Data: Differentiable> Add for Trace<'network, Data> {
type Output = Self;
fn add(self, rhs: Self) -> Self {
Self::of(self.value + rhs.value)
}
}
impl<'network, Data: Differentiable> Sub for Trace<'network, Data> {
type Output = Self;
fn sub(self, rhs: Self) -> Self {
Self::of(self.value - rhs.value)
}
}
impl<'network, Data: Differentiable> Mul for Trace<'network, Data> {
type Output = Self;
fn mul(self, rhs: Self) -> Self {
Self::of(self.value * rhs.value)
}
}
impl<'network, Data: Differentiable> Div for Trace<'network, Data> {
type Output = Self;
fn div(self, rhs: Self) -> Self {
Self::of(self.value / rhs.value)
}
}
impl<'network, Data: Differentiable> Neg for Trace<'network, Data> {
type Output = Self;
fn neg(self) -> Self {
Self::of(-self.value)
}
}
impl<'network, Data: Tensorial> Differentiable for Trace<'network, Data> {
type Accumulator = Self;
fn promote(&self) -> Self {
*self
}
fn demote(accumulated: Self) -> Self {
accumulated
}
fn zero_like(&self) -> Self {
self.counted_like(0)
}
fn one_like(&self) -> Self {
self.counted_like(1)
}
fn counted(_shape: Shape, _count: usize) -> Self {
panic!("`Trace` records derivative rules, which never call `counted`");
}
fn shape(&self) -> Shape {
self.value.shape()
}
}
impl<'network, Data: Tensorial> Elementary for Trace<'network, Data> {
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 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))
}
}
impl<'network, Data: Tensorial> Tensorial for Trace<'network, Data> {
fn matmul(&self, rhs: &Self) -> Self {
Self::of(self.value.matmul(rhs.value))
}
fn transpose(&self) -> Self {
Self::of(self.value.transpose())
}
fn sum(&self) -> Self {
Self::of(self.value.sum())
}
fn sum_along(&self, axis: usize) -> Self {
Self::of(self.value.sum_along(axis))
}
fn max_along(&self, _axis: usize) -> Self {
panic!("`Trace` records derivative rules, which never call `max_along`");
}
fn broadcast_like(&self, reference: &Self) -> Self {
Self::of(self.value.broadcast_like(reference.value))
}
fn broadcast_along(&self, axis: usize, reference: &Self) -> Self {
Self::of(self.value.broadcast_along(axis, reference.value))
}
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, rows: usize) -> Self {
Self::of(self.value.scatter(selection.value, rows))
}
}