use std::sync::{Arc, Mutex};
pub trait MatrixHook: Send + Sync {
fn on_converge(&self, node_name: &str, actual_contribution: f64, surprise: f64, quality: f64);
fn route(&self, from: &str, candidates: &[String]) -> Option<Vec<String>>;
fn c_value(&self) -> f64;
fn completion(&self) -> f64;
fn is_converged(&self) -> bool;
fn record_transition(&self, from: &str, to: &str, quality: f64);
}
#[derive(Clone)]
pub struct MatrixHookHandle(pub(crate) Arc<dyn MatrixHook>);
impl MatrixHookHandle {
pub fn new(hook: impl MatrixHook + 'static) -> Self {
Self(Arc::new(hook))
}
pub fn on_converge(
&self,
node_name: &str,
actual_contribution: f64,
surprise: f64,
quality: f64,
) {
self.0
.on_converge(node_name, actual_contribution, surprise, quality);
}
pub fn route(&self, from: &str, candidates: &[String]) -> Option<Vec<String>> {
self.0.route(from, candidates)
}
pub fn c_value(&self) -> f64 {
self.0.c_value()
}
pub fn completion(&self) -> f64 {
self.0.completion()
}
pub fn is_converged(&self) -> bool {
self.0.is_converged()
}
pub fn record_transition(&self, from: &str, to: &str, quality: f64) {
self.0.record_transition(from, to, quality);
}
}
impl std::fmt::Debug for MatrixHookHandle {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("MatrixHookHandle")
.field("c_value", &self.c_value())
.field("completion", &self.completion())
.field("is_converged", &self.is_converged())
.finish()
}
}
pub struct DefaultMatrixHook<T: ConvergenceRecorder, R: RoutingResolver> {
tracker: Mutex<T>,
router: Mutex<R>,
}
impl<T: ConvergenceRecorder, R: RoutingResolver> DefaultMatrixHook<T, R> {
pub fn new(tracker: T, router: R) -> Self {
Self {
tracker: Mutex::new(tracker),
router: Mutex::new(router),
}
}
}
impl<T: ConvergenceRecorder, R: RoutingResolver> MatrixHook for DefaultMatrixHook<T, R> {
fn on_converge(&self, _node_name: &str, actual_contribution: f64, surprise: f64, quality: f64) {
if let Ok(mut t) = self.tracker.lock() {
t.record(actual_contribution, surprise, quality);
}
}
fn route(&self, from: &str, candidates: &[String]) -> Option<Vec<String>> {
self.router.lock().ok()?.resolve(from, candidates)
}
fn c_value(&self) -> f64 {
self.tracker.lock().map(|t| t.c_value()).unwrap_or(0.0)
}
fn completion(&self) -> f64 {
self.tracker.lock().map(|t| t.completion()).unwrap_or(0.0)
}
fn is_converged(&self) -> bool {
self.tracker
.lock()
.map(|t| t.is_converged())
.unwrap_or(false)
}
fn record_transition(&self, from: &str, to: &str, quality: f64) {
if let Ok(mut r) = self.router.lock() {
r.learn(from, to, quality);
}
}
}
pub trait ConvergenceRecorder: Send {
fn record(&mut self, actual_contribution: f64, surprise: f64, quality: f64);
fn c_value(&self) -> f64;
fn completion(&self) -> f64;
fn is_converged(&self) -> bool;
}
pub trait RoutingResolver: Send {
fn resolve(&self, from: &str, candidates: &[String]) -> Option<Vec<String>>;
fn learn(&mut self, from: &str, to: &str, quality: f64);
}