use std::ops::Add;
use static_assertions::assert_impl_all;
use crate::{Element, Tensor};
use super::{Kinship, Origin, Parameters, Symbol};
assert_impl_all!(Field<f64>: Send, Sync);
#[derive(Debug, Clone)]
pub struct Field<E> {
origin: Origin,
payloads: Vec<Tensor<E>>,
}
pub type Gradients<E> = Field<E>;
impl<E: Element> Field<E> {
pub(crate) fn new(origin: Origin, payloads: Vec<Tensor<E>>) -> Self {
Self { origin, payloads }
}
pub(crate) fn origin(&self) -> Origin {
self.origin
}
pub(crate) fn len(&self) -> usize {
self.payloads.len()
}
pub fn of(&self, symbol: Symbol) -> &Tensor<E> {
let index = Kinship::over(self.origin, self.payloads.len())
.locate(symbol, "symbol was allocated after this field was produced");
&self.payloads[index]
}
pub fn map(&self, transform: impl Fn(&Tensor<E>) -> Tensor<E>) -> Self {
Self {
origin: self.origin,
payloads: self.payloads.iter().map(transform).collect(),
}
}
pub fn zip(&self, other: &Self, combine: impl Fn(&Tensor<E>, &Tensor<E>) -> Tensor<E>) -> Self {
self.assert_compatible(other);
Self {
origin: self.origin,
payloads: self
.payloads
.iter()
.zip(&other.payloads)
.map(|(left, right)| combine(left, right))
.collect(),
}
}
pub fn payloads(&self) -> &[Tensor<E>] {
&self.payloads
}
pub fn parameters(&self, parameters: &Parameters<E>) -> Parameters<E> {
parameters.filled_from(self)
}
fn assert_compatible(&self, other: &Self) {
assert!(
self.origin == other.origin,
"fields belong to different networks"
);
assert_eq!(
self.payloads.len(),
other.payloads.len(),
"fields cover different prefixes of the network"
);
}
}
impl<E: Element> Field<E> {
pub fn scale(&self, factor: &Tensor<E>) -> Self {
self.map(|value| value.clone() * factor.broadcast_like(value))
}
}
impl<E: Element> Add for &Field<E> {
type Output = Field<E>;
fn add(self, rhs: Self) -> Field<E> {
self.zip(rhs, |left, right| left.clone() + right.clone())
}
}
impl<E: Element> Add for Field<E> {
type Output = Field<E>;
fn add(self, rhs: Self) -> Field<E> {
&self + &rhs
}
}
#[cfg(test)]
#[path = "tests/field_tests.rs"]
mod tests;