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            _ => SolverResult::NoSolution,
157        }
158    }
159
160    /// Solve a system of equations
161    ///
162    /// # Examples
163    ///
164    /// ```rust
165    /// use mathhook_core::{MathSolver, Expression};
166    /// use mathhook_core::{symbol, expr};
167    ///
168    /// let mut solver = MathSolver::new();
169    /// let equations = vec![
170    ///     Expression::equation(expr!(x), expr!(1)),
171    ///     Expression::equation(expr!(y), expr!(2)),
172    /// ];
173    /// let variables = vec![symbol!(x), symbol!(y)];
174    /// let result = solver.solve_system(&equations, &variables);
175    /// ```
176    pub fn solve_system(
177        &mut self,
178        equations: &[Expression],
179        variables: &[Symbol],
180    ) -> Vec<SolverResult> {
181        // Basic implementation - solve each equation independently
182        equations
183            .iter()
184            .map(|eq| self.solve(eq, &variables[0])) // Simplified for now
185            .collect()
186    }
187
188    /// Update solver configuration
189    ///
190    /// # Examples
191    ///
192    /// ```rust
193    /// use mathhook_core::{MathSolver, SolverConfig};
194    ///
195    /// let mut solver = MathSolver::new();
196    /// let new_config = SolverConfig {
197    ///     max_iterations: 2000,
198    ///     ..Default::default()
199    /// };
200    /// solver.configure(new_config);
201    /// ```
202    pub fn configure(&mut self, config: SolverConfig) {
203        self.config = config;
204    }
205
206    // Private helper methods
207    fn convert_solver_result(
208        &self,
209        algebra_result: crate::algebra::solvers::SolverResult,
210    ) -> SolverResult {
211        match algebra_result {
212            crate::algebra::solvers::SolverResult::Single(expr) => SolverResult::Single(expr),
213            crate::algebra::solvers::SolverResult::Multiple(exprs) => SolverResult::Multiple(exprs),
214            crate::algebra::solvers::SolverResult::NoSolution => SolverResult::NoSolution,
215            crate::algebra::solvers::SolverResult::InfiniteSolutions => {
216                SolverResult::InfiniteSolutions
217            }
218            crate::algebra::solvers::SolverResult::Parametric(exprs) => {
219                // Parametric solutions are returned as multiple solutions for simplicity
220                SolverResult::Multiple(exprs)
221            }
222            crate::algebra::solvers::SolverResult::Partial(exprs) => {
223                // Partial solutions are returned as multiple solutions
224                SolverResult::Multiple(exprs)
225            }
226        }
227    }
228}
229
230impl Default for MathSolver {
231    fn default() -> Self {
232        Self::new()
233    }
234}