use nalgebra::RealField;
use num_complex::Complex;
use num_traits::{Float, One, Zero};
use std::{
fmt,
fmt::{Debug, Display, Formatter},
ops::{Add, Div, Mul},
};
use crate::polynomial::Poly;
mod arithmetic;
#[derive(Clone, Debug, PartialEq)]
pub struct Rf<T> {
num: Poly<T>,
den: Poly<T>,
}
impl<T> Rf<T> {
#[must_use]
pub fn new(num: Poly<T>, den: Poly<T>) -> Self {
Self { num, den }
}
#[must_use]
pub fn num(&self) -> &Poly<T> {
&self.num
}
#[must_use]
pub fn den(&self) -> &Poly<T> {
&self.den
}
}
impl<T: Clone + PartialEq + Zero> Rf<T> {
#[must_use]
#[allow(clippy::cast_possible_wrap, clippy::cast_possible_truncation)]
pub fn relative_degree(&self) -> i32 {
match (self.den.degree(), self.num.degree()) {
(Some(d), Some(n)) => d as i32 - n as i32,
(Some(d), None) => d as i32,
(None, Some(n)) => -(n as i32),
_ => 0,
}
}
}
impl<T: Float + RealField> Rf<T> {
#[must_use]
pub fn real_poles(&self) -> Option<Vec<T>> {
self.den.real_roots()
}
#[must_use]
pub fn complex_poles(&self) -> Vec<Complex<T>> {
self.den.complex_roots()
}
#[must_use]
pub fn real_zeros(&self) -> Option<Vec<T>> {
self.num.real_roots()
}
#[must_use]
pub fn complex_zeros(&self) -> Vec<Complex<T>> {
self.num.complex_roots()
}
}
impl<T: Clone + Div<Output = T> + One + PartialEq + Zero> Rf<T> {
#[must_use]
pub fn normalize(&self) -> Self {
if self.den.is_zero() {
return self.clone();
}
let (den, an) = self.den.monic();
let num = &self.num / an;
Self { num, den }
}
pub fn normalize_mut(&mut self) {
if self.den.is_zero() {
return;
}
let an = self.den.monic_mut();
self.num.div_mut(&an);
}
}
impl<T: Clone> Rf<T> {
pub fn eval_by_val<N>(&self, s: N) -> N
where
N: Add<T, Output = N> + Clone + Div<Output = N> + Mul<Output = N> + Zero,
{
self.num.eval_by_val(s.clone()) / self.den.eval_by_val(s)
}
}
impl<T> Rf<T> {
pub fn eval<'a, N>(&'a self, s: &'a N) -> N
where
T: 'a,
N: 'a + Add<&'a T, Output = N> + Div<Output = N> + Mul<&'a N, Output = N> + Zero,
{
self.num.eval(s) / self.den.eval(s)
}
}
impl<T> Display for Rf<T>
where
T: Display + One + PartialEq + PartialOrd + Zero,
{
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
let (s_num, s_den) = if let Some(precision) = f.precision() {
let num = format!("{poly:.prec$}", poly = self.num, prec = precision);
let den = format!("{poly:.prec$}", poly = self.den, prec = precision);
(num, den)
} else {
let num = format!("{}", self.num);
let den = format!("{}", self.den);
(num, den)
};
let length = s_num.len().max(s_den.len());
let dash = "\u{2500}".repeat(length);
write!(f, "{}\n{}\n{}", s_num, dash, s_den)
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::poly;
use num_complex::Complex;
use num_traits::Inv;
#[test]
fn rational_function_creation() {
let num = poly!(1., 2., 3.);
let den = poly!(-4.2, -3.12, 0.0012);
let rf = Rf::new(num.clone(), den.clone());
assert_eq!(&num, rf.num());
assert_eq!(&den, rf.den());
}
#[test]
fn relative_degree() {
let rf = Rf::new(poly!(1., 2.), poly!(-4., 6., -2.));
let expected = rf.relative_degree();
assert_eq!(expected, 1);
assert_eq!(rf.inv().relative_degree(), -1);
assert_eq!(-1, Rf::new(poly!(1., 1.), Poly::zero()).relative_degree());
assert_eq!(1, Rf::new(Poly::zero(), poly!(1., 1.)).relative_degree());
assert_eq!(
0,
Rf::<f32>::new(Poly::zero(), Poly::zero()).relative_degree()
);
}
#[test]
fn evaluation() {
let rf = Rf::new(poly!(-0.75, 0.25), poly!(0.75, 0.75, 1.));
let res = rf.eval(&Complex::new(0., 0.9));
assert_abs_diff_eq!(0.429, res.re, epsilon = 0.001);
assert_abs_diff_eq!(1.073, res.im, epsilon = 0.001);
}
#[test]
fn evaluation_by_value() {
let rf = Rf::new(poly!(-0.75, 0.25), poly!(0.75, 0.75, 1.));
let res1 = rf.eval(&Complex::new(0., 0.9));
let res2 = rf.eval_by_val(Complex::new(0., 0.9));
assert_eq!(res1, res2);
}
#[test]
fn poles() {
let rf = Rf::new(poly!(1.), poly!(6., -5., 1.));
assert_eq!(Some(vec![2., 3.]), rf.real_poles());
}
#[test]
fn complex_poles() {
use num_complex::Complex32;
let rf = Rf::new(poly!(1.), poly!(10., -6., 1.));
assert_eq!(
vec![Complex32::new(3., -1.), Complex32::new(3., 1.)],
rf.complex_poles()
);
}
#[test]
fn zeros() {
let rf = Rf::new(poly!(1.), poly!(6., -5., 1.));
assert_eq!(None, rf.real_zeros());
}
#[test]
fn complex_zeros() {
use num_complex::Complex32;
let rf = Rf::new(poly!(3.25, 3., 1.), poly!(10., -3., 1.));
assert_eq!(
vec![Complex32::new(-1.5, -1.), Complex32::new(-1.5, 1.)],
rf.complex_zeros()
);
}
#[test]
fn print() {
let rf = Rf::new(Poly::<f64>::one(), Poly::new_from_roots(&[-1.]));
assert_eq!(
"1\n\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\n1 +1s",
format!("{}", rf)
);
let rf2 = Rf::new(poly!(1.123), poly!(0.987, -1.321));
assert_eq!(
"1.12\n\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\n0.99 -1.32s",
format!("{:.2}", rf2)
);
}
#[test]
fn normalization() {
let rf = Rf::new(poly!(1., 2.), poly!(-4., 6., -2.));
let expected = Rf::new(poly!(-0.5, -1.), poly!(2., -3., 1.));
assert_eq!(expected, rf.normalize());
let rf2 = Rf::new(poly!(1.), poly!(0.));
assert_eq!(rf2, rf2.normalize());
}
#[test]
fn normalization_mutable() {
let mut rf = Rf::new(poly!(1., 2.), poly!(-4., 6., -2.));
rf.normalize_mut();
let expected = Rf::new(poly!(-0.5, -1.), poly!(2., -3., 1.));
assert_eq!(expected, rf);
let mut rf2 = Rf::new(poly!(1.), poly!(0.));
let rf3 = rf2.clone();
rf2.normalize_mut();
assert_eq!(rf2, rf3);
}
#[test]
fn eval_trasfer_function() {
let s_num = Poly::new_from_coeffs(&[-1., 1.]);
let s_den = Poly::new_from_coeffs(&[0., 1.]);
let s = Rf::<f64>::new(s_num, s_den);
let p = Poly::new_from_coeffs(&[1., 2., 3.]);
let r = p.eval(&s);
let expected = Rf::<f64>::new(poly!(3., -8., 6.), poly!(0., 0., 1.));
assert_eq!(expected, r);
}
}