use super::Symbol;
#[derive(Debug, Clone)]
pub struct Adjoints {
target: Symbol,
pairs: Vec<(Symbol, Symbol)>,
}
impl Adjoints {
pub(crate) fn new(target: Symbol, pairs: Vec<(Symbol, Symbol)>) -> Self {
Self { target, pairs }
}
pub fn target(&self) -> Symbol {
self.target
}
pub fn pairs(&self) -> &[(Symbol, Symbol)] {
&self.pairs
}
pub fn wrt(&self) -> impl Iterator<Item = Symbol> + '_ {
self.pairs.iter().map(|&(wrt, _)| wrt)
}
pub fn gradients(&self) -> impl Iterator<Item = Symbol> + '_ {
self.pairs.iter().map(|&(_, gradient)| gradient)
}
pub fn of(&self, wrt: Symbol) -> Symbol {
self.pairs
.iter()
.find(|&&(entry, _)| entry == wrt)
.map(|&(_, gradient)| gradient)
.expect("no gradient was recorded for this symbol; it was not a `wrt` entry")
}
pub fn roots(&self) -> impl Iterator<Item = Symbol> + '_ {
std::iter::once(self.target).chain(self.gradients())
}
pub fn map_gradients(&self, mut rewrite: impl FnMut(Symbol) -> Symbol) -> Self {
Self {
target: self.target,
pairs: self
.pairs
.iter()
.map(|&(wrt, gradient)| (wrt, rewrite(gradient)))
.collect(),
}
}
}
#[cfg(test)]
#[path = "tests/adjoints_tests.rs"]
mod tests;