use bumpalo::Bump;
use std::{cell::RefCell, ptr::NonNull};
use crate::utils::errors::Result;
use crate::{ad::node::TapeNode, utils::errors::QSError};
pub struct Tape {
bump: Bump,
book: Vec<NonNull<TapeNode>>,
mark: usize,
active: bool,
}
impl Tape {
#[must_use]
pub fn new() -> Self {
Self {
bump: Bump::new(),
book: Vec::new(),
mark: 0,
active: false,
}
}
#[inline]
fn push(&mut self, n: TapeNode) -> NonNull<TapeNode> {
let ptr = NonNull::from(self.bump.alloc(n));
self.book.push(ptr);
ptr
}
#[inline]
pub fn reset_adjoints() {
TAPE.with(|tc| {
for &ptr in &tc.borrow().book {
unsafe { (*ptr.as_ptr()).adj = 0.0 };
}
});
}
pub const fn mark(&self) -> usize {
self.mark
}
#[inline]
fn index_of(&self, p: NonNull<TapeNode>) -> Option<usize> {
self.book.iter().position(|&q| q == p)
}
#[inline]
pub fn new_leaf(&mut self) -> Option<NonNull<TapeNode>> {
self.record(TapeNode::default())
}
#[inline]
pub fn record(&mut self, n: TapeNode) -> Option<NonNull<TapeNode>> {
self.active.then(|| self.push(n))
}
pub fn node(&self, p: NonNull<TapeNode>) -> Option<&TapeNode> {
self.index_of(p).map(|i| unsafe { self.book[i].as_ref() })
}
pub fn mut_node(&mut self, p: NonNull<TapeNode>) -> Option<&mut TapeNode> {
self.index_of(p).map(|i| unsafe { self.book[i].as_mut() })
}
pub fn propagate_from(&mut self, root: NonNull<TapeNode>) -> Result<()> {
let start = self
.index_of(root)
.ok_or(QSError::NodeNotIndexedInTapeErr)?;
for i in (0..=start).rev() {
let node = unsafe { self.book[i].as_ref().clone() };
node.propagate_into();
}
Ok(())
}
pub fn propagate_mark_to_start(&mut self) -> Result<()> {
let end = self.mark.saturating_sub(1);
for i in (0..=end).rev() {
let node = unsafe { self.book[i].as_ref().clone() };
node.propagate_into();
}
Ok(())
}
pub fn propagate_to_mark(&mut self) -> Result<()> {
let start = self.mark;
let end = self.book.len().saturating_sub(1);
if start > end {
return Ok(()); }
for i in (start..=end).rev() {
let node = unsafe { self.book[i].as_ref().clone() };
node.propagate_into();
}
Ok(())
}
pub fn start_recording() {
TAPE.with(|tc| {
let mut t = tc.borrow_mut();
t.bump.reset();
t.book.clear();
t.mark = 0;
t.active = true;
});
}
pub fn stop_recording() {
TAPE.with(|tc| tc.borrow_mut().active = false);
}
#[inline]
#[must_use]
pub fn is_active() -> bool {
TAPE.with(|tc| tc.borrow().active)
}
pub fn set_mark() {
TAPE.with(|tc| {
let len = tc.borrow().book.len();
tc.borrow_mut().mark = len;
});
}
pub fn rewind_to_mark() {
TAPE.with(|tc| {
let mark = tc.borrow().mark;
tc.borrow_mut().book.truncate(mark);
});
}
pub fn reset_mark() {
TAPE.with(|tc| {
tc.borrow_mut().mark = 0;
});
}
pub fn rewind_to_init() {
TAPE.with(|tc| {
let mut t = tc.borrow_mut();
t.bump.reset();
t.book.clear();
t.mark = 0;
});
}
}
impl Default for Tape {
fn default() -> Self {
Self::new()
}
}
thread_local! {
pub static TAPE: RefCell<Tape> = RefCell::new(Tape {
bump: Bump::new(),
book: Vec::new(),
mark: 0,
active: false,
});
}