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}