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}