use std::rc::Rc;
use crate::{
argument::Argument,
derivation_rules::helpers::is_one,
expressions::{
product::product_of, sum::sum_of, Exponent, Expression, Fraction, Integer, Negation,
},
};
use super::DerivationRule;
pub struct DivideFractions {}
impl DerivationRule for DivideFractions {
fn apply(&self, input: Expression) -> Vec<(Expression, Rc<Argument>)> {
let fraction = match input {
Expression::Fraction(ref f) => f,
_ => return vec![],
};
let mut numerator: Vec<Expression> = match fraction.numerator() {
Expression::Product(p) => p.factors().clone(),
exp => vec![exp],
};
let mut denominator: Vec<Expression> = match fraction.denominator() {
Expression::Product(p) => p.factors().clone(),
exp => vec![exp],
};
fn contains_base(list: &Vec<Expression>, exp: &Expression) -> bool {
for e in list {
match e {
Expression::Exponent(e) => {
if e.base() == *exp {
return true;
}
}
e => {
if *e == *exp {
return true;
}
}
}
}
false
}
fn base_of(exp: &Expression) -> Expression {
match exp {
Expression::Exponent(e) => e.base(),
_ => exp.clone(),
}
}
for elem in &mut numerator {
let base = base_of(elem);
if !contains_base(&denominator, &base) {
continue;
}
let top_power = match elem {
Expression::Exponent(e) => e.power(),
_ => Integer::of(1),
};
let bottom_match = denominator
.iter_mut()
.find(|exp| base_of(exp) == base)
.unwrap();
let bottom_power = match bottom_match {
Expression::Exponent(e) => e.power(),
_ => Integer::of(1),
};
*elem = Exponent::of(base, sum_of(&[top_power, Negation::of(bottom_power)]));
*bottom_match = Integer::of(1);
}
let result = if is_one(&product_of(&denominator)) {
product_of(&numerator)
} else {
Fraction::of(product_of(&numerator), product_of(&denominator))
};
if result == input {
return vec![];
}
vec![(
result,
Argument::new(String::from("Divided fraction"), vec![input], self.name()),
)]
}
fn name(&self) -> String {
String::from("DivideFractions")
}
}