use crate::approx::approximate_rational;
use crate::primitive::int;
use crate::symbolic::expr::{SymExpr, Primary};
use rug::Integer;
pub(crate) fn make_fraction(numerator: SymExpr, denominator: SymExpr) -> SymExpr {
numerator *
SymExpr::Exp(
Box::new(denominator),
Box::new(SymExpr::Primary(Primary::Integer(int(-1)))),
)
}
pub(crate) fn extract_integer_fraction(
factors: &mut Vec<SymExpr>,
numerator_optional: bool,
denominator_optional: bool,
) -> Option<(Integer, Integer)> {
let mut idx = 0;
let mut numerator = None;
let mut denominator = None;
while idx < factors.len() {
if numerator.is_none() && factors[idx].is_integer() {
numerator = Some(factors.swap_remove(idx).into_integer().unwrap());
continue;
}
if denominator.is_none() && factors[idx].is_integer_recip() {
denominator = Some(factors.swap_remove(idx).into_integer_recip().unwrap());
continue;
}
if numerator.is_some() && denominator.is_some() {
break;
}
idx += 1;
}
match (numerator, denominator) {
(Some(numerator), Some(denominator)) => Some((numerator, denominator)),
(Some(numerator), None) if denominator_optional => Some((numerator, int(1))),
(None, Some(denominator)) if numerator_optional => Some((int(1), denominator)),
(None, None) if numerator_optional && denominator_optional => Some((int(1), int(1))),
_ => None,
}
}
pub(crate) fn extract_fractional(factors: &mut Vec<SymExpr>) -> Option<SymExpr> {
let mut idx = 0;
let mut numerator_idx = None;
let mut denominator_idx = None;
while idx < factors.len() {
if factors[idx].is_float() {
return Some(factors.swap_remove(idx));
}
if numerator_idx.is_none() && factors[idx].is_integer() {
numerator_idx = Some(idx);
continue;
}
if denominator_idx.is_none() && factors[idx].is_integer_recip() {
denominator_idx = Some(idx);
continue;
}
if numerator_idx.is_some() && denominator_idx.is_some() {
break;
}
idx += 1;
}
match (numerator_idx, denominator_idx) {
(Some(numerator_idx), Some(denominator_idx)) => {
if numerator_idx > denominator_idx {
Some(factors.swap_remove(numerator_idx)
* factors.swap_remove(denominator_idx))
} else {
Some(factors.swap_remove(denominator_idx)
* factors.swap_remove(numerator_idx))
}
},
(Some(numerator_idx), None) => Some(factors.swap_remove(numerator_idx)),
(None, Some(denominator_idx)) => Some(factors.swap_remove(denominator_idx)),
(None, None) => None,
}
}
pub(crate) fn extract_explicit_frac(expr: &mut SymExpr) -> Option<(Integer, Integer)> {
match expr {
SymExpr::Primary(Primary::Integer(num)) => {
Some((std::mem::replace(num, int(1)), int(1)))
},
SymExpr::Primary(Primary::Float(num)) => {
let rational = approximate_rational(num);
*expr = SymExpr::Primary(Primary::Integer(int(1)));
Some(rational.into_numer_denom())
},
SymExpr::Mul(factors) => extract_integer_fraction(factors, false, true),
SymExpr::Exp(..) => {
if expr.is_integer_recip() {
let denominator = std::mem::replace(expr, SymExpr::Primary(Primary::Integer(int(1))))
.into_integer_recip()
.unwrap();
Some((int(1), denominator))
} else {
None
}
},
_ => None,
}
}