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}