deep_causality/traits/transferable/mod.rs
1/*
2 * SPDX-License-Identifier: MIT
3 * Copyright (c) 2023 - 2026. The DeepCausality Authors and Contributors. All Rights Reserved.
4 */
5
6//!
7//! Trait for assumption verification used in the Model type.
8//!
9use crate::{Assumable, Assumption, AssumptionError, PropagatingEffect};
10use std::sync::Arc;
11
12/// Trait for types that can verify their assumptions against propagating effects.
13///
14/// Assumptions are verified using `PropagatingEffect<bool>` where the boolean
15/// represents whether an assumption holds or not.
16pub trait Transferable {
17 fn get_assumptions(&self) -> &Option<Arc<Vec<Assumption>>>;
18
19 /// Verifies the model's assumptions against a given PropagatingEffect.
20 ///
21 /// The function iterates through all defined assumptions and checks them against
22 /// the provided data. It short-circuits and returns immediately on the first
23 /// failure or error.
24 ///
25 /// Overwrite the default implementation if you need customization.
26 ///
27 /// # Arguments
28 /// * `effect` - Sample data to be tested. Details on sampling should be documented in each assumption.
29 ///
30 /// # Returns
31 /// * `Ok(())` if all assumptions hold true.
32 /// * `Err(AssumptionError::AssumptionFailed(String))` if an assumption is not met.
33 /// * `Err(AssumptionError::NoAssumptionsDefined)` if the model has no assumptions.
34 /// * `Err(AssumptionError::NoDataToTestDefined)` if the effect slice is empty.
35 /// * `Err(AssumptionError::EvaluationError(...))` if an error occurs during evaluation.
36 ///
37 fn verify_assumptions(&self, effect: &[PropagatingEffect<f64>]) -> Result<(), AssumptionError> {
38 if effect.is_empty() {
39 return Err(AssumptionError::NoDataToTestDefined);
40 }
41
42 if self.get_assumptions().is_none() {
43 return Err(AssumptionError::NoAssumptionsDefined);
44 }
45
46 let assumptions = self.get_assumptions().as_ref().unwrap();
47
48 for assumption in assumptions.iter() {
49 // The `?` operator propagates any evaluation errors.
50 if !assumption.verify_assumption(effect)? {
51 // If an assumption returns `Ok(false)`, the check has failed.
52 // We now return an error containing the specific assumption that failed.
53 return Err(AssumptionError::AssumptionFailed(assumption.to_string()));
54 }
55 }
56
57 // If the loop completes, all assumptions passed.
58 Ok(())
59 }
60}