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}