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///
26/// @no-binding - internal configuration, use Expression::solve() API
27#[derive(Debug, Clone)]
28pub struct SolverConfig {
29    pub max_iterations: u32,
30    pub tolerance: f64,
31    pub use_numeric: bool,
32    pub simplify_results: bool,
33}
34
35impl Default for SolverConfig {
36    fn default() -> Self {
37        Self {
38            max_iterations: 1000,
39            tolerance: 1e-10,
40            use_numeric: false,
41            simplify_results: true,
42        }
43    }
44}
45
46/// Stateful mathematical solver for the hybrid API
47///
48/// This is a separate object from Expression that maintains configuration
49/// and state for complex solving operations.
50///
51/// @no-binding - use Expression::solve() or Expression::solve_with_steps() instead
52///
53/// # Examples
54///
55/// ```rust
56/// use mathhook_core::{MathSolver, Expression, symbol, expr};
57/// use mathhook_core::simplify::Simplify;
58///
59/// let solver = MathSolver::new();
60/// let x = symbol!(x);
61/// let equation = Expression::equation(
62///     expr!((2*x) + 3),
63///     expr!(7),
64/// );
65///
66/// let result = solver.solve(&equation, &x);
67/// // Result: SolverResult::Single for x = 2
68/// ```
69pub struct MathSolver {
70    config: SolverConfig,
71    smart_solver: SmartEquationSolver,
72}
73
74impl MathSolver {
75    /// Create a new solver with default configuration
76    ///
77    /// # Examples
78    ///
79    /// ```rust
80    /// use mathhook_core::MathSolver;
81    ///
82    /// let solver = MathSolver::new();
83    /// ```
84    pub fn new() -> Self {
85        Self {
86            config: SolverConfig::default(),
87            smart_solver: SmartEquationSolver::new(),
88        }
89    }
90
91    /// Create a new solver with custom configuration
92    ///
93    /// # Examples
94    ///
95    /// ```rust
96    /// use mathhook_core::{MathSolver, SolverConfig};
97    ///
98    /// let config = SolverConfig {
99    ///     max_iterations: 500,
100    ///     tolerance: 1e-8,
101    ///     use_numeric: true,
102    ///     simplify_results: false,
103    /// };
104    /// let solver = MathSolver::with_config(config);
105    /// ```
106    pub fn with_config(config: SolverConfig) -> Self {
107        Self {
108            config,
109            smart_solver: SmartEquationSolver::new(),
110        }
111    }
112
113    /// Solve an equation for a given variable
114    ///
115    /// # Examples
116    ///
117    /// ```rust
118    /// use mathhook_core::{MathSolver, Expression};
119    /// use mathhook_core::{symbol, expr};
120    /// let solver = MathSolver::new();
121    /// let equation = Expression::equation(
122    ///     expr!(x),
123    ///     expr!(5),
124    /// );
125    /// let result = solver.solve(&equation, &symbol!(x));
126    /// ```
127    pub fn solve(&self, equation: &Expression, variable: &Symbol) -> SolverResult {
128        match equation {
129            Expression::Relation(relation_data) => {
130                let left = &relation_data.left;
131                let right = &relation_data.right;
132
133                let standard_form = Expression::add(vec![
134                    left.clone(),
135                    Expression::mul(vec![Expression::integer(-1), right.clone()]),
136                ]);
137
138                let (algebra_result, _explanation) = self
139                    .smart_solver
140                    .solve_with_equation(&standard_form, variable);
141
142                let result = self.convert_solver_result(algebra_result);
143
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            _ => {
157                let (algebra_result, _explanation) =
158                    self.smart_solver.solve_with_equation(equation, variable);
159
160                let result = self.convert_solver_result(algebra_result);
161
162                if self.config.simplify_results {
163                    match result {
164                        SolverResult::Single(expr) => SolverResult::Single(expr.simplify()),
165                        SolverResult::Multiple(exprs) => {
166                            SolverResult::Multiple(exprs.iter().map(|e| e.simplify()).collect())
167                        }
168                        other => other,
169                    }
170                } else {
171                    result
172                }
173            }
174        }
175    }
176
177    /// Solve a system of equations
178    ///
179    /// # Examples
180    ///
181    /// ```rust
182    /// use mathhook_core::{MathSolver, Expression};
183    /// use mathhook_core::{symbol, expr};
184    ///
185    /// let solver = MathSolver::new();
186    /// let equations = vec![
187    ///     Expression::equation(expr!(x), expr!(1)),
188    ///     Expression::equation(expr!(y), expr!(2)),
189    /// ];
190    /// let variables = vec![symbol!(x), symbol!(y)];
191    /// let result = solver.solve_system(&equations, &variables);
192    /// ```
193    pub fn solve_system(
194        &self,
195        equations: &[Expression],
196        variables: &[Symbol],
197    ) -> Vec<SolverResult> {
198        equations
199            .iter()
200            .map(|eq| self.solve(eq, &variables[0]))
201            .collect()
202    }
203
204    /// Update solver configuration
205    ///
206    /// # Examples
207    ///
208    /// ```rust
209    /// use mathhook_core::{MathSolver, SolverConfig};
210    ///
211    /// let mut solver = MathSolver::new();
212    /// let new_config = SolverConfig {
213    ///     max_iterations: 2000,
214    ///     ..Default::default()
215    /// };
216    /// solver.configure(new_config);
217    /// ```
218    pub fn configure(&mut self, config: SolverConfig) {
219        self.config = config;
220    }
221
222    fn convert_solver_result(
223        &self,
224        algebra_result: crate::algebra::solvers::SolverResult,
225    ) -> SolverResult {
226        match algebra_result {
227            crate::algebra::solvers::SolverResult::Single(expr) => SolverResult::Single(expr),
228            crate::algebra::solvers::SolverResult::Multiple(exprs) => SolverResult::Multiple(exprs),
229            crate::algebra::solvers::SolverResult::NoSolution => SolverResult::NoSolution,
230            crate::algebra::solvers::SolverResult::InfiniteSolutions => {
231                SolverResult::InfiniteSolutions
232            }
233            crate::algebra::solvers::SolverResult::Parametric(exprs) => {
234                SolverResult::Multiple(exprs)
235            }
236            crate::algebra::solvers::SolverResult::Partial(exprs) => SolverResult::Multiple(exprs),
237        }
238    }
239}
240
241impl Default for MathSolver {
242    fn default() -> Self {
243        Self::new()
244    }
245}