mathhook_core/educational/
traits.rs

1//! Educational operation traits for step-by-step explanations
2//!
3//! This module defines the core architectural pattern for integrating educational
4//! explanations across all mathematical operations in MathHook.
5
6use crate::educational::step_by_step::StepByStepExplanation;
7
8/// Context information for educational operations
9///
10/// Provides metadata about the operation being performed, which can be used
11/// to generate appropriate educational explanations.
12#[derive(Debug, Clone, PartialEq)]
13pub struct OperationContext {
14    /// Type of operation (e.g., "solving_equation", "differentiation", "simplification")
15    pub operation_type: String,
16    /// Difficulty level (1-10, where 1 is basic and 10 is advanced)
17    pub difficulty_level: u8,
18    /// Mathematical domain (e.g., "algebra", "calculus", "linear_algebra")
19    pub domain: String,
20    /// Prerequisites required to understand this operation
21    pub prerequisites: Vec<String>,
22}
23
24impl OperationContext {
25    /// Create a new operation context
26    ///
27    /// # Arguments
28    ///
29    /// * `operation_type` - Type of mathematical operation
30    /// * `difficulty_level` - Difficulty from 1-10
31    /// * `domain` - Mathematical domain
32    ///
33    /// # Examples
34    ///
35    /// ```rust
36    /// use mathhook_core::educational::traits::OperationContext;
37    ///
38    /// let context = OperationContext::new(
39    ///     "solving_quadratic",
40    ///     5,
41    ///     "algebra"
42    /// );
43    /// assert_eq!(context.operation_type, "solving_quadratic");
44    /// assert_eq!(context.difficulty_level, 5);
45    /// ```
46    pub fn new<S: Into<String>>(operation_type: S, difficulty_level: u8, domain: S) -> Self {
47        Self {
48            operation_type: operation_type.into(),
49            difficulty_level: difficulty_level.min(10),
50            domain: domain.into(),
51            prerequisites: Vec::new(),
52        }
53    }
54
55    /// Add a prerequisite to this operation
56    ///
57    /// # Examples
58    ///
59    /// ```rust
60    /// use mathhook_core::educational::traits::OperationContext;
61    ///
62    /// let mut context = OperationContext::new("solving_quadratic", 5, "algebra");
63    /// context.add_prerequisite("factoring");
64    /// context.add_prerequisite("square_roots");
65    /// assert_eq!(context.prerequisites.len(), 2);
66    /// ```
67    pub fn add_prerequisite<S: Into<String>>(&mut self, prerequisite: S) {
68        self.prerequisites.push(prerequisite.into());
69    }
70
71    /// Create context for equation solving
72    pub fn equation_solving(difficulty_level: u8) -> Self {
73        let mut context = Self::new("solving_equation", difficulty_level, "algebra");
74        context.add_prerequisite("basic_algebra");
75        context
76    }
77
78    /// Create context for differentiation
79    pub fn differentiation(difficulty_level: u8) -> Self {
80        let mut context = Self::new("differentiation", difficulty_level, "calculus");
81        context.add_prerequisite("limits");
82        context.add_prerequisite("functions");
83        context
84    }
85
86    /// Create context for simplification
87    pub fn simplification(difficulty_level: u8) -> Self {
88        let mut context = Self::new("simplification", difficulty_level, "algebra");
89        context.add_prerequisite("basic_operations");
90        context
91    }
92}
93
94/// Trait for mathematical operations that provide educational explanations
95///
96/// This trait establishes the architectural pattern for integrating step-by-step
97/// educational explanations into mathematical operations. All operations that want
98/// to provide educational value should implement this trait.
99///
100/// The trait provides two execution paths:
101/// 1. `execute_with_steps` - Full educational mode with detailed explanations
102/// 2. `execute_fast` - Performance-optimized mode without explanation overhead
103pub trait EducationalOperation {
104    /// The output type of this operation
105    type Output;
106    fn execute_with_steps(&self) -> (Self::Output, StepByStepExplanation);
107    fn educational_context(&self) -> OperationContext;
108    fn execute_fast(&self) -> Self::Output {
109        let (result, _explanation) = self.execute_with_steps();
110        result
111    }
112    fn can_explain(&self) -> bool {
113        true
114    }
115    fn estimated_steps(&self) -> Option<usize> {
116        None
117    }
118}
119
120/// Extension trait for adding educational capabilities to existing operations
121///
122/// This trait allows existing mathematical operations to be wrapped with
123/// educational functionality without modifying their core implementation.
124pub trait EducationalExt {
125    /// Wrap this operation to enable educational explanation generation
126    ///
127    /// This method creates a wrapper that implements `EducationalOperation`
128    /// around the existing operation.
129    fn with_education(self) -> impl EducationalOperation<Output = Self>
130    where
131        Self: Sized + Clone;
132}
133
134#[cfg(test)]
135mod tests {
136    use super::*;
137
138    #[test]
139    fn test_operation_context_creation() {
140        let context = OperationContext::new("test_operation", 5, "algebra");
141        assert_eq!(context.operation_type, "test_operation");
142        assert_eq!(context.difficulty_level, 5);
143        assert_eq!(context.domain, "algebra");
144        assert!(context.prerequisites.is_empty());
145    }
146
147    #[test]
148    fn test_operation_context_difficulty_clamping() {
149        let context = OperationContext::new("test", 15, "algebra");
150        assert_eq!(context.difficulty_level, 10);
151    }
152
153    #[test]
154    fn test_operation_context_prerequisites() {
155        let mut context = OperationContext::new("advanced_operation", 8, "calculus");
156        context.add_prerequisite("limits");
157        context.add_prerequisite("derivatives");
158
159        assert_eq!(context.prerequisites.len(), 2);
160        assert!(context.prerequisites.contains(&"limits".to_string()));
161        assert!(context.prerequisites.contains(&"derivatives".to_string()));
162    }
163
164    #[test]
165    fn test_context_factory_methods() {
166        let eq_context = OperationContext::equation_solving(5);
167        assert_eq!(eq_context.operation_type, "solving_equation");
168        assert_eq!(eq_context.domain, "algebra");
169        assert!(!eq_context.prerequisites.is_empty());
170
171        let diff_context = OperationContext::differentiation(7);
172        assert_eq!(diff_context.operation_type, "differentiation");
173        assert_eq!(diff_context.domain, "calculus");
174
175        let simp_context = OperationContext::simplification(3);
176        assert_eq!(simp_context.operation_type, "simplification");
177        assert_eq!(simp_context.domain, "algebra");
178    }
179
180    struct TestOperation {
181        value: i64,
182    }
183
184    impl EducationalOperation for TestOperation {
185        type Output = i64;
186
187        fn execute_with_steps(&self) -> (Self::Output, StepByStepExplanation) {
188            use crate::educational::step_by_step::Step;
189
190            let steps = vec![
191                Step::new("Initialize", "Starting with value"),
192                Step::new("Calculate", "Performing operation"),
193                Step::new("Result", "Final result obtained"),
194            ];
195
196            (self.value * 2, StepByStepExplanation::new(steps))
197        }
198
199        fn educational_context(&self) -> OperationContext {
200            OperationContext::new("test_operation", 3, "testing")
201        }
202
203        fn execute_fast(&self) -> Self::Output {
204            self.value * 2
205        }
206
207        fn estimated_steps(&self) -> Option<usize> {
208            Some(3)
209        }
210    }
211
212    #[test]
213    fn test_educational_operation_implementation() {
214        let operation = TestOperation { value: 21 };
215
216        let (result, explanation) = operation.execute_with_steps();
217        assert_eq!(result, 42);
218        assert_eq!(explanation.steps.len(), 3);
219        assert_eq!(explanation.total_steps, 3);
220
221        let fast_result = operation.execute_fast();
222        assert_eq!(fast_result, 42);
223
224        let context = operation.educational_context();
225        assert_eq!(context.operation_type, "test_operation");
226        assert_eq!(context.difficulty_level, 3);
227
228        assert!(operation.can_explain());
229        assert_eq!(operation.estimated_steps(), Some(3));
230    }
231}