mathhook_core/
solvers.rs

1//! Solver objects for the hybrid API
2//!
3//! This module provides stateful solver objects that complement the Expression-centric API.
4//! These are separate objects that maintain state and configuration for complex solving operations.
5
6use crate::algebra::equation_analyzer::SmartEquationSolver;
7use crate::core::{Expression, Symbol};
8use crate::simplify::Simplify;
9use serde::{Deserialize, Serialize};
10
11/// Result of a solving operation
12#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
13pub enum SolverResult {
14    /// Single solution found
15    Single(Expression),
16    /// Multiple solutions found
17    Multiple(Vec<Expression>),
18    /// No solution exists
19    NoSolution,
20    /// Infinite solutions exist
21    InfiniteSolutions,
22}
23
24/// Configuration for solving operations
25#[derive(Debug, Clone)]
26pub struct SolverConfig {
27    pub max_iterations: u32,
28    pub tolerance: f64,
29    pub use_numeric: bool,
30    pub simplify_results: bool,
31}
32
33impl Default for SolverConfig {
34    fn default() -> Self {
35        Self {
36            max_iterations: 1000,
37            tolerance: 1e-10,
38            use_numeric: false,
39            simplify_results: true,
40        }
41    }
42}
43
44/// Stateful mathematical solver for the hybrid API
45///
46/// This is a separate object from Expression that maintains configuration
47/// and state for complex solving operations.
48///
49/// # Examples
50///
51/// ```rust
52/// use mathhook_core::{MathSolver, Expression, symbol, expr};
53/// use mathhook_core::simplify::Simplify;
54///
55/// let mut solver = MathSolver::new();
56/// let x = symbol!(x);
57/// let equation = Expression::equation(
58///     expr!((2*x) + 3),
59///     expr!(7),
60/// );
61///
62/// let result = solver.solve(&equation, &x);
63/// // Result: SolverResult::Single for x = 2
64/// ```
65pub struct MathSolver {
66    config: SolverConfig,
67    smart_solver: SmartEquationSolver,
68}
69
70impl MathSolver {
71    /// Create a new solver with default configuration
72    ///
73    /// # Examples
74    ///
75    /// ```rust
76    /// use mathhook_core::MathSolver;
77    ///
78    /// let solver = MathSolver::new();
79    /// ```
80    pub fn new() -> Self {
81        Self {
82            config: SolverConfig::default(),
83            smart_solver: SmartEquationSolver::new(),
84        }
85    }
86
87    /// Create a new solver with custom configuration
88    ///
89    /// # Examples
90    ///
91    /// ```rust
92    /// use mathhook_core::{MathSolver, SolverConfig};
93    ///
94    /// let config = SolverConfig {
95    ///     max_iterations: 500,
96    ///     tolerance: 1e-8,
97    ///     use_numeric: true,
98    ///     simplify_results: false,
99    /// };
100    /// let solver = MathSolver::with_config(config);
101    /// ```
102    pub fn with_config(config: SolverConfig) -> Self {
103        Self {
104            config,
105            smart_solver: SmartEquationSolver::new(),
106        }
107    }
108
109    /// Solve an equation for a given variable
110    ///
111    /// # Examples
112    ///
113    /// ```rust
114    /// use mathhook_core::{MathSolver, Expression};
115    /// use mathhook_core::{symbol, expr};
116    /// let mut solver = MathSolver::new();
117    /// let equation = Expression::equation(
118    ///     expr!(x),
119    ///     expr!(5),
120    /// );
121    /// let result = solver.solve(&equation, &symbol!(x));
122    /// ```
123    pub fn solve(&mut self, equation: &Expression, variable: &Symbol) -> SolverResult {
124        match equation {
125            Expression::Relation(relation_data) => {
126                // Extract left and right sides and convert to standard form (LHS - RHS = 0)
127                let left = &relation_data.left;
128                let right = &relation_data.right;
129
130                let standard_form = Expression::add(vec![
131                    left.clone(),
132                    Expression::mul(vec![Expression::integer(-1), right.clone()]),
133                ]);
134
135                // Use the SmartEquationSolver to solve
136                let (algebra_result, _explanation) = self
137                    .smart_solver
138                    .solve_with_equation(&standard_form, variable);
139
140                // Convert algebra::solvers::SolverResult to solvers::SolverResult
141                let result = self.convert_solver_result(algebra_result);
142
143                // Apply simplification if configured
144                if self.config.simplify_results {
145                    match result {
146                        SolverResult::Single(expr) => SolverResult::Single(expr.simplify()),
147                        SolverResult::Multiple(exprs) => {
148                            SolverResult::Multiple(exprs.iter().map(|e| e.simplify()).collect())
149                        }
150                        other => other,
151                    }
152                } else {
153                    result
154                }
155            }
156            // If not a relation, treat expression as "expression = 0"
157            _ => {
158                let (algebra_result, _explanation) =
159                    self.smart_solver.solve_with_equation(equation, variable);
160
161                let result = self.convert_solver_result(algebra_result);
162
163                if self.config.simplify_results {
164                    match result {
165                        SolverResult::Single(expr) => SolverResult::Single(expr.simplify()),
166                        SolverResult::Multiple(exprs) => {
167                            SolverResult::Multiple(exprs.iter().map(|e| e.simplify()).collect())
168                        }
169                        other => other,
170                    }
171                } else {
172                    result
173                }
174            }
175        }
176    }
177
178    /// Solve a system of equations
179    ///
180    /// # Examples
181    ///
182    /// ```rust
183    /// use mathhook_core::{MathSolver, Expression};
184    /// use mathhook_core::{symbol, expr};
185    ///
186    /// let mut solver = MathSolver::new();
187    /// let equations = vec![
188    ///     Expression::equation(expr!(x), expr!(1)),
189    ///     Expression::equation(expr!(y), expr!(2)),
190    /// ];
191    /// let variables = vec![symbol!(x), symbol!(y)];
192    /// let result = solver.solve_system(&equations, &variables);
193    /// ```
194    pub fn solve_system(
195        &mut self,
196        equations: &[Expression],
197        variables: &[Symbol],
198    ) -> Vec<SolverResult> {
199        // Basic implementation - solve each equation independently
200        equations
201            .iter()
202            .map(|eq| self.solve(eq, &variables[0])) // Simplified for now
203            .collect()
204    }
205
206    /// Update solver configuration
207    ///
208    /// # Examples
209    ///
210    /// ```rust
211    /// use mathhook_core::{MathSolver, SolverConfig};
212    ///
213    /// let mut solver = MathSolver::new();
214    /// let new_config = SolverConfig {
215    ///     max_iterations: 2000,
216    ///     ..Default::default()
217    /// };
218    /// solver.configure(new_config);
219    /// ```
220    pub fn configure(&mut self, config: SolverConfig) {
221        self.config = config;
222    }
223
224    // Private helper methods
225    fn convert_solver_result(
226        &self,
227        algebra_result: crate::algebra::solvers::SolverResult,
228    ) -> SolverResult {
229        match algebra_result {
230            crate::algebra::solvers::SolverResult::Single(expr) => SolverResult::Single(expr),
231            crate::algebra::solvers::SolverResult::Multiple(exprs) => SolverResult::Multiple(exprs),
232            crate::algebra::solvers::SolverResult::NoSolution => SolverResult::NoSolution,
233            crate::algebra::solvers::SolverResult::InfiniteSolutions => {
234                SolverResult::InfiniteSolutions
235            }
236            crate::algebra::solvers::SolverResult::Parametric(exprs) => {
237                // Parametric solutions are returned as multiple solutions for simplicity
238                SolverResult::Multiple(exprs)
239            }
240            crate::algebra::solvers::SolverResult::Partial(exprs) => {
241                // Partial solutions are returned as multiple solutions
242                SolverResult::Multiple(exprs)
243            }
244        }
245    }
246}
247
248impl Default for MathSolver {
249    fn default() -> Self {
250        Self::new()
251    }
252}