use num_traits::{Inv, One, Zero};
use std::ops::{Add, Div, Mul, Neg, Sub};
use crate::{polynomial::Poly, rational_function::Rf};
impl<T> Rf<T> {
pub fn inv_mut(&mut self) {
std::mem::swap(&mut self.num, &mut self.den);
}
}
impl<T: Clone> Inv for &Rf<T> {
type Output = Rf<T>;
fn inv(self) -> Self::Output {
Self::Output {
num: self.den.clone(),
den: self.num.clone(),
}
}
}
impl<T: Clone> Inv for Rf<T> {
type Output = Self;
fn inv(mut self) -> Self::Output {
self.inv_mut();
self
}
}
impl<T: Clone + Neg<Output = T>> Neg for &Rf<T> {
type Output = Rf<T>;
fn neg(self) -> Self::Output {
Self::Output {
num: -&self.num,
den: self.den.clone(),
}
}
}
impl<T: Clone + Neg<Output = T>> Neg for Rf<T> {
type Output = Self;
fn neg(mut self) -> Self::Output {
self.num = -self.num;
self
}
}
#[allow(clippy::suspicious_arithmetic_impl)]
impl<T: Clone + Mul<Output = T> + One + PartialEq + Zero> Add for &Rf<T> {
type Output = Rf<T>;
fn add(self, rhs: Self) -> Self::Output {
if self.is_zero() {
return rhs.clone();
}
if rhs.is_zero() {
return self.clone();
}
let (num, den) = if self.den == rhs.den {
(&self.num + &rhs.num, self.den.clone())
} else {
(
&self.num * &rhs.den + &self.den * &rhs.num,
&self.den * &rhs.den,
)
};
Self::Output::new(num, den)
}
}
#[allow(clippy::suspicious_arithmetic_impl)]
impl<T: Clone + One + PartialEq + Zero> Add for Rf<T> {
type Output = Self;
fn add(mut self, rhs: Self) -> Self {
if self.is_zero() {
return rhs;
}
if rhs.is_zero() {
return self;
}
if self.den == rhs.den {
self.num = self.num + rhs.num;
self
} else {
self.num = &self.num * &rhs.den + &self.den * &rhs.num;
self.den = self.den * rhs.den;
self
}
}
}
impl<T: Clone + Mul<Output = T> + PartialEq + Zero> Add<T> for Rf<T> {
type Output = Self;
fn add(mut self, rhs: T) -> Self {
self.num = self.num + &self.den * rhs;
self
}
}
impl<T: Clone + Mul<Output = T> + PartialEq + Zero> Add<&T> for Rf<T> {
type Output = Self;
fn add(mut self, rhs: &T) -> Self {
self.num = self.num + &self.den * rhs;
self
}
}
#[allow(clippy::suspicious_arithmetic_impl)]
impl<T: Clone + Neg<Output = T> + PartialEq + Sub<Output = T> + Zero + One> Sub for &Rf<T> {
type Output = Rf<T>;
fn sub(self, rhs: Self) -> Self::Output {
if self.is_zero() {
return -rhs.clone();
}
if rhs.is_zero() {
return self.clone();
}
let (num, den) = if self.den == rhs.den {
(&self.num - &rhs.num, self.den.clone())
} else {
(
&self.num * &rhs.den - &self.den * &rhs.num,
&self.den * &rhs.den,
)
};
Self::Output::new(num, den)
}
}
#[allow(clippy::suspicious_arithmetic_impl)]
impl<T: Clone + Neg<Output = T> + One + PartialEq + Sub<Output = T> + Zero> Sub for Rf<T> {
type Output = Self;
fn sub(mut self, rhs: Self) -> Self {
if self.is_zero() {
return -rhs;
}
if rhs.is_zero() {
return self;
}
if self.den == rhs.den {
self.num = self.num - rhs.num;
self
} else {
self.num = &self.num * &rhs.den - &self.den * &rhs.num;
self.den = self.den * rhs.den;
self
}
}
}
impl<T: Clone + One + PartialEq + Zero> Mul for &Rf<T> {
type Output = Rf<T>;
fn mul(self, rhs: Self) -> Self::Output {
if self.is_zero() || rhs.is_zero() {
return Self::Output::zero();
}
let num = &self.num * &rhs.num;
let den = &self.den * &rhs.den;
Self::Output::new(num, den)
}
}
impl<T: Clone + One + PartialEq + Zero> Mul for Rf<T> {
type Output = Self;
fn mul(mut self, rhs: Self) -> Self {
if self.is_zero() || rhs.is_zero() {
return Self::Output::zero();
}
self.num = self.num * rhs.num;
self.den = self.den * rhs.den;
self
}
}
impl<T: Clone + One + PartialEq + Zero> Mul<&Rf<T>> for Rf<T> {
type Output = Self;
fn mul(mut self, rhs: &Rf<T>) -> Self {
if self.is_zero() || rhs.is_zero() {
return Self::Output::zero();
}
self.num = self.num * &rhs.num;
self.den = self.den * &rhs.den;
self
}
}
#[allow(clippy::suspicious_arithmetic_impl)]
impl<T: Clone + One + PartialEq + Zero> Div for &Rf<T> {
type Output = Rf<T>;
fn div(self, rhs: Self) -> Self::Output {
match (self.is_zero(), rhs.is_zero()) {
(true, false) => return Self::Output::zero(),
(false, true) => return Self::Output::zero().inv(),
_ => (),
};
let num = &self.num * &rhs.den;
let den = &self.den * &rhs.num;
Self::Output::new(num, den)
}
}
#[allow(clippy::suspicious_arithmetic_impl)]
impl<T: Clone + One + PartialEq + Zero> Div for Rf<T> {
type Output = Self;
fn div(mut self, rhs: Self) -> Self {
match (self.is_zero(), rhs.is_zero()) {
(true, false) => return Self::Output::zero(),
(false, true) => return Self::Output::zero().inv(),
_ => (),
};
self.num = self.num * rhs.den;
self.den = self.den * rhs.num;
self
}
}
impl<T: Clone + One + PartialEq + Zero> Zero for Rf<T> {
fn zero() -> Self {
Self {
num: Poly::zero(),
den: Poly::one(),
}
}
fn is_zero(&self) -> bool {
self.num.is_zero() && !self.den.is_zero()
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::poly;
use num_traits::Float;
#[test]
fn rf_inversion() {
let num1 = poly!(1., 2., 3.);
let den1 = poly!(-4.2, -3.12, 0.0012);
let rf1 = Rf::new(num1, den1);
let num2 = poly!(-4.2, -3.12, 0.0012);
let den2 = poly!(1., 2., 3.);
let mut rf2 = Rf::new(num2, den2);
assert_eq!(rf2, (&rf1).inv());
rf2.inv_mut();
assert_eq!(rf2, rf1);
assert_eq!(rf2.inv(), rf1.inv());
}
#[test]
fn rf_neg() {
let rf1 = Rf::new(poly!(1., 2.), poly!(1., 5.));
let rf2 = Rf::new(poly!(-1., -2.), poly!(1., 5.));
assert_eq!(-&rf1, rf2);
assert_eq!(rf1, -(-(&rf1)));
}
#[test]
fn add_references() {
let rf1 = Rf::new(poly!(1., 2.), poly!(1., 5.));
let rf2 = Rf::new(poly!(3.), poly!(1., 5.));
let actual = &rf1 + &rf2;
let expected = Rf::new(poly!(4., 2.), poly!(1., 5.));
assert_eq!(expected, actual);
assert_eq!(expected, &expected + &Rf::zero());
assert_eq!(expected, &Rf::zero() + &expected);
}
#[test]
fn add_values() {
let rf1 = Rf::new(poly!(1., 2.), poly!(3., -4.));
let rf2 = Rf::new(poly!(3.), poly!(1., 5.));
let actual = rf1 + rf2;
let expected = Rf::new(poly!(10., -5., 10.), poly!(3., 11., -20.));
assert_eq!(expected, actual);
assert_eq!(expected, expected.clone() + Rf::zero());
assert_eq!(expected, Rf::<f32>::zero() + expected.clone());
}
#[test]
fn add_multiple_values() {
let rf1 = Rf::new(poly!(1., 2.), poly!(3., -4.));
let rf2 = Rf::new(poly!(3.), poly!(1., 5.));
let rf3 = Rf::new(poly!(0., 4.), poly!(3., 11., -20.));
let actual = &(&rf1 + &rf2) + &rf3;
let expected = Rf::new(poly!(10., -1., 10.), poly!(3., 11., -20.));
assert_eq!(expected, actual);
let actual2 = (rf1 + rf2) + rf3;
assert_eq!(actual, actual2);
}
#[test]
fn add_scalar_value() {
let rf = Rf::new(poly!(1., 2.), poly!(3., -4.));
let actual = rf + 1.;
let expected = Rf::new(poly!(4., -2.), poly!(3., -4.));
assert_eq!(expected, actual);
}
#[test]
#[allow(clippy::op_ref)]
fn add_scalar_reference() {
let rf = Rf::new(poly!(1., 2.), poly!(3., -4.));
let actual = rf + &2.;
let expected = Rf::new(poly!(7., -6.), poly!(3., -4.));
assert_eq!(expected, actual);
}
#[test]
fn sub_references() {
let rf1 = Rf::new(poly!(-1., 9.), poly!(4., -1.));
let rf2 = Rf::new(poly!(3.), poly!(4., -1.));
let actual = &rf1 - &rf2;
let expected = Rf::new(poly!(-4., 9.), poly!(4., -1.));
assert_eq!(expected, actual);
assert_eq!(expected, &expected - &Rf::zero());
assert_eq!(-&expected, &Rf::zero() - &expected);
}
#[test]
fn sub_values() {
let rf1 = Rf::new(poly!(1., -2.), poly!(4., -4.));
let rf2 = Rf::new(poly!(2.), poly!(2., 3.));
let actual = rf1 - rf2;
let expected = Rf::new(poly!(-6., 7., -6.), poly!(8., 4., -12.));
assert_eq!(expected, actual);
assert_eq!(expected, expected.clone() - Rf::zero());
assert_eq!(-&expected, Rf::zero() - expected);
}
#[test]
fn sub_multiple_values() {
let rf1 = Rf::new(poly!(1., -2.), poly!(4., -4.));
let rf2 = Rf::new(poly!(2.), poly!(2., 3.));
let rf3 = Rf::new(poly!(0., 2.), poly!(8., 4., -12.));
let actual = &(&rf1 - &rf2) - &rf3;
let expected = Rf::new(poly!(-6., 5., -6.), poly!(8., 4., -12.));
assert_eq!(expected, actual);
let actual2 = (rf1 - rf2) - rf3;
assert_eq!(actual, actual2);
}
#[test]
fn mul_references() {
let rf1 = Rf::new(poly!(1., 2., 3.), poly!(1., 5.));
let rf2 = Rf::new(poly!(3.), poly!(1., 6., 5.));
let actual = &rf1 * &rf2;
let expected = Rf::new(poly!(3., 6., 9.), poly!(1., 11., 35., 25.));
assert_eq!(expected, actual);
assert_eq!(Rf::zero(), &expected * &Rf::zero());
assert_eq!(Rf::zero(), &Rf::zero() * &expected);
}
#[test]
fn mul_values() {
let rf1 = Rf::new(poly!(1., 2., 3.), poly!(1., 5.));
let rf2 = Rf::new(poly!(-5.), poly!(1., 6., 5.));
let actual = rf1 * rf2;
let expected = Rf::new(poly!(-5., -10., -15.), poly!(1., 11., 35., 25.));
assert_eq!(expected, actual);
assert_eq!(Rf::zero(), expected.clone() * Rf::zero());
assert_eq!(Rf::zero(), Rf::zero() * expected);
}
#[test]
fn mul_value_reference() {
let rf1 = Rf::new(poly!(1., 2., 3.), poly!(1., 5.));
let rf2 = Rf::new(poly!(-5.), poly!(1., 6., 5.));
let actual = rf1 * &rf2;
let expected = Rf::new(poly!(-5., -10., -15.), poly!(1., 11., 35., 25.));
assert_eq!(expected, actual);
assert_eq!(Rf::zero(), expected.clone() * &Rf::zero());
assert_eq!(Rf::zero(), Rf::zero() * &expected);
}
#[test]
fn div_values() {
let rf1 = Rf::new(poly!(1., 2., 3.), poly!(1., 5.));
let rf2 = Rf::new(poly!(3.), poly!(1., 6., 5.));
let actual = rf2 / rf1;
let expected = Rf::new(poly!(3., 15.), poly!(1., 8., 20., 28., 15.));
assert_eq!(expected, actual);
assert_eq!(Rf::zero(), &Rf::zero() / &expected);
assert!((&expected / &Rf::zero()).eval(&1.).is_infinite());
assert!((&Rf::<f32>::zero() / &Rf::zero()).eval(&1.).is_nan());
}
#[test]
#[allow(clippy::eq_op)]
fn div_references() {
let rf1 = Rf::new(poly!(1., 2., 3.), poly!(1., 5.));
let actual = &rf1 / &rf1;
let expected = Rf::new(poly!(1., 7., 13., 15.), poly!(1., 7., 13., 15.));
assert_eq!(expected, actual);
assert_eq!(Rf::zero(), Rf::zero() / expected.clone());
assert!((expected / Rf::zero()).eval(&1.).is_infinite());
assert!((Rf::<f32>::zero() / Rf::zero()).eval(&1.).is_nan());
}
#[test]
fn zero_rf() {
assert!(Rf::<f32>::zero().is_zero());
assert!(!Rf::new(poly!(0.), poly!(0.)).is_zero());
}
}