mathhook_core/algebra/
rational.rs

1//! Rational expression operations and simplification
2//! Handles rational functions, fraction simplification, and rational arithmetic
3//!
4//! # Noncommutative Simplification
5//!
6//! For noncommutative expressions (matrices, operators):
7//! - (AB)/(AC) can simplify to B/C only if A is left-invertible and cancellable
8//! - (BA)/(CA) can simplify to B/C only if A is right-invertible and cancellable
9//! - In general, simplification with noncommutative terms is NOT always valid
10//! - This implementation currently preserves order and does NOT auto-simplify noncommutative rationals
11
12use crate::core::{Expression, Number};
13use num_bigint::BigInt;
14use num_rational::BigRational;
15use num_traits::{One, Zero};
16
17/// Trait for rational expression operations
18pub trait RationalSimplify {
19    fn simplify_rational(&self) -> Self;
20    fn rationalize(&self) -> Self;
21    fn to_rational_form(&self) -> (Expression, Expression); // (numerator, denominator)
22}
23
24impl RationalSimplify for Expression {
25    /// Simplify rational expressions by canceling common factors
26    fn simplify_rational(&self) -> Self {
27        match self {
28            // Handle division represented as multiplication by inverse
29            Expression::Mul(factors) => self.simplify_rational_multiplication(factors),
30
31            // Handle fractions in other forms
32            Expression::Pow(base, exp) => {
33                // Check for negative exponents (which represent division)
34                if let Expression::Number(Number::Integer(n)) = exp.as_ref() {
35                    if *n < 0 {
36                        // x^(-n) = 1/x^n
37                        let positive_exp = Expression::integer(-n);
38                        let denominator = Expression::pow(base.as_ref().clone(), positive_exp);
39                        return self
40                            .create_rational_division(&Expression::integer(1), &denominator);
41                    }
42                }
43                self.clone()
44            }
45
46            _ => self.clone(),
47        }
48    }
49
50    /// Convert to rational form (numerator/denominator)
51    fn to_rational_form(&self) -> (Expression, Expression) {
52        match self {
53            Expression::Number(Number::Rational(r)) => (
54                Expression::big_integer(r.numer().clone()),
55                Expression::big_integer(r.denom().clone()),
56            ),
57
58            Expression::Mul(factors) => {
59                let (num_factors, den_factors) = self.separate_rational_factors(factors);
60
61                let numerator = if num_factors.is_empty() {
62                    Expression::integer(1)
63                } else {
64                    Expression::mul(num_factors)
65                };
66
67                let denominator = if den_factors.is_empty() {
68                    Expression::integer(1)
69                } else {
70                    Expression::mul(den_factors)
71                };
72
73                (numerator, denominator)
74            }
75
76            Expression::Pow(base, exp) => {
77                if let Expression::Number(Number::Integer(n)) = exp.as_ref() {
78                    if *n < 0 {
79                        // Negative exponent: move to denominator
80                        let positive_exp = Expression::integer(-n);
81                        let denominator = Expression::pow(base.as_ref().clone(), positive_exp);
82                        return (Expression::integer(1), denominator);
83                    }
84                }
85                (self.clone(), Expression::integer(1))
86            }
87
88            _ => (self.clone(), Expression::integer(1)),
89        }
90    }
91
92    /// Rationalize denominators (remove radicals from denominators)
93    fn rationalize(&self) -> Self {
94        // This is a complex operation - simplified implementation for now
95        self.clone()
96    }
97}
98
99impl Expression {
100    /// Simplify rational expressions in multiplication
101    fn simplify_rational_multiplication(&self, factors: &[Expression]) -> Expression {
102        let (numerator_factors, denominator_factors) = self.separate_rational_factors(factors);
103
104        // Simplify by canceling common factors
105
106        self.cancel_common_factors(&numerator_factors, &denominator_factors)
107    }
108
109    /// Separate factors into numerator and denominator parts
110    fn separate_rational_factors(
111        &self,
112        factors: &[Expression],
113    ) -> (Vec<Expression>, Vec<Expression>) {
114        let mut numerator_factors = Vec::new();
115        let mut denominator_factors = Vec::new();
116
117        for factor in factors {
118            match factor {
119                // Negative exponents go to denominator
120                Expression::Pow(base, exp) => {
121                    if let Expression::Number(Number::Integer(n)) = exp.as_ref() {
122                        if *n < 0 {
123                            let positive_exp = Expression::integer(-n);
124                            denominator_factors
125                                .push(Expression::pow(base.as_ref().clone(), positive_exp));
126                        } else {
127                            numerator_factors.push(factor.clone());
128                        }
129                    } else {
130                        numerator_factors.push(factor.clone());
131                    }
132                }
133
134                // Regular factors go to numerator
135                _ => {
136                    numerator_factors.push(factor.clone());
137                }
138            }
139        }
140
141        (numerator_factors, denominator_factors)
142    }
143
144    /// Cancel common factors between numerator and denominator
145    fn cancel_common_factors(
146        &self,
147        num_factors: &[Expression],
148        den_factors: &[Expression],
149    ) -> Expression {
150        if den_factors.is_empty() {
151            // No denominator, just return numerator
152            if num_factors.is_empty() {
153                return Expression::integer(1);
154            } else if num_factors.len() == 1 {
155                return num_factors[0].clone();
156            } else {
157                return Expression::mul(num_factors.to_vec());
158            }
159        }
160
161        let numerator = if num_factors.is_empty() {
162            Expression::integer(1)
163        } else {
164            Expression::mul(num_factors.to_vec())
165        };
166
167        let denominator = Expression::mul(den_factors.to_vec());
168
169        // Find GCD of numerator and denominator
170        let gcd = numerator.gcd(&denominator);
171
172        if !gcd.is_one() {
173            // Cancel common factor
174            let simplified_num = self.divide_expressions(&numerator, &gcd);
175            let simplified_den = self.divide_expressions(&denominator, &gcd);
176
177            self.create_rational_division(&simplified_num, &simplified_den)
178        } else {
179            self.create_rational_division(&numerator, &denominator)
180        }
181    }
182
183    /// Create a rational division expression
184    fn create_rational_division(
185        &self,
186        numerator: &Expression,
187        denominator: &Expression,
188    ) -> Expression {
189        if denominator.is_one() {
190            numerator.clone()
191        } else if numerator.is_zero() {
192            Expression::integer(0)
193        } else {
194            // Represent as multiplication by inverse (negative exponent)
195            Expression::mul(vec![
196                numerator.clone(),
197                Expression::pow(denominator.clone(), Expression::integer(-1)),
198            ])
199        }
200    }
201
202    /// Divide two expressions (simplified division)
203    fn divide_expressions(&self, dividend: &Expression, divisor: &Expression) -> Expression {
204        match (dividend, divisor) {
205            // Numeric division
206            (Expression::Number(Number::Integer(a)), Expression::Number(Number::Integer(b))) => {
207                if !b.is_zero() {
208                    let rational = BigRational::new(BigInt::from(*a), BigInt::from(*b));
209                    if rational.denom().is_one() {
210                        Expression::big_integer(rational.numer().clone())
211                    } else {
212                        Expression::number(Number::rational(rational))
213                    }
214                } else {
215                    dividend.clone() // Division by zero - return original
216                }
217            }
218
219            // Same expressions divide to 1
220            _ if dividend == divisor => Expression::integer(1),
221
222            // Multiplication division
223            (Expression::Mul(factors), _) => {
224                let mut remaining_factors = factors.clone();
225                if let Some(pos) = remaining_factors.iter().position(|f| f == divisor) {
226                    remaining_factors.remove(pos);
227                    if remaining_factors.is_empty() {
228                        Expression::integer(1)
229                    } else if remaining_factors.len() == 1 {
230                        remaining_factors[0].clone()
231                    } else {
232                        Expression::mul(remaining_factors.as_ref().clone())
233                    }
234                } else {
235                    dividend.clone()
236                }
237            }
238
239            // Default: return original
240            _ => dividend.clone(),
241        }
242    }
243
244    /// Add rational expressions: a/b + c/d = (ad + bc)/(bd)
245    pub fn add_rationals(&self, other: &Expression) -> Expression {
246        let (num1, den1) = self.to_rational_form();
247        let (num2, den2) = other.to_rational_form();
248
249        if den1 == den2 {
250            // Same denominator: just add numerators
251            let new_num = Expression::add(vec![num1, num2]);
252            self.create_rational_division(&new_num, &den1)
253        } else {
254            // Different denominators: find common denominator
255            let new_num = Expression::add(vec![
256                Expression::mul(vec![num1, den2.clone()]),
257                Expression::mul(vec![num2, den1.clone()]),
258            ]);
259            let new_den = Expression::mul(vec![den1, den2]);
260
261            self.create_rational_division(&new_num, &new_den)
262        }
263    }
264
265    /// Multiply rational expressions: (a/b) * (c/d) = (ac)/(bd)
266    pub fn multiply_rationals(&self, other: &Expression) -> Expression {
267        let (num1, den1) = self.to_rational_form();
268        let (num2, den2) = other.to_rational_form();
269
270        let new_num = Expression::mul(vec![num1, num2]);
271        let new_den = Expression::mul(vec![den1, den2]);
272
273        self.create_rational_division(&new_num, &new_den)
274    }
275
276    /// Simplify complex rational expressions
277    pub fn simplify_complex_rational(&self) -> Expression {
278        // Handle nested fractions and complex rational expressions
279        match self {
280            Expression::Mul(factors) => {
281                // Look for patterns like (a/b) * (c/d)
282                let mut rational_parts = Vec::new();
283                let mut other_parts = Vec::new();
284
285                for factor in factors.iter() {
286                    if self.is_rational_expression(factor) {
287                        rational_parts.push(factor.clone());
288                    } else {
289                        other_parts.push(factor.clone());
290                    }
291                }
292
293                if rational_parts.len() > 1 {
294                    // Multiply rational parts together
295                    let mut result = rational_parts[0].clone();
296                    for rational in &rational_parts[1..] {
297                        result = result.multiply_rationals(rational);
298                    }
299
300                    // Combine with other parts
301                    if !other_parts.is_empty() {
302                        other_parts.push(result);
303                        Expression::mul(other_parts)
304                    } else {
305                        result
306                    }
307                } else {
308                    self.clone()
309                }
310            }
311            _ => self.clone(),
312        }
313    }
314
315    /// Check if an expression is a rational expression
316    fn is_rational_expression(&self, expr: &Expression) -> bool {
317        match expr {
318            Expression::Number(Number::Rational(_)) => true,
319            Expression::Pow(_, exp) => {
320                // Negative exponents indicate rational expressions
321                if let Expression::Number(Number::Integer(n)) = exp.as_ref() {
322                    *n < 0
323                } else {
324                    false
325                }
326            }
327            _ => false,
328        }
329    }
330
331    /// Extract rational coefficient from expression
332    pub fn extract_rational_coefficient(&self) -> (BigRational, Expression) {
333        match self {
334            Expression::Number(Number::Rational(r)) => ((**r).clone(), Expression::integer(1)),
335            Expression::Number(Number::Integer(n)) => {
336                (BigRational::from(BigInt::from(*n)), Expression::integer(1))
337            }
338            Expression::Mul(factors) => {
339                let mut coefficient = BigRational::one();
340                let mut non_rational_factors = Vec::new();
341
342                for factor in factors.iter() {
343                    match factor {
344                        Expression::Number(Number::Rational(r)) => {
345                            coefficient *= r.as_ref();
346                        }
347                        Expression::Number(Number::Integer(n)) => {
348                            coefficient *= BigRational::from(BigInt::from(*n));
349                        }
350                        _ => {
351                            non_rational_factors.push(factor.clone());
352                        }
353                    }
354                }
355
356                let remaining = if non_rational_factors.is_empty() {
357                    Expression::integer(1)
358                } else if non_rational_factors.len() == 1 {
359                    non_rational_factors[0].clone()
360                } else {
361                    Expression::mul(non_rational_factors)
362                };
363
364                (coefficient, remaining)
365            }
366            _ => (BigRational::one(), self.clone()),
367        }
368    }
369}
370
371#[cfg(test)]
372mod tests {
373    use super::*;
374    use crate::symbol;
375
376    #[test]
377    fn test_rational_detection() {
378        // Test basic rational number
379        let rational = Expression::number(Number::rational(BigRational::new(
380            BigInt::from(3),
381            BigInt::from(4),
382        )));
383
384        let (num, den) = rational.to_rational_form();
385
386        assert_eq!(num, Expression::integer(3));
387        assert_eq!(den, Expression::integer(4));
388    }
389
390    #[test]
391    fn test_simple_rational_combination() {
392        // Test 1/2 + 1/3 = 5/6
393        let half = Expression::number(Number::rational(BigRational::new(
394            BigInt::from(1),
395            BigInt::from(2),
396        )));
397        let third = Expression::number(Number::rational(BigRational::new(
398            BigInt::from(1),
399            BigInt::from(3),
400        )));
401
402        let result = half.add_rationals(&third);
403        println!("1/2 + 1/3 = {}", result);
404
405        // Should be 5/6
406        assert!(!result.is_zero());
407    }
408
409    #[test]
410    fn test_rational_simplification() {
411        let x = symbol!(x);
412
413        // Test x^(-1) = 1/x
414        let expr = Expression::pow(Expression::symbol(x.clone()), Expression::integer(-1));
415        let result = expr.simplify_rational();
416
417        println!("x^(-1) simplified = {}", result);
418        assert!(!result.is_zero());
419    }
420
421    #[test]
422    fn test_rational_multiplication() {
423        // Test (2/3) * (3/4) = 6/12 = 1/2
424        let frac1 = Expression::number(Number::rational(BigRational::new(
425            BigInt::from(2),
426            BigInt::from(3),
427        )));
428        let frac2 = Expression::number(Number::rational(BigRational::new(
429            BigInt::from(3),
430            BigInt::from(4),
431        )));
432
433        let result = frac1.multiply_rationals(&frac2);
434        println!("(2/3) * (3/4) = {}", result);
435
436        assert!(!result.is_zero());
437    }
438
439    #[test]
440    fn test_common_factor_cancellation() {
441        let x = symbol!(x);
442
443        // Test (6x) / (9x) = 2/3 (if implemented)
444        let numerator =
445            Expression::mul(vec![Expression::integer(6), Expression::symbol(x.clone())]);
446        let denominator =
447            Expression::mul(vec![Expression::integer(9), Expression::symbol(x.clone())]);
448
449        let expr = Expression::integer(1).create_rational_division(&numerator, &denominator);
450        let result = expr.simplify_rational();
451
452        println!("(6x)/(9x) simplified = {}", result);
453        assert!(!result.is_zero());
454    }
455
456    #[test]
457    fn test_extract_rational_coefficient() {
458        let x = symbol!(x);
459
460        let expr = Expression::mul(vec![
461            Expression::number(Number::rational(BigRational::new(
462                BigInt::from(3),
463                BigInt::from(4),
464            ))),
465            Expression::symbol(x.clone()),
466        ]);
467
468        let (coeff, remaining) = expr.extract_rational_coefficient();
469
470        println!(
471            "Coefficient: {}, Remaining: {}",
472            Expression::number(Number::rational(coeff)),
473            remaining
474        );
475
476        assert_eq!(remaining, Expression::symbol(x));
477    }
478}