use std::{ops::{Add, Sub, SubAssign, AddAssign, Neg}, fmt::Display, fmt::Debug, convert::TryInto, convert::TryFrom};
use crate::math::general::NumTools;
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct Polynomial<const C: usize, T> {
coefficients: [T; C],
solutions: Option<[Option<T>; C]>
}
impl<const C: usize, T: From<u8> +
Copy +
std::ops::Sub<Output = T> +
std::ops::Add<Output = T> +
std::ops::Div<Output = T> +
std::ops::Mul<Output = T> +
std::ops::Div +
std::ops::Mul +
std::ops::SubAssign +
std::ops::AddAssign +
std::ops::MulAssign +
std::cmp::PartialOrd +
std::ops::Sub +
std::ops::Add +
std::fmt::Display> Polynomial<C, T> {
pub fn new() -> Polynomial<C, T> {
Polynomial {
coefficients: [1u8.into(); C],
solutions: None
}
}
pub fn new_from_coefficients(coefficients: [T; C]) -> Polynomial<C, T> {
Polynomial {
coefficients,
solutions: None
}
}
pub fn get_coefficients(&self) -> [T; C] {
self.coefficients
}
pub fn get_degree(&self) -> usize {
self.coefficients.len() - 1
}
pub fn eval(&self, x: T) -> T {
let mut result: T = 0u8.into();
let mut exponent: usize = self.get_degree();
for coefficient in self.coefficients {
result.inc_by(coefficient * x.pow(exponent));
if exponent > 0
{ exponent.dec(); }
}
result
}
pub fn get_solutions(&mut self) -> Option<[Option<T>; C]>
where
f64: From<T> + TryInto<T>,
T: Neg<Output = T> + TryFrom<f64>,
<f64 as std::convert::TryInto<T>>::Error: Debug,
<T as std::convert::TryFrom<f64>>::Error: Debug {
if self.solutions.is_some()
{ return self.solutions; }
let mut res = [None; C];
if self.get_degree() == 2 {
let discriminant = self.coefficients[1].square() -
T::from(4) * self.coefficients[0] * self.coefficients[2];
if discriminant.is_negative()
{ return None; }
let x_1 = (- self.coefficients[1] +
(f64::from(discriminant).sqrt()).try_into().unwrap()) /
(T::from(2) * self.coefficients[0]);
let x_2 = (- self.coefficients[1] -
(f64::from(discriminant).sqrt()).try_into().unwrap()) /
(T::from(2) * self.coefficients[0]);
match x_1 == x_2 {
true => { res[0] = Some(x_1); self.solutions = Some(res); }
false => { res[0] = Some(x_1); res[1] = Some(x_2);
self.solutions = Some(res) }
}
return self.solutions.clone();
}
if self.get_degree() == 1 {
res[0] = Some(- self.coefficients[1] / self.coefficients[0]);
return self.solutions;
}
None
}
}
impl<const C: usize, T: std::ops::AddAssign + Copy> Add for Polynomial<C, T> {
type Output = Polynomial<C, T>;
fn add(self, rhs: Self) -> Self::Output {
Polynomial {
coefficients: {
let mut res_coeff = self.coefficients;
for (index, i) in rhs.coefficients.iter().enumerate() {
res_coeff[index] += *i;
}
res_coeff
},
solutions: None
}
}
}
impl<const C: usize, T: std::ops::SubAssign +
Copy +
PartialEq +
From<u8>> Sub for Polynomial<C, T> {
type Output = Polynomial<C, T>;
fn sub(self, rhs: Self) -> Self::Output {
let mut res_coeff = self.coefficients;
for (index, i) in rhs.coefficients.iter().enumerate() {
res_coeff[index] -= *i;
}
let mut _deg = C;
for i in res_coeff {
if i == 0u8.into() {
_deg.dec();
continue;
}
break;
}
Polynomial {
coefficients: res_coeff,
solutions: None
}
}
}
impl<const C: usize, T: Copy +
Clone +
PartialEq +
Sub<Output = T> +
SubAssign +
From<u8>> SubAssign for Polynomial<C, T> {
fn sub_assign(&mut self, rhs: Self) {
*self = *self - rhs;
}
}
impl<const C: usize, T: Copy +
Clone +
PartialEq +
Add<Output = T> +
AddAssign +
From<u8>> AddAssign for Polynomial<C, T> {
fn add_assign(&mut self, rhs: Self) {
*self = *self + rhs;
}
}
impl<const C: usize, T: Display +
PartialOrd +
From<u8> +
Copy> std::fmt::Display for Polynomial<C, T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let mut res = String::with_capacity(C * 4);
let mut current_exponent: usize;
for (exp, coeff) in self.coefficients.iter().enumerate() {
current_exponent = self.coefficients.len() - exp - 1;
if current_exponent == 0
{ break; }
if coeff < &0u8.into()
{ res.push_str(&format!(" - {}x", &coeff.to_string()[1..coeff.to_string().len()])); }
else
{ res.push_str(&format!(" + {}x", coeff)); }
if current_exponent != 1
{ res.push_str(&format!("^{}", current_exponent)); }
}
if self.coefficients[self.coefficients.len() - 1] < 0u8.into()
{ res.push_str(
&format!(" - {}",
&self.coefficients[self.coefficients.len() - 1]
.to_string()
[1..self.coefficients
[self.coefficients.len() - 1]
.to_string()
.len()
]
)
);
}
else
{ res.push_str(&format!(" + {}", self.coefficients[self.coefficients.len() - 1])); }
write!(f, "{}", &res[3..res.len()])
}
}