mathhook_core/algebra/simplification/
registry.rs1use super::elementary::{
7 AbsSimplificationStrategy, ExpSimplificationStrategy, SqrtSimplificationStrategy,
8};
9use super::logarithmic::{LogarithmSimplificationStrategy, NaturalLogSimplificationStrategy};
10use super::special::{FactorialSimplificationStrategy, GammaSimplificationStrategy};
11use super::strategy::SimplificationStrategy;
12use super::trigonometric::{
13 CosSimplificationStrategy, GenericTrigSimplificationStrategy, SinSimplificationStrategy,
14 TanSimplificationStrategy,
15};
16use crate::core::Expression;
17use once_cell::sync::Lazy;
18use std::collections::HashMap;
19
20pub static SIMPLIFICATION_REGISTRY: Lazy<SimplificationRegistry> =
25 Lazy::new(SimplificationRegistry::new);
26
27pub struct SimplificationRegistry {
32 strategies: HashMap<String, Box<dyn SimplificationStrategy>>,
34}
35
36impl Default for SimplificationRegistry {
37 fn default() -> Self {
38 Self::new()
39 }
40}
41
42impl SimplificationRegistry {
43 pub fn new() -> Self {
47 let mut registry = Self {
48 strategies: HashMap::with_capacity(32),
49 };
50
51 registry.initialize_logarithmic_strategies();
52 registry.initialize_trigonometric_strategies();
53 registry.initialize_elementary_strategies();
54 registry.initialize_special_strategies();
55
56 registry
57 }
58
59 pub fn register(&mut self, name: &str, strategy: Box<dyn SimplificationStrategy>) {
66 self.strategies.insert(name.to_owned(), strategy);
67 }
68
69 #[inline(always)]
79 pub fn get_strategy(&self, name: &str) -> Option<&dyn SimplificationStrategy> {
80 self.strategies.get(name).map(|s| &**s)
81 }
82
83 pub fn simplify_function(&self, name: &str, args: &[Expression]) -> Expression {
104 if let Some(strategy) = self.get_strategy(name) {
105 if strategy.applies_to(args) {
106 strategy.simplify(args)
107 } else {
108 Expression::function(name, args.to_vec())
109 }
110 } else {
111 Expression::function(name, args.to_vec())
112 }
113 }
114
115 #[inline(always)]
117 pub fn has_strategy(&self, name: &str) -> bool {
118 self.strategies.contains_key(name)
119 }
120
121 pub fn strategy_count(&self) -> usize {
123 self.strategies.len()
124 }
125
126 pub fn list_functions(&self) -> Vec<String> {
128 self.strategies.keys().cloned().collect()
129 }
130
131 fn initialize_logarithmic_strategies(&mut self) {
132 self.register("log", Box::new(LogarithmSimplificationStrategy));
133 self.register("ln", Box::new(NaturalLogSimplificationStrategy));
134 }
135
136 fn initialize_trigonometric_strategies(&mut self) {
137 self.register("sin", Box::new(SinSimplificationStrategy));
138 self.register("cos", Box::new(CosSimplificationStrategy));
139 self.register("tan", Box::new(TanSimplificationStrategy));
140
141 self.register(
142 "csc",
143 Box::new(GenericTrigSimplificationStrategy::new("csc")),
144 );
145 self.register(
146 "sec",
147 Box::new(GenericTrigSimplificationStrategy::new("sec")),
148 );
149 self.register(
150 "cot",
151 Box::new(GenericTrigSimplificationStrategy::new("cot")),
152 );
153
154 self.register(
155 "asin",
156 Box::new(GenericTrigSimplificationStrategy::new("asin")),
157 );
158 self.register(
159 "acos",
160 Box::new(GenericTrigSimplificationStrategy::new("acos")),
161 );
162 self.register(
163 "atan",
164 Box::new(GenericTrigSimplificationStrategy::new("atan")),
165 );
166
167 self.register(
168 "sinh",
169 Box::new(GenericTrigSimplificationStrategy::new("sinh")),
170 );
171 self.register(
172 "cosh",
173 Box::new(GenericTrigSimplificationStrategy::new("cosh")),
174 );
175 self.register(
176 "tanh",
177 Box::new(GenericTrigSimplificationStrategy::new("tanh")),
178 );
179 }
180
181 fn initialize_elementary_strategies(&mut self) {
182 self.register("sqrt", Box::new(SqrtSimplificationStrategy));
183 self.register("abs", Box::new(AbsSimplificationStrategy));
184 self.register("exp", Box::new(ExpSimplificationStrategy));
185 }
186
187 fn initialize_special_strategies(&mut self) {
188 self.register("gamma", Box::new(GammaSimplificationStrategy));
189 self.register("factorial", Box::new(FactorialSimplificationStrategy));
190 }
191}
192
193#[inline(always)]
197pub fn get_simplification_registry() -> &'static SimplificationRegistry {
198 &SIMPLIFICATION_REGISTRY
199}
200
201#[cfg(test)]
202mod tests {
203 use super::*;
204
205 #[test]
206 fn test_registry_initialization() {
207 let registry = SimplificationRegistry::new();
208
209 assert_eq!(registry.strategy_count(), 19);
211
212 assert!(registry.strategies.capacity() >= 32);
214 }
215
216 #[test]
217 fn test_registry_has_strategies() {
218 let registry = SimplificationRegistry::new();
219
220 assert!(registry.has_strategy("log"));
221 assert!(registry.has_strategy("ln"));
222 assert!(registry.has_strategy("sin"));
223 assert!(registry.has_strategy("cos"));
224 assert!(registry.has_strategy("tan"));
225 assert!(registry.has_strategy("sqrt"));
226 assert!(registry.has_strategy("abs"));
227 assert!(registry.has_strategy("exp"));
228 assert!(registry.has_strategy("gamma"));
229 assert!(registry.has_strategy("factorial"));
230 }
231
232 #[test]
233 fn test_global_registry_access() {
234 let _registry = get_simplification_registry();
235
236 let result = SIMPLIFICATION_REGISTRY.simplify_function("unknown", &[]);
237
238 assert!(matches!(result, Expression::Function { .. }));
239 }
240
241 #[test]
242 fn test_simplify_log_of_one() {
243 use crate::expr;
244
245 let result = SIMPLIFICATION_REGISTRY.simplify_function("log", &[expr!(1)]);
246 assert_eq!(result, expr!(0));
247 }
248
249 #[test]
250 fn test_simplify_ln_of_one() {
251 use crate::expr;
252
253 let result = SIMPLIFICATION_REGISTRY.simplify_function("ln", &[expr!(1)]);
254 assert_eq!(result, expr!(0));
255 }
256
257 #[test]
258 fn test_simplify_sin_of_zero() {
259 use crate::expr;
260
261 let result = SIMPLIFICATION_REGISTRY.simplify_function("sin", &[expr!(0)]);
262 assert_eq!(result, expr!(0));
263 }
264
265 #[test]
266 fn test_simplify_cos_of_zero() {
267 use crate::expr;
268
269 let result = SIMPLIFICATION_REGISTRY.simplify_function("cos", &[expr!(0)]);
270 assert_eq!(result, expr!(1));
271 }
272
273 #[test]
274 fn test_simplify_factorial_of_zero() {
275 use crate::expr;
276
277 let result = SIMPLIFICATION_REGISTRY.simplify_function("factorial", &[expr!(0)]);
278 assert_eq!(result, expr!(1));
279 }
280
281 #[test]
282 fn test_simplify_factorial_of_five() {
283 use crate::expr;
284
285 let result = SIMPLIFICATION_REGISTRY.simplify_function("factorial", &[expr!(5)]);
286 assert_eq!(result, expr!(120));
287 }
288}