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