#![feature(map_try_insert)]
pub mod engineer;
pub mod polynomials {
use num::{Num, Signed, Float, Zero};
use std::{
collections::BTreeMap,
fmt::Display,
ops::{Add, AddAssign, Div, Mul, Sub, DivAssign},
};
#[derive(Debug, Clone, PartialEq)]
pub struct Polynomial<T: Num>(Vec<PolynomialTerm<T>>);
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct PolynomialTerm<T: Num> {
pub power: u32,
pub coefficient: T,
}
impl<T: Num + Copy + PartialOrd> Polynomial<T> {
fn combine_like_terms(&mut self) {
let mut term_map = BTreeMap::new();
for term in self.0.iter() {
if term.coefficient.is_zero() {
continue;
}
if let Err(occupied) = term_map.try_insert(term.power, term.coefficient) {
*occupied.entry.into_mut() = occupied.value + *occupied.entry.get();
}
}
self.0.clear();
for pair in term_map {
self.0.push(PolynomialTerm {
power: pair.0,
coefficient: pair.1,
});
}
self.0.sort_by(|a, b| b.power.cmp(&a.power));
}
pub fn get_terms(&mut self) -> Vec<PolynomialTerm<T>> {
self.combine_like_terms();
self.0.clone()
}
}
impl<T: Num + Copy + PartialOrd> Polynomial<T> {
pub fn push_term(&mut self, term: PolynomialTerm<T>) {
self.0.push(term);
self.0.sort_by(|a, b| b.power.cmp(&a.power));
self.combine_like_terms();
}
}
impl<T: Num> Polynomial<T> {
pub fn get_degree(&self) -> u32 {
for term in &self.0 {
if term.coefficient != T::zero() {
return term.power;
}
}
0
}
}
impl<T: Num + Copy + PartialOrd> Polynomial<T> {
pub fn new_from_term_vec(terms: Vec<PolynomialTerm<T>>) -> Self {
let mut new = Polynomial(Vec::new());
for term in terms {
new.push_term(term);
}
new
}
}
impl<T: Num + Copy + PartialOrd> Polynomial<T>{
pub fn new_from_num_vec(terms: Vec<T>) -> Self {
if terms.is_empty(){
return Self(vec![])
}
let degree = terms.len() - 1;
let mut polynomial_terms: Vec<PolynomialTerm<T>> = Vec::new();
for (i, term) in terms.iter().enumerate() {
polynomial_terms.push(PolynomialTerm {
power: (degree - i) as u32,
coefficient: *term,
});
}
let mut poly = Self(polynomial_terms);
poly.combine_like_terms();
poly
}
}
impl<T: Num + Copy + PartialOrd + Display + Signed + DivAssign+Float> Polynomial<T> {
pub fn new_from_points(points: Vec<(T, T)>) -> Self {
let mut poly = Polynomial::new_from_num_vec(vec![]);
for point in &points {
let mut delta = Polynomial::new_from_num_vec(vec![point.1]);
for other_point in &points {
if other_point.0 == point.0 {
continue;
}
delta = delta
* (Polynomial::new_from_term_vec(vec![PolynomialTerm{coefficient:T::one(),power:1},PolynomialTerm{coefficient:-other_point.0,power:0}])
/ (point.0 - other_point.0));
}
poly = poly + delta.clone();
}
poly
}
}
impl<T: Num + Copy + PartialOrd + num::pow::Pow<u32, Output = T> + AddAssign> Polynomial<T> {
pub fn evaluate(&mut self, x: T) -> T {
let mut answer = T::zero();
for term in self.get_terms() {
answer += term.coefficient * x.pow(term.power);
}
answer
}
}
impl<T:Num+Copy+PartialOrd+AddAssign> Zero for Polynomial<T>{
fn zero() -> Self {
Polynomial::new_from_num_vec(vec![])
}
fn is_zero(&self) -> bool {
let mut total=T::zero();
for term in &self.0{
total+=term.coefficient;
}
total.is_zero()
}
}
impl<T:Num+Copy+PartialOrd> num::One for Polynomial<T>{
fn one() -> Self {
Polynomial::new_from_num_vec(vec![T::one()])
}
}
impl<T: Num + Signed + Display> Display for Polynomial<T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let mut formatted_equation = String::new();
let mut actual_i=0;
for term in self.0.iter() {
if term.coefficient.is_zero() {
continue;
}
if actual_i != 0 && term.coefficient.is_positive() {
formatted_equation += "+"
}
if !term.coefficient.is_one() || term.power == 0 {
formatted_equation += &term.coefficient.to_string();
}
if term.power != 0 {
formatted_equation += "x";
if term.power != 1 {
formatted_equation += &format!("^{}", term.power);
}
}
actual_i+=1;
}
write!(f, "{}", formatted_equation)
}
}
impl<T: Num + Copy + PartialOrd> Mul<Polynomial<T>> for Polynomial<T> {
type Output = Polynomial<T>;
fn mul(self, rhs: Polynomial<T>) -> Self::Output {
let mut out = Polynomial::new_from_term_vec(Vec::new());
for lht in self.0 {
for rht in rhs.0.iter() {
out.push_term(lht * (*rht));
}
}
out
}
}
impl<T: Num> Mul<PolynomialTerm<T>> for PolynomialTerm<T> {
type Output = PolynomialTerm<T>;
fn mul(self, rhs: PolynomialTerm<T>) -> Self::Output {
PolynomialTerm {
power: self.power + rhs.power,
coefficient: self.coefficient * rhs.coefficient,
}
}
}
impl<T: Num + Copy> Mul<PolynomialTerm<T>> for Polynomial<T> {
type Output = Polynomial<T>;
fn mul(self, rhs: PolynomialTerm<T>) -> Self::Output {
let out = self.clone().0.iter().map(|x| *x * rhs).collect();
Polynomial(out)
}
}
impl<T: Num + Copy> Mul<T> for Polynomial<T> {
type Output = Polynomial<T>;
fn mul(self, rhs: T) -> Self::Output {
self * PolynomialTerm {
coefficient: rhs,
power: 0,
}
}
}
impl<T: Num + Copy + PartialOrd> Add for Polynomial<T> {
type Output = Polynomial<T>;
fn add(self, rhs: Self) -> Self::Output {
let mut cloned = self.clone();
cloned.0.extend(rhs.0);
cloned.combine_like_terms();
cloned
}
}
impl<T: Num + Copy + Signed + PartialOrd> Sub for Polynomial<T> {
type Output = Polynomial<T>;
fn sub(self, rhs: Self) -> Self::Output {
let mut cloned = rhs.clone();
for term in cloned.0.iter_mut() {
term.coefficient = -term.coefficient
}
self + cloned
}
}
pub struct DivOutput<T: Num> {
pub remainder: Polynomial<T>,
pub output: Polynomial<T>,
}
impl<T: Num> Div for PolynomialTerm<T> {
type Output = PolynomialTerm<T>;
fn div(self, rhs: Self) -> Self::Output {
Self {
power: self.power - rhs.power,
coefficient: self.coefficient / rhs.coefficient,
}
}
}
impl<T: Num + Copy> Div<PolynomialTerm<T>> for Polynomial<T> {
type Output = Polynomial<T>;
fn div(self, rhs: PolynomialTerm<T>) -> Self::Output {
let mut out = self;
for term in out.0.iter_mut() {
*term = *term / rhs;
}
out
}
}
impl<T: Num + Copy + PartialOrd> num::pow::Pow<i32> for Polynomial<T> {
type Output = Polynomial<T>;
fn pow(self, rhs: i32) -> Self::Output {
let mut poly = Polynomial::new_from_num_vec(vec![T::one()]);
for _ in 0..rhs {
poly = poly * self.clone();
}
todo!()
}
}
impl<T: Num + Display + Copy + PartialOrd + Signed> Display for PolynomialTerm<T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let poly = Polynomial::new_from_term_vec(vec![*self]);
write!(f, "{}", poly)
}
}
impl<T: Num + Copy + PartialOrd + Signed> Div<Polynomial<T>> for Polynomial<T> {
type Output = DivOutput<T>;
fn div(self, rhs: Self) -> Self::Output {
if rhs.0.is_empty(){
panic!("cannot divide by empty polynomial");
}
let binding = rhs.clone();
let first_divisor_term = binding.0.get(0).unwrap();
let mut answer = Polynomial::new_from_term_vec(Vec::new());
let mut remainder = self;
while remainder.get_degree() >= rhs.get_degree() {
let factor = *remainder.0.get(0).unwrap() / *first_divisor_term;
remainder = remainder.clone() - (rhs.clone() * factor);
answer.push_term(factor);
}
remainder.combine_like_terms();
answer.combine_like_terms();
DivOutput {
remainder,
output: answer,
}
}
}
impl<T: Num + Copy + DivAssign> Div<T> for Polynomial<T> {
type Output = Polynomial<T>;
fn div(mut self, rhs: T) -> Self::Output {
if rhs.is_zero(){
panic!("cannot divide polynomial by zero");
}
for term in self.0.iter_mut() {
term.coefficient /= rhs
}
self
}
}
}
#[cfg(test)]
mod tests {
use super::polynomials::*;
#[test]
fn polynomial_div() {
let poly1 = Polynomial::new_from_num_vec(vec![1, 5, 6]);
let poly2 = Polynomial::new_from_num_vec(vec![5, 6, 9, 6]);
let combined = poly1.clone() * poly2.clone();
let divided = combined / poly1;
assert_eq!(divided.output, poly2);
}
#[test]
fn polynomial_div_with_remainder() {
let dividend = Polynomial::new_from_num_vec(vec![1., -12., 38., -17.]);
let divisor = Polynomial::new_from_num_vec(vec![3., 18., 14.]);
assert_eq!(
(dividend / divisor).remainder,
Polynomial::new_from_num_vec(vec![424. / 3., 67.])
)
}
#[test]
fn polynomial_mul() {
let poly1 = Polynomial::new_from_num_vec(vec![1, 5, 6]);
let poly2 = Polynomial::new_from_num_vec(vec![5, 6, 9, 6]);
assert_eq!(
poly1 * poly2,
Polynomial::new_from_num_vec(vec![5, 31, 69, 87, 84, 36])
);
}
#[test]
fn poly_from_points() {
let poly: Polynomial<f32> = Polynomial::new_from_num_vec(vec![5., 6., 9., 6.]);
let points: Vec<(f32, f32)> = vec![
(9.0, 4218.0),
(3.0,222.0),
(4.0,458.0),
(7.0, 2078.0),
];
let new_poly = Polynomial::new_from_points(points);
assert_eq!(new_poly,poly)
}
}