1use std::fmt::{Display, Debug};
8use std::ops::{AddAssign, Mul, MulAssign, DivAssign, SubAssign, Div};
9use std::str::FromStr;
10use num_traits::{Zero, One, ToPrimitive, Pow, FromPrimitive};
11use auto_impl_ops::auto_ops;
12
13use crate::abst::{MathType, IndexType};
14use crate::lc::LcKey;
15use crate::util::format::superscript;
16use crate::util::parse_err::ParseErr;
17use super::{Mono, MonoOrd};
18
19#[derive(Clone, Copy, PartialEq, Eq, Hash, Default, PartialOrd, Ord)]
22#[cfg_attr(feature = "serde", derive(serde_with::DeserializeFromStr))]
23pub struct Var<const X: char, I>(
24 I
25);
26
27impl<const X: char, I> Var<X, I> {
28 pub fn var_symbol() -> char {
29 X
30 }
31
32 pub fn eval<R>(&self, x: &R) -> R
33 where R: Mul<Output = R>, I: Copy, for<'x> &'x R: Pow<I, Output = R> {
34 x.pow(self.0)
35 }
36
37 fn to_string_u(&self, unicode: bool) -> String
38 where I: ToPrimitive {
39 fmt_mono(&X.to_string(), &self.0, unicode)
40 }
41}
42
43impl<const X: char, I> FromStr for Var<X, I>
44where I: Zero + FromStr + FromPrimitive {
45 type Err = ParseErr;
46 fn from_str(s: &str) -> Result<Self, Self::Err> {
47 if s == "1" {
48 Ok(Self(I::zero()))
49 } else if let Some(d) = parse_mono_deg(&X.to_string(), s) {
50 Ok(Self(d))
51 } else {
52 Err(ParseErr::invalid(s, &format!("a monomial in {X}")))
53 }
54 }
55}
56
57impl<const X: char, I> From<I> for Var<X, I> {
58 fn from(d: I) -> Self {
59 Self(d)
60 }
61}
62
63impl<const X: char, I> One for Var<X, I>
64where I: for<'x >AddAssign<&'x I> + Zero {
65 fn one() -> Self {
66 Self::from(I::zero()) }
68}
69
70#[auto_ops]
73impl<const X: char, I> MulAssign<&Var<X, I>> for Var<X, I>
74where I: for<'x >AddAssign<&'x I> {
75 fn mul_assign(&mut self, rhs: &Var<X, I>) {
76 self.0 += &rhs.0 }
78}
79
80#[auto_ops]
81impl<const X: char, I> DivAssign<&Var<X, I>> for Var<X, I>
82where I: for<'x >SubAssign<&'x I> {
83 fn div_assign(&mut self, rhs: &Var<X, I>) {
84 self.0 -= &rhs.0 }
86}
87
88impl<const X: char, I> Display for Var<X, I>
89where I: ToPrimitive {
90 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
91 let s = self.to_string_u(true);
92 f.write_str(&s)
93 }
94}
95
96impl<const X: char, I> Debug for Var<X, I>
97where I: ToPrimitive {
98 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
99 Display::fmt(self, f)
100 }
101}
102
103#[cfg(feature = "serde")]
104impl<const X: char, I> serde::Serialize for Var<X, I>
105where I: ToPrimitive {
106 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
107 where S: serde::Serializer {
108 serializer.serialize_str(&self.to_string_u(false))
109 }
110}
111
112impl<const X: char, I> MathType for Var<X, I>
113where I: IndexType + ToPrimitive {
114 fn math_symbol() -> String {
115 format!("{X}")
116 }
117}
118
119impl<const X: char, I> MonoOrd for Var<X, I>
120where I: IndexType + ToPrimitive {
121 fn cmp_lex(&self, other: &Self) -> std::cmp::Ordering {
122 I::cmp(&self.0, &other.0)
123 }
124
125 fn cmp_grlex(&self, other: &Self) -> std::cmp::Ordering {
126 I::cmp(&self.0, &other.0)
127 }
128}
129
130impl<const X: char, I> LcKey for Var<X, I>
131where I: IndexType + ToPrimitive {}
132
133macro_rules! impl_univar_unsigned {
134 ($I:ty) => {
135 impl<const X: char> Mono for Var<X, $I> {
136 type Deg = $I;
137
138 fn deg(&self) -> Self::Deg {
139 self.0
140 }
141
142 fn is_unit(&self) -> bool {
143 self.0.is_zero()
144 }
145
146 fn inv(&self) -> Option<Self> {
147 if self.is_unit() {
148 Some(Self(0))
149 } else {
150 None
151 }
152 }
153
154 fn divides(&self, other: &Self) -> bool {
155 self.0 <= other.0
156 }
157 }
158 };
159}
160
161macro_rules! impl_univar_signed {
162 ($I:ty) => {
163 impl<const X: char> Mono for Var<X, $I> {
164 type Deg = $I;
165
166 fn deg(&self) -> Self::Deg {
167 self.0
168 }
169
170 fn is_unit(&self) -> bool {
171 true
172 }
173
174 fn inv(&self) -> Option<Self> { Some(Self(-self.0))
176 }
177
178 fn divides(&self, _other: &Self) -> bool {
179 true
180 }
181 }
182 };
183}
184
185impl_univar_unsigned!(usize);
186impl_univar_signed! (isize);
187
188mod tex {
189 use crate::util::tex::TeX;
190 use super::*;
191
192 impl<const X: char, I> TeX for Var<X, I>
193 where I: ToPrimitive {
194 fn tex_math_symbol() -> String {
195 String::from(X)
196 }
197 fn tex_string(&self) -> String {
198 self.to_string_u(false)
199 }
200 }
201}
202
203pub(crate) fn fmt_mono<I>(x: &str, d: &I, unicode: bool) -> String
204where I: ToPrimitive {
205 let d = d.to_isize().unwrap();
206 if d.is_zero() {
207 "1".to_string()
208 } else if d.is_one() {
209 x.to_string()
210 } else if unicode {
211 let e = superscript(d);
212 format!("{x}{e}")
213 } else {
214 let d = d.to_string();
215 if d.len() == 1 {
216 format!("{x}^{d}")
217 } else {
218 format!("{x}^{{{d}}}")
219 }
220 }
221}
222
223pub(crate) fn parse_mono_deg<I>(x: &str, s: &str) -> Option<I>
224where I: FromStr + FromPrimitive {
225 use regex::Regex;
226
227 let p1 = format!(r"^{x}\^(-?[0-9]+)$");
228 let p2 = format!(r"^{x}\^\{{(-?[0-9]+)\}}$");
229
230 let r1 = Regex::new(&p1).unwrap();
231 let r2 = Regex::new(&p2).unwrap();
232
233 if s == "1" {
234 I::from_i32(0)
235 } else if s == x {
236 I::from_i32(1)
237 } else if let Some(c) = r1.captures(s) {
238 I::from_str(&c[1]).ok()
239 } else if let Some(c) = r2.captures(s) {
240 I::from_str(&c[1]).ok()
241 } else {
242 None
243 }
244}
245
246#[cfg(test)]
247mod tests {
248 use super::*;
249
250 #[test]
251 fn init() {
252 type M = Var<'X',usize>;
253 let x = M::from;
254
255 let d = x(2);
256
257 assert_eq!(d.0, 2);
258 assert_eq!(d.deg(), 2);
259 assert_eq!(M::var_symbol(), 'X');
260 }
261
262 #[test]
263 fn from_str() {
264 type M = Var<'X',isize>;
265 let x = M::from;
266
267 assert_eq!(M::from_str("1"), Ok(M::one()));
268 assert_eq!(M::from_str("X"), Ok(x(1)));
269 assert_eq!(M::from_str("X^2"), Ok(x(2)));
270 assert_eq!(M::from_str("X^{-2}"), Ok(x(-2)));
271 assert!(M::from_str("2").is_err());
272 assert!(M::from_str("x").is_err());
273
274 assert_eq!(M::from_str("X^23"), Ok(x(23)));
276 assert_eq!(M::from_str("X^-2"), Ok(x(-2)));
277 }
278
279 #[test]
280 fn display() {
281 type M = Var<'X', isize>;
282 let x = M::from;
283
284 let d = x(0);
285 assert_eq!(&d.to_string(), "1");
286
287 let d = x(1);
288 assert_eq!(&d.to_string(), "X");
289
290 let d = x(2);
291 assert_eq!(&d.to_string(), "X²");
292
293 let d = x(-1);
294 assert_eq!(&d.to_string(), "X⁻¹");
295
296 let d = x(-2);
297 assert_eq!(&d.to_string(), "X⁻²");
298 }
299
300 #[test]
301 fn neg_opt_unsigned() {
302 type M = Var<'X',usize>;
303 let x = M::from;
304
305 let d = x(0);
306 assert_eq!(d.inv(), Some(x(0)));
307
308 let d = x(1);
309 assert_eq!(d.inv(), None);
310 }
311
312 #[test]
313 fn neg_opt_signed() {
314 type M = Var<'X',isize>;
315 let x = M::from;
316
317 let d = x(0);
318 assert_eq!(d.inv(), Some(x(0)));
319
320 let d = x(1);
321 assert_eq!(d.inv(), Some(x(-1)));
322
323 let d = x(-3);
324 assert_eq!(d.inv(), Some(x(3)));
325 }
326
327 #[test]
328 fn eval() {
329 type M = Var<'X', usize>;
330 let x = M::from;
331
332 let d = x(0);
333 assert_eq!(d.eval(&2), 1);
334
335 let d = x(1);
336 assert_eq!(d.eval(&2), 2);
337
338 let d = x(2);
339 assert_eq!(d.eval(&2), 4);
340 }
341
342 #[test]
343 fn ord() {
344 type M = Var<'X', isize>;
345 let x = M::from;
346
347 assert!(x(0) < x(1));
348 assert!(x(1) < x(2));
349 assert!(x(-1) < x(0));
350 }
351
352 #[test]
353 #[cfg(feature = "serde")]
354 fn serialize() {
355 type M = Var<'X', isize>;
356 let x = M::from;
357
358 let d = x(0);
359 let ser = serde_json::to_string(&d).unwrap();
360 let des = serde_json::from_str::<M>(&ser).unwrap();
361
362 assert_eq!(&ser, "\"1\"");
363 assert_eq!(d, des);
364
365 let d = x(1);
366 let ser = serde_json::to_string(&d).unwrap();
367 let des = serde_json::from_str::<M>(&ser).unwrap();
368
369 assert_eq!(&ser, "\"X\"");
370 assert_eq!(d, des);
371
372 let d = x(2);
373 let ser = serde_json::to_string(&d).unwrap();
374 let des = serde_json::from_str::<M>(&ser).unwrap();
375
376 assert_eq!(&ser, "\"X^2\"");
377 assert_eq!(d, des);
378
379 let d = x(21);
380 let ser = serde_json::to_string(&d).unwrap();
381 let des = serde_json::from_str::<M>(&ser).unwrap();
382
383 assert_eq!(&ser, "\"X^{21}\"");
384 assert_eq!(d, des);
385
386 let d = x(-2);
387 let ser = serde_json::to_string(&d).unwrap();
388 let des = serde_json::from_str::<M>(&ser).unwrap();
389
390 assert_eq!(&ser, "\"X^{-2}\"");
391 assert_eq!(d, des);
392 }
393}