mathhook_core/algebra/simplification/
logarithmic.rs1use super::strategy::SimplificationStrategy;
6use crate::core::commutativity::Commutativity;
7use crate::core::{Expression, Number};
8
9pub struct LogarithmSimplificationStrategy;
11
12impl SimplificationStrategy for LogarithmSimplificationStrategy {
13 fn simplify(&self, args: &[Expression]) -> Expression {
14 if args.len() == 1 {
15 match &args[0] {
16 Expression::Number(Number::Integer(n)) if *n == 1 => Expression::integer(0),
17
18 Expression::Number(Number::Integer(n)) if *n == 10 => Expression::integer(1),
19
20 Expression::Pow(base, exp) => Expression::mul(vec![
21 exp.as_ref().clone(),
22 Expression::function("log", vec![base.as_ref().clone()]),
23 ]),
24
25 Expression::Mul(factors) => {
26 let commutativity =
27 Commutativity::combine(factors.iter().map(|f| f.commutativity()));
28
29 if commutativity.can_sort() {
30 let log_terms: Vec<Expression> = factors
31 .iter()
32 .map(|f| Expression::function("log", vec![f.clone()]))
33 .collect();
34 Expression::add(log_terms)
35 } else {
36 Expression::function("log", args.to_vec())
37 }
38 }
39
40 _ => Expression::function("log", args.to_vec()),
41 }
42 } else if args.len() == 2 {
43 let x = &args[0];
44 let base = &args[1];
45
46 if x == base {
47 Expression::integer(1)
48 } else if x.is_one() {
49 Expression::integer(0)
50 } else {
51 Expression::function("log", args.to_vec())
52 }
53 } else {
54 Expression::function("log", args.to_vec())
55 }
56 }
57
58 fn applies_to(&self, args: &[Expression]) -> bool {
59 !args.is_empty() && args.len() <= 2
60 }
61
62 fn name(&self) -> &str {
63 "LogarithmSimplificationStrategy"
64 }
65}
66
67pub struct NaturalLogSimplificationStrategy;
69
70impl SimplificationStrategy for NaturalLogSimplificationStrategy {
71 fn simplify(&self, args: &[Expression]) -> Expression {
72 if args.len() == 1 {
73 match &args[0] {
74 Expression::Number(Number::Integer(n)) if *n == 1 => Expression::integer(0),
75
76 Expression::Function {
77 name,
78 args: inner_args,
79 } if name.as_ref() == "exp" && inner_args.len() == 1 => inner_args[0].clone(),
80
81 Expression::Pow(base, exp) => Expression::mul(vec![
82 exp.as_ref().clone(),
83 Expression::function("ln", vec![base.as_ref().clone()]),
84 ]),
85
86 _ => Expression::function("ln", args.to_vec()),
87 }
88 } else {
89 Expression::function("ln", args.to_vec())
90 }
91 }
92
93 fn applies_to(&self, args: &[Expression]) -> bool {
94 args.len() == 1
95 }
96
97 fn name(&self) -> &str {
98 "NaturalLogSimplificationStrategy"
99 }
100}
101
102#[cfg(test)]
103mod tests {
104 use super::*;
105 use crate::{expr, symbol};
106
107 #[test]
108 fn test_log_of_one() {
109 let strategy = LogarithmSimplificationStrategy;
110 let result = strategy.simplify(&[expr!(1)]);
111 assert_eq!(result, expr!(0));
112 }
113
114 #[test]
115 fn test_log_of_ten() {
116 let strategy = LogarithmSimplificationStrategy;
117 let result = strategy.simplify(&[expr!(10)]);
118 assert_eq!(result, expr!(1));
119 }
120
121 #[test]
122 fn test_log_power_rule() {
123 let strategy = LogarithmSimplificationStrategy;
124 let result = strategy.simplify(&[expr!(x ^ 2)]);
125
126 if let Expression::Mul(terms) = result {
127 assert_eq!(terms.len(), 2);
128 } else {
129 panic!("Expected multiplication");
130 }
131 }
132
133 #[test]
134 fn test_log_with_base() {
135 let strategy = LogarithmSimplificationStrategy;
136 let x = symbol!(x);
137 let result = strategy.simplify(&[x.clone().into(), x.into()]);
138 assert_eq!(result, expr!(1));
139 }
140
141 #[test]
142 fn test_ln_of_one() {
143 let strategy = NaturalLogSimplificationStrategy;
144 let result = strategy.simplify(&[expr!(1)]);
145 assert_eq!(result, expr!(0));
146 }
147
148 #[test]
149 fn test_ln_of_exp() {
150 let strategy = NaturalLogSimplificationStrategy;
151 let x = symbol!(x);
152 let exp_x = Expression::function("exp", vec![x.clone().into()]);
153 let result = strategy.simplify(&[exp_x]);
154 assert_eq!(result, x.into());
155 }
156
157 #[test]
158 fn test_ln_power_rule() {
159 let strategy = NaturalLogSimplificationStrategy;
160 let result = strategy.simplify(&[expr!(x ^ 3)]);
161
162 if let Expression::Mul(terms) = result {
163 assert_eq!(terms.len(), 2);
164 } else {
165 panic!("Expected multiplication");
166 }
167 }
168}