1use std::cmp::Ordering;
4use std::fmt;
5use std::hash::{Hash, Hasher};
6use std::ops::{Add, Mul, MulAssign, Neg, Sub};
7
8use approx;
9use derive_builder::Builder;
10use indexmap::{IndexMap, IndexSet};
11use num::Complex;
12use num_traits::{ToPrimitive, Zero};
13use serde::{Deserialize, Serialize};
14
15use crate::auxiliary::misc::HashableFloat;
16use crate::chartab::unityroot::UnityRoot;
17
18type F = fraction::GenericFraction<u32>;
19
20#[cfg(test)]
21#[path = "character_tests.rs"]
22mod character_tests;
23
24#[derive(Builder, Clone, Serialize, Deserialize)]
33pub struct Character {
34 #[builder(setter(custom))]
36 terms: IndexMap<UnityRoot, usize>,
37
38 #[builder(setter(custom), default = "1e-14")]
40 threshold: f64,
41}
42
43impl CharacterBuilder {
44 fn terms(&mut self, ts: &[(UnityRoot, usize)]) -> &mut Self {
45 let mut terms = IndexMap::<UnityRoot, usize>::new();
46 for (ur, mult) in ts.iter() {
49 *terms.entry(ur.clone()).or_default() += mult;
50 }
51 self.terms = Some(terms);
52 self
53 }
54
55 fn threshold(&mut self, thresh: f64) -> &mut Self {
56 if thresh >= 0.0 {
57 self.threshold = Some(thresh);
58 } else {
59 log::error!(
60 "Threshold value {} is invalid. Threshold must be non-negative.",
61 thresh
62 );
63 self.threshold = None;
64 }
65 self
66 }
67}
68
69impl Character {
70 fn builder() -> CharacterBuilder {
76 CharacterBuilder::default()
77 }
78
79 #[must_use]
85 pub fn new(ts: &[(UnityRoot, usize)]) -> Self {
86 Self::builder()
87 .terms(ts)
88 .build()
89 .expect("Unable to construct a character.")
90 }
91
92 pub fn threshold(&self) -> f64 {
94 self.threshold
95 }
96
97 #[must_use]
107 pub fn complex_value(&self) -> Complex<f64> {
108 self.terms
109 .iter()
110 .filter_map(|(uroot, &mult)| {
111 if mult > 0 {
112 Some(
113 uroot.complex_value()
114 * mult
115 .to_f64()
116 .unwrap_or_else(|| panic!("Unable to convert `{mult}` to `f64`.")),
117 )
118 } else {
119 None
120 }
121 })
122 .sum()
123 }
124
125 #[must_use]
136 pub fn get_numerical(&self, real_only: bool, precision: usize) -> String {
137 let Complex { re, im } = self.complex_value();
138 if real_only {
139 format!("{:+.precision$}", {
140 if approx::relative_eq!(
141 re,
142 0.0,
143 epsilon = self.threshold,
144 max_relative = self.threshold
145 ) && re < 0.0
146 {
147 -re
148 } else {
149 re
150 }
151 })
152 } else {
153 format!(
154 "{:+.precision$} {} {:.precision$}i",
155 {
156 if approx::relative_eq!(
157 re,
158 0.0,
159 epsilon = self.threshold,
160 max_relative = self.threshold
161 ) && re < 0.0
162 {
163 -re
164 } else {
165 re
166 }
167 },
168 {
169 if im >= 0.0
170 || approx::relative_eq!(
171 im,
172 0.0,
173 epsilon = self.threshold,
174 max_relative = self.threshold
175 )
176 {
177 "+"
178 } else {
179 "-"
180 }
181 },
182 im.abs()
183 )
184 }
185 }
186
187 fn get_concise(&self, num_non_int: bool) -> String {
203 let complex_value = self.complex_value();
204 let precision = 3i32;
205 let precision_u = usize::try_from(precision.unsigned_abs())
206 .expect("Unable to represent `precision` as `usize`.");
207 if approx::relative_eq!(
208 complex_value.im,
209 0.0,
210 epsilon = 10.0f64.powi(-precision - 1).max(self.threshold),
211 max_relative = 10.0f64.powi(-precision - 1).max(self.threshold)
212 ) {
213 let rounded_re = complex_value.re.round_factor(self.threshold);
216 if approx::relative_eq!(
217 rounded_re,
218 rounded_re.round(),
219 epsilon = 10.0f64.powi(-precision - 1).max(self.threshold),
220 max_relative = 10.0f64.powi(-precision - 1).max(self.threshold)
221 ) {
222 if approx::relative_eq!(
224 rounded_re,
225 0.0,
226 epsilon = 10.0f64.powi(-precision - 1).max(self.threshold),
227 max_relative = 10.0f64.powi(-precision - 1).max(self.threshold)
228 ) {
229 "0".to_string()
230 } else {
231 format!("{:+.0}", complex_value.re)
232 }
233 } else {
234 if num_non_int {
236 format!("{:+.precision_u$}", complex_value.re)
237 } else {
238 format!("{self:?}")
239 }
240 }
241 } else if approx::relative_eq!(
242 complex_value.re,
243 0.0,
244 epsilon = self.threshold,
245 max_relative = self.threshold
246 ) {
247 let rounded_im = complex_value.im.round_factor(self.threshold);
250 if approx::relative_eq!(
251 rounded_im,
252 rounded_im.round(),
253 epsilon = 10.0f64.powi(-precision - 1).max(self.threshold),
254 max_relative = 10.0f64.powi(-precision - 1).max(self.threshold)
255 ) {
256 if approx::relative_eq!(
258 rounded_im.abs(),
259 1.0,
260 epsilon = 10.0f64.powi(-precision - 1).max(self.threshold),
261 max_relative = 10.0f64.powi(-precision - 1).max(self.threshold)
262 ) {
263 let imag = if rounded_im > 0.0 { "+i" } else { "-i" };
265 imag.to_string()
266 } else {
267 format!("{:+.0}i", complex_value.im)
269 }
270 } else {
271 if num_non_int {
273 format!("{:+.precision_u$}i", complex_value.im)
274 } else {
275 format!("{self:?}")
276 }
277 }
278 } else {
279 let rounded_re = complex_value.re.round_factor(self.threshold);
282 let rounded_im = complex_value.im.round_factor(self.threshold);
283 if (approx::relative_ne!(
284 rounded_re,
285 rounded_re.round(),
286 epsilon = 10.0f64.powi(-precision - 1).max(self.threshold),
287 max_relative = 10.0f64.powi(-precision - 1).max(self.threshold)
288 ) || approx::relative_ne!(
289 rounded_im,
290 rounded_im.round(),
291 epsilon = 10.0f64.powi(-precision - 1).max(self.threshold),
292 max_relative = 10.0f64.powi(-precision - 1).max(self.threshold)
293 )) && !num_non_int
294 {
295 format!("{self:?}")
296 } else {
297 format!(
298 "{:+.precision_u$} {} {:.precision_u$}i",
299 complex_value.re,
300 {
301 if complex_value.im > 0.0 {
302 "+"
303 } else {
304 "-"
305 }
306 },
307 complex_value.im.abs()
308 )
309 }
310 }
311 }
312
313 #[must_use]
326 pub fn simplify(&self) -> Self {
327 let mut urs: IndexSet<_> = self.terms.keys().rev().collect();
328 let mut simplified_terms = Vec::<(UnityRoot, usize)>::with_capacity(urs.len());
329 let f12 = F::new(1u32, 2u32);
330 while !urs.is_empty() {
331 let ur = urs
332 .pop()
333 .expect("Unable to retrieve an unexamined unity root.");
334 let nur_option = urs
335 .iter()
336 .find(|&test_ur| {
337 test_ur.fraction == ur.fraction + f12 || test_ur.fraction == ur.fraction - f12
338 })
339 .copied();
340 if let Some(nur) = nur_option {
341 let res = urs.shift_remove(nur);
342 debug_assert!(res);
343 let ur_mult = self
344 .terms
345 .get(ur)
346 .unwrap_or_else(|| panic!("Unable to retrieve the multiplicity of {ur}."));
347 let nur_mult = self
348 .terms
349 .get(nur)
350 .unwrap_or_else(|| panic!("Unable to retrieve the multiplicity of {nur}."));
351 match ur_mult.cmp(nur_mult) {
352 Ordering::Less => simplified_terms.push((nur.clone(), nur_mult - ur_mult)),
353 Ordering::Greater => simplified_terms.push((ur.clone(), ur_mult - nur_mult)),
354 Ordering::Equal => (),
355 };
356 } else {
357 let ur_mult = self
358 .terms
359 .get(ur)
360 .unwrap_or_else(|| panic!("Unable to retrieve the multiplicity of {ur}."));
361 simplified_terms.push((ur.clone(), *ur_mult));
362 }
363 }
364 Character::builder()
365 .terms(&simplified_terms)
366 .threshold(self.threshold)
367 .build()
368 .expect("Unable to construct a simplified character.")
369 }
370
371 #[must_use]
381 pub fn complex_conjugate(&self) -> Self {
382 Self::builder()
383 .terms(
384 &self
385 .terms
386 .iter()
387 .map(|(ur, mult)| (ur.complex_conjugate(), *mult))
388 .collect::<Vec<_>>(),
389 )
390 .threshold(self.threshold)
391 .build()
392 .unwrap_or_else(|_| panic!("Unable to construct the complex conjugate of `{self}`."))
393 }
394}
395
396impl PartialEq for Character {
401 fn eq(&self, other: &Self) -> bool {
402 (self.terms == other.terms) || {
403 let self_complex = self.complex_value();
404 let other_complex = other.complex_value();
405 let thresh = (self.threshold * other.threshold).sqrt();
406 approx::relative_eq!(
407 self_complex.re,
408 other_complex.re,
409 epsilon = thresh,
410 max_relative = thresh
411 ) && approx::relative_eq!(
412 self_complex.im,
413 other_complex.im,
414 epsilon = thresh,
415 max_relative = thresh
416 )
417 }
418 }
419}
420
421impl Eq for Character {}
422
423impl PartialOrd for Character {
424 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
426 let mut self_terms = self.terms.clone();
427 self_terms.retain(|_, mult| *mult > 0);
428 self_terms.sort_by(|uroot1, _, uroot2, _| {
429 uroot1
430 .partial_cmp(uroot2)
431 .unwrap_or_else(|| panic!("{uroot1} and {uroot2} cannot be compared."))
432 });
433
434 let mut other_terms = other.terms.clone();
435 other_terms.retain(|_, mult| *mult > 0);
436 other_terms.sort_by(|uroot1, _, uroot2, _| {
437 uroot1
438 .partial_cmp(uroot2)
439 .unwrap_or_else(|| panic!("{uroot1} and {uroot2} cannot be compared."))
440 });
441
442 let self_terms_vec = self_terms.into_iter().collect::<Vec<_>>();
443 let other_terms_vec = other_terms.into_iter().collect::<Vec<_>>();
444 self_terms_vec.partial_cmp(&other_terms_vec)
445 }
446}
447
448impl fmt::Debug for Character {
449 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
452 let one = UnityRoot::new(0u32, 2u32);
453 let str_terms: Vec<String> = self
454 .terms
455 .clone()
456 .sorted_by(|k1, _, k2, _| {
457 k1.partial_cmp(k2)
458 .unwrap_or_else(|| panic!("{k1} and {k2} cannot be compared."))
459 })
460 .filter_map(|(root, mult)| {
461 if mult == 1 {
462 Some(format!("{root}"))
463 } else if mult == 0 {
464 None
465 } else if root == one {
466 Some(format!("{mult}"))
467 } else {
468 Some(format!("{mult}*{root}"))
469 }
470 })
471 .collect();
472 if str_terms.is_empty() {
473 write!(f, "0")
474 } else {
475 write!(f, "{}", str_terms.join(" + "))
476 }
477 }
478}
479
480impl fmt::Display for Character {
481 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
484 write!(f, "{}", self.get_concise(false))
485 }
486}
487
488impl Hash for Character {
489 fn hash<H: Hasher>(&self, state: &mut H) {
490 let terms_vec = self
491 .terms
492 .clone()
493 .sorted_by(|ur1, m1, ur2, m2| {
494 PartialOrd::partial_cmp(&(ur1.clone(), m1), &(ur2.clone(), m2)).unwrap_or_else(
495 || {
496 panic!(
497 "{:?} anmd {:?} cannot be compared.",
498 (ur1.clone(), m1),
499 (ur2.clone(), m2)
500 )
501 },
502 )
503 })
504 .collect::<Vec<_>>();
505 terms_vec.hash(state);
506 }
507}
508
509impl Zero for Character {
513 fn zero() -> Self {
514 Self::new(&[])
515 }
516
517 fn is_zero(&self) -> bool {
518 *self == Self::zero()
519 }
520}
521
522impl Add<&'_ Character> for &Character {
526 type Output = Character;
527
528 fn add(self, rhs: &Character) -> Self::Output {
529 let mut sum = self.clone();
530 for (ur, mult) in rhs.terms.iter() {
531 *sum.terms.entry(ur.clone()).or_default() += mult;
532 }
533 sum
534 }
535}
536
537impl Add<&'_ Character> for Character {
538 type Output = Character;
539
540 fn add(self, rhs: &Self) -> Self::Output {
541 &self + rhs
542 }
543}
544
545impl Add<Character> for &Character {
546 type Output = Character;
547
548 fn add(self, rhs: Character) -> Self::Output {
549 self + &rhs
550 }
551}
552
553impl Add<Character> for Character {
554 type Output = Character;
555
556 fn add(self, rhs: Self) -> Self::Output {
557 &self + &rhs
558 }
559}
560
561impl Neg for &Character {
565 type Output = Character;
566
567 fn neg(self) -> Self::Output {
568 let f12 = F::new(1u32, 2u32);
569 let terms: IndexMap<_, _> = self
570 .terms
571 .iter()
572 .map(|(ur, mult)| {
573 let mut nur = ur.clone();
574 nur.fraction = (nur.fraction + f12).fract();
575 (nur, *mult)
576 })
577 .collect();
578 let mut nchar = self.clone();
579 nchar.terms = terms;
580 nchar
581 }
582}
583
584impl Neg for Character {
585 type Output = Character;
586
587 fn neg(self) -> Self::Output {
588 -&self
589 }
590}
591
592impl Sub<&'_ Character> for &Character {
596 type Output = Character;
597
598 fn sub(self, rhs: &Character) -> Self::Output {
599 self + (-rhs)
600 }
601}
602
603impl Sub<&'_ Character> for Character {
604 type Output = Character;
605
606 fn sub(self, rhs: &Self) -> Self::Output {
607 &self + (-rhs)
608 }
609}
610
611impl Sub<Character> for &Character {
612 type Output = Character;
613
614 fn sub(self, rhs: Character) -> Self::Output {
615 self + (-&rhs)
616 }
617}
618
619impl Sub<Character> for Character {
620 type Output = Character;
621
622 fn sub(self, rhs: Self) -> Self::Output {
623 &self + (-&rhs)
624 }
625}
626
627impl MulAssign<usize> for Character {
631 fn mul_assign(&mut self, rhs: usize) {
632 self.terms.iter_mut().for_each(|(_, mult)| {
633 *mult *= rhs;
634 });
635 }
636}
637
638impl Mul<usize> for &Character {
642 type Output = Character;
643
644 fn mul(self, rhs: usize) -> Self::Output {
645 let mut prod = self.clone();
646 prod *= rhs;
647 prod
648 }
649}
650
651impl Mul<usize> for Character {
652 type Output = Character;
653
654 fn mul(self, rhs: usize) -> Self::Output {
655 &self * rhs
656 }
657}