1use std::{
2 default::Default,
3 fmt::{Debug, Display, Error},
4 i64,
5 iter::Sum,
6 num::IntErrorKind,
7 ops::{Add, Div, Mul, Neg},
8 str::FromStr,
9};
10
11use num::{Num, NumCast, Signed};
12
13pub trait MonomialValue:
15 Num + NumCast + Signed + Copy + Default + Debug + Display + FromStr + PartialOrd
16{
17}
18
19impl<T> MonomialValue for T where
20 T: Num + NumCast + Signed + Copy + Default + Debug + Display + FromStr + PartialOrd
21{
22}
23
24#[derive(Default, Debug, PartialEq, PartialOrd, Clone, Copy)]
26pub struct Monomial<T> {
27 pub(crate) value: T,
28 pub(crate) exp: i32,
29}
30
31impl<T: MonomialValue> Monomial<T> {
32 pub fn new(value: T, mut exp: i32) -> Monomial<T> {
35 if T::is_zero(&value) {
36 exp = 0;
37 }
38
39 Monomial { value, exp }
40 }
41
42 pub fn get_value(&self) -> T {
43 self.value
44 }
45
46 pub fn get_exp(&self) -> i32 {
47 self.exp
48 }
49
50 pub fn is_operable(&self, other: &Self) -> bool {
52 self.exp == other.exp
53 }
54}
55
56impl<T: MonomialValue> TryFrom<&str> for Monomial<T> {
62 type Error = &'static str;
63
64 fn try_from(value: &str) -> Result<Self, Self::Error> {
65 let clean_value = value
66 .trim()
67 .to_lowercase()
68 .replace(" ", "")
69 .replace("^", "")
70 .replace("+", "");
71
72 let mut split: Vec<&str> = clean_value.split("x").collect();
73
74 if split.is_empty() {
75 return Ok(Monomial::default());
76 }
77
78 if "-" == split[0] {
79 split[0] = "-1";
80 }
81
82 let base = match split[0].parse::<T>() {
83 Ok(v) => v,
84 Err(_) if split[0].is_empty() => T::one(),
85 Err(_) => return Err("Not valid base"),
86 };
87
88 let exp = match split.len() {
89 1 => 0,
90 2 => match split[1].parse::<i32>() {
91 Ok(v) => v,
92 Err(err) if err.kind() == &IntErrorKind::Empty => 1,
93 Err(_) => return Err("Not valid exponent"),
94 },
95 _ => return Err("To much symbols"),
96 };
97
98 Ok(Monomial { value: base, exp })
99 }
100}
101
102impl<T: MonomialValue> Neg for Monomial<T> {
103 type Output = Self;
104
105 fn neg(self) -> Self::Output {
106 Monomial::new(-self.value, self.exp)
107 }
108}
109
110impl<T: MonomialValue> Add for Monomial<T> {
111 type Output = Result<Self, &'static str>;
112
113 fn add(self, rhs: Self) -> Self::Output {
114 if !self.is_operable(&rhs) {
115 return Err("Monomials only allow add same exponent");
116 }
117
118 Ok(Monomial::new(self.value + rhs.value, self.exp))
119 }
120}
121
122impl<T: MonomialValue> Mul for Monomial<T> {
123 type Output = Self;
124
125 fn mul(self, rhs: Self) -> Self::Output {
126 Monomial::new(self.value * rhs.value, self.exp + rhs.exp)
127 }
128}
129
130impl<T: MonomialValue> Div for Monomial<T> {
131 type Output = Self;
132
133 fn div(self, rhs: Self) -> Self::Output {
134 Monomial::new(self.value / rhs.value, self.exp - rhs.exp)
135 }
136}
137
138impl<T: MonomialValue> Sum<Self> for Monomial<T> {
139 fn sum<I: Iterator<Item = Self>>(iter: I) -> Self {
140 let mut exp = 0;
141 let mut sum = T::zero();
142 for mono in iter {
143 exp = mono.get_exp();
144 sum = sum + mono.get_value();
145 }
146
147 Monomial::new(sum, exp)
148 }
149}
150
151impl<T: MonomialValue> Display for Monomial<T> {
157 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
158 let val: i64 = T::to_i64(&self.value).ok_or(Error)?;
159 let base: String = match val {
160 -1 if self.exp == 0 => "-1".to_string(),
161 -1 => "-".to_string(),
162 1 if self.exp == 0 => "1".to_string(),
163 1 => "".to_string(),
164 _ => format!("{}", self.value),
165 };
166
167 let exp: String = match self.exp {
168 0 => "".to_string(),
169 1 => "x".to_string(),
170 _ => format!("x^{}", self.exp),
171 };
172
173 write!(f, "{}{}", base, exp)
174 }
175}