use std::sync::Arc;
use static_assertions::assert_impl_all;
use crate::{Element, Tensor};
use crate::op::Op;
use super::{Kinship, Node, Origin, Parameters, SlotStore, Structure, Symbol, Tape, ValueId};
assert_impl_all!(Network<f64>: Send, Sync);
#[derive(Debug)]
pub struct Network<E> {
origin: Origin,
structure: Structure<Tensor<E>>,
initials: SlotStore<Tensor<E>>,
inputs: Arc<SlotStore<Tensor<E>>>,
}
impl<E: Element> Network<E> {
pub(super) fn seal(
origin: Origin,
structure: Structure<Tensor<E>>,
initials: SlotStore<Tensor<E>>,
inputs: SlotStore<Tensor<E>>,
) -> Self {
Self {
origin,
structure,
initials,
inputs: Arc::new(inputs),
}
}
pub fn into_tape(self) -> Tape<E> {
Tape::reopen(self.origin, self)
}
pub(super) fn into_stores(
self,
) -> (
Structure<Tensor<E>>,
SlotStore<Tensor<E>>,
SlotStore<Tensor<E>>,
) {
(
self.structure,
self.initials,
Arc::unwrap_or_clone(self.inputs),
)
}
pub fn parameters(&self) -> Parameters<E> {
Parameters::new(self.origin, self.initials.clone())
}
pub fn len(&self) -> usize {
self.structure.len()
}
pub fn is_empty(&self) -> bool {
self.len() == 0
}
pub(crate) fn origin(&self) -> Origin {
self.origin
}
pub(crate) fn structure(&self) -> &Structure<Tensor<E>> {
&self.structure
}
pub(crate) fn inputs(&self) -> &Arc<SlotStore<Tensor<E>>> {
&self.inputs
}
pub(crate) fn parameters_len(&self) -> usize {
self.initials.len()
}
pub fn node(&self, symbol: Symbol) -> Node {
let id = self.locate(symbol);
self.structure.node_at(self.origin, id.index())
}
pub fn nodes(&self) -> impl Iterator<Item = Node> + '_ {
(0..self.len()).map(|index| self.structure.node_at(self.origin, index))
}
pub fn payload(&self, symbol: Symbol) -> Option<&Tensor<E>> {
let id = self.locate(symbol);
match self
.structure
.ops
.get(id.index())
.expect("`locate` checked the bounds")
{
Op::Leaf(leaf) => Some(&leaf.0),
Op::Parameter(parameter) => Some(&self.initials.payloads()[parameter.0.index()]),
Op::Input(input) => Some(&self.inputs.payloads()[input.0.index()]),
_ => None,
}
}
pub fn describe(&self) -> String {
use std::fmt::Write;
let mut lines = String::new();
for node in self.nodes() {
writeln!(lines, "{}", node.spec_line()).expect("writing to a string cannot fail");
}
let nodes = self.len();
let parameters = self.initials.len();
let inputs = self.inputs.len();
writeln!(
lines,
"network: {nodes} node{}, {parameters} parameter{}, {inputs} input{}",
if nodes == 1 { "" } else { "s" },
if parameters == 1 { "" } else { "s" },
if inputs == 1 { "" } else { "s" },
)
.expect("writing to a string cannot fail");
lines
}
pub(crate) fn locate(&self, symbol: Symbol) -> ValueId {
Kinship::over(self.origin, self.structure.len())
.locate(symbol, "symbol is not allocated in this network");
symbol.id
}
}
#[cfg(test)]
#[path = "tests/network_tests.rs"]
mod tests;