1use std::cmp::Ordering;
4use std::collections::{HashMap, VecDeque};
5use std::error::Error;
6use std::fmt;
7use std::hash::{Hash, Hasher};
8use std::str::FromStr;
9
10use counter::Counter;
11use derive_builder::Builder;
12use indexmap::IndexMap;
13use itertools::Itertools;
14use phf::phf_map;
15use regex::Regex;
16use serde::{Deserialize, Serialize};
17
18pub static FROBENIUS_SCHUR_SYMBOLS: phf::Map<i8, &'static str> = phf_map! {
20 1i8 => "r",
21 0i8 => "c",
22 -1i8 => "q",
23};
24
25pub trait MathematicalSymbol: Clone + Hash + Eq + fmt::Display {
36 fn main(&self) -> String;
38
39 fn presuper(&self) -> String;
41
42 fn presub(&self) -> String;
44
45 fn postsuper(&self) -> String;
47
48 fn postsub(&self) -> String;
50
51 fn prefactor(&self) -> String;
53
54 fn postfactor(&self) -> String;
56
57 fn multiplicity(&self) -> Option<usize>;
60}
61
62pub trait LinearSpaceSymbol: MathematicalSymbol + FromStr {
68 fn dimensionality(&self) -> usize;
70
71 fn set_dimensionality(&mut self, dim: usize) -> bool;
81}
82
83pub trait ReducibleLinearSpaceSymbol: LinearSpaceSymbol
93where
94 Self::Subspace: LinearSpaceSymbol + PartialOrd,
95{
96 type Subspace;
98
99 fn from_subspaces(subspaces: &[(Self::Subspace, usize)]) -> Self;
101
102 fn subspaces(&self) -> Vec<(&Self::Subspace, &usize)>;
104
105 #[must_use]
115 fn sorted_subspaces(&self) -> Vec<(&Self::Subspace, &usize)> {
116 self.subspaces()
117 .iter()
118 .sorted_by(|(a, _), (b, _)| {
119 a.partial_cmp(b)
120 .unwrap_or_else(|| panic!("`{a}` and `{b}` cannot be compared."))
121 })
122 .cloned()
123 .collect::<Vec<_>>()
124 }
125}
126
127impl<R> MathematicalSymbol for R
132where
133 R: ReducibleLinearSpaceSymbol,
134{
135 fn main(&self) -> String {
137 self.subspaces()
138 .iter()
139 .map(|(irrep, &mult)| {
140 format!(
141 "{}{irrep}",
142 if mult != 1 {
143 mult.to_string()
144 } else {
145 String::new()
146 }
147 )
148 })
149 .join(" ⊕ ")
150 }
151
152 fn presuper(&self) -> String {
154 String::new()
155 }
156
157 fn presub(&self) -> String {
158 String::new()
159 }
160
161 fn postsuper(&self) -> String {
163 String::new()
164 }
165
166 fn postsub(&self) -> String {
168 String::new()
169 }
170
171 fn prefactor(&self) -> String {
173 "1".to_string()
174 }
175
176 fn postfactor(&self) -> String {
178 String::new()
179 }
180
181 fn multiplicity(&self) -> Option<usize> {
183 Some(1)
184 }
185}
186
187impl<R> LinearSpaceSymbol for R
188where
189 R: ReducibleLinearSpaceSymbol,
190{
191 fn dimensionality(&self) -> usize {
192 self.subspaces()
193 .iter()
194 .map(|(symbol, &mult)| symbol.dimensionality() * mult)
195 .sum()
196 }
197
198 fn set_dimensionality(&mut self, _: usize) -> bool {
199 log::error!("The dimensionality of `{self}` cannot be set.");
200 false
201 }
202}
203
204pub trait CollectionSymbol: MathematicalSymbol {
210 type CollectionElement;
212
213 fn from_reps(
225 symstr: &str,
226 reps: Option<Vec<Self::CollectionElement>>,
227 ) -> Result<Self, GenericSymbolParsingError>;
228
229 fn representative(&self) -> Option<&Self::CollectionElement>;
231
232 fn representatives(&self) -> Option<&Vec<Self::CollectionElement>>;
234
235 fn size(&self) -> usize {
239 self.multiplicity().unwrap_or_else(|| {
240 panic!(
241 "Unable to deduce the multiplicity of the class from the prefactor {}.",
242 self.prefactor()
243 )
244 }) * self
245 .representatives()
246 .map(|reps| reps.len())
247 .expect("No representatives found.")
248 }
249}
250
251#[derive(Builder, Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Serialize, Deserialize)]
275pub struct GenericSymbol {
276 main: String,
278
279 #[builder(default = "String::new()")]
281 presuper: String,
282
283 #[builder(default = "String::new()")]
285 presub: String,
286
287 #[builder(default = "String::new()")]
289 postsuper: String,
290
291 #[builder(default = "String::new()")]
293 postsub: String,
294
295 #[builder(default = "String::new()")]
297 prefactor: String,
298
299 #[builder(default = "String::new()")]
301 postfactor: String,
302}
303
304impl GenericSymbol {
305 fn builder() -> GenericSymbolBuilder {
306 GenericSymbolBuilder::default()
307 }
308
309 pub(crate) fn set_main(&mut self, main: &str) {
311 self.main = main.to_string();
312 }
313
314 pub(crate) fn set_presub(&mut self, presub: &str) {
316 self.presub = presub.to_string();
317 }
318
319 pub(crate) fn set_postsub(&mut self, postsub: &str) {
321 self.postsub = postsub.to_string();
322 }
323}
324
325impl MathematicalSymbol for GenericSymbol {
330 fn main(&self) -> String {
331 self.main.clone()
332 }
333
334 fn presuper(&self) -> String {
335 self.presuper.clone()
336 }
337
338 fn presub(&self) -> String {
339 self.presub.clone()
340 }
341
342 fn postsuper(&self) -> String {
343 self.postsuper.clone()
344 }
345
346 fn postsub(&self) -> String {
347 self.postsub.clone()
348 }
349
350 fn prefactor(&self) -> String {
351 self.prefactor.clone()
352 }
353
354 fn postfactor(&self) -> String {
355 self.postfactor.clone()
356 }
357
358 fn multiplicity(&self) -> Option<usize> {
359 str::parse::<usize>(&self.prefactor).ok()
360 }
361}
362
363impl FromStr for GenericSymbol {
364 type Err = GenericSymbolParsingError;
365
366 fn from_str(symstr: &str) -> Result<Self, Self::Err> {
378 let strs: Vec<&str> = symstr.split('|').collect();
379 if strs.len() == 1 {
380 Ok(Self::builder()
381 .main(strs[0].to_string())
382 .build()
383 .unwrap_or_else(|_| {
384 panic!("Unable to construct a generic symbol from `{symstr}`.")
385 }))
386 } else if strs.len() == 5 {
387 let prefacstr = strs[0];
388 let prestr = strs[1];
389 let mainstr = strs[2];
390 let poststr = strs[3];
391 let postfacstr = strs[4];
392
393 let presuper_re = Regex::new(r"\^\((.*?)\)").expect("Regex pattern invalid.");
394 let presuperstr = if let Some(cap) = presuper_re.captures(prestr) {
395 cap.get(1)
396 .expect("Expected regex group cannot be captured.")
397 .as_str()
398 } else {
399 ""
400 };
401
402 let presub_re = Regex::new(r"_\((.*?)\)").expect("Regex pattern invalid.");
403 let presubstr = if let Some(cap) = presub_re.captures(prestr) {
404 cap.get(1)
405 .expect("Expected regex group cannot be captured.")
406 .as_str()
407 } else {
408 ""
409 };
410
411 let postsuper_re = Regex::new(r"\^\((.*?)\)").expect("Regex pattern invalid.");
412 let postsuperstr = if let Some(cap) = postsuper_re.captures(poststr) {
413 cap.get(1)
414 .expect("Expected regex group cannot be captured.")
415 .as_str()
416 } else {
417 ""
418 };
419
420 let postsub_re = Regex::new(r"_\((.*?)\)").expect("Regex pattern invalid.");
421 let postsubstr = if let Some(cap) = postsub_re.captures(poststr) {
422 cap.get(1)
423 .expect("Expected regex group cannot be captured.")
424 .as_str()
425 } else {
426 ""
427 };
428
429 Ok(Self::builder()
430 .main(mainstr.to_string())
431 .presuper(presuperstr.to_string())
432 .presub(presubstr.to_string())
433 .postsuper(postsuperstr.to_string())
434 .postsub(postsubstr.to_string())
435 .prefactor(prefacstr.to_string())
436 .postfactor(postfacstr.to_string())
437 .build()
438 .unwrap_or_else(|_| {
439 panic!("Unable to construct a generic symbol from `{symstr}`.")
440 }))
441 } else {
442 Err(GenericSymbolParsingError(format!(
443 "`{symstr}` is not parsable."
444 )))
445 }
446 }
447}
448
449impl fmt::Display for GenericSymbol {
450 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
451 let prefac_str = if self.prefactor() == "1" {
452 String::new()
453 } else {
454 self.prefactor()
455 };
456 let presuper_str = if self.presuper().is_empty() {
457 String::new()
458 } else {
459 format!("^({})", self.presuper())
460 };
461 let presub_str = if self.presub().is_empty() {
462 String::new()
463 } else {
464 format!("_({})", self.presub())
465 };
466 let main_str = format!("|{}|", self.main());
467 let postsuper_str = if self.postsuper().is_empty() {
468 String::new()
469 } else {
470 format!("^({})", self.postsuper())
471 };
472 let postsub_str = if self.postsub().is_empty() {
473 String::new()
474 } else {
475 format!("_({})", self.postsub())
476 };
477 let postfac_str = if self.postfactor() == "1" {
478 String::new()
479 } else {
480 self.postfactor()
481 };
482 write!(
483 f,
484 "{prefac_str}{presuper_str}{presub_str}{main_str}{postsuper_str}{postsub_str}{postfac_str}",
485 )
486 }
487}
488
489#[derive(Debug, Clone)]
490pub struct GenericSymbolParsingError(pub String);
491
492impl fmt::Display for GenericSymbolParsingError {
493 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
494 write!(f, "Generic symbol parsing error: {}.", self.0)
495 }
496}
497
498impl Error for GenericSymbolParsingError {}
499
500#[derive(Builder, Debug, Clone, Eq, Serialize, Deserialize)]
510pub struct DecomposedSymbol<S>
511where
512 S: LinearSpaceSymbol + PartialOrd,
513{
514 symbols: IndexMap<S, usize>,
515}
516
517impl<S> DecomposedSymbol<S>
518where
519 S: LinearSpaceSymbol + PartialOrd,
520{
521 fn builder() -> DecomposedSymbolBuilder<S> {
522 DecomposedSymbolBuilder::<S>::default()
523 }
524
525 pub fn new(symstr: &str) -> Result<Self, DecomposedSymbolBuilderError> {
536 Self::from_str(symstr)
537 }
538}
539
540impl<S> ReducibleLinearSpaceSymbol for DecomposedSymbol<S>
545where
546 S: LinearSpaceSymbol + PartialOrd,
547{
548 type Subspace = S;
549
550 fn from_subspaces(irreps: &[(Self::Subspace, usize)]) -> Self {
551 Self::builder()
552 .symbols(
553 irreps
554 .iter()
555 .filter(|(_, mult)| *mult != 0)
556 .cloned()
557 .collect::<IndexMap<_, _>>(),
558 )
559 .build()
560 .expect("Unable to construct a decomposed symbol from a slice of symbols.")
561 }
562
563 fn subspaces(&self) -> Vec<(&Self::Subspace, &usize)> {
564 self.symbols.iter().collect::<Vec<_>>()
565 }
566}
567
568impl<S> FromStr for DecomposedSymbol<S>
569where
570 S: LinearSpaceSymbol + PartialOrd + FromStr,
571{
572 type Err = DecomposedSymbolBuilderError;
573
574 fn from_str(symstr: &str) -> Result<Self, Self::Err> {
594 let re = Regex::new(r"(\d?)(.*)").expect("Regex pattern invalid.");
595 let symbols = symstr
596 .split('⊕')
597 .map(|irrep_str| {
598 let cap = re
599 .captures(irrep_str.trim())
600 .unwrap_or_else(|| panic!("{irrep_str} does not fit the expected pattern."));
601 let mult_str = cap
602 .get(1)
603 .expect("Unable to parse the multiplicity of the irrep.")
604 .as_str();
605 let mult = if mult_str.is_empty() {
606 1
607 } else {
608 str::parse::<usize>(mult_str)
609 .unwrap_or_else(|_| panic!("`{mult_str}` is not a positive integer."))
610 };
611 let irrep = cap.get(2).expect("Unable to parse the irrep.").as_str();
612 (
613 S::from_str(irrep)
614 .unwrap_or_else(|_| panic!("Unable to parse {irrep} as a valid symbol.")),
615 mult,
616 )
617 })
618 .collect::<IndexMap<_, _>>();
619 Self::builder().symbols(symbols).build()
620 }
621}
622
623impl<S> Hash for DecomposedSymbol<S>
624where
625 S: LinearSpaceSymbol + PartialOrd,
626{
627 fn hash<H: Hasher>(&self, state: &mut H) {
628 for symbol in self.sorted_subspaces() {
629 symbol.hash(state);
630 }
631 }
632}
633
634impl<S> PartialOrd for DecomposedSymbol<S>
635where
636 S: LinearSpaceSymbol + PartialOrd,
637{
638 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
639 let self_subspaces = self.sorted_subspaces();
640 let other_subspaces = other.sorted_subspaces();
641 self_subspaces.partial_cmp(&other_subspaces)
642 }
643}
644
645impl<S> fmt::Display for DecomposedSymbol<S>
646where
647 S: LinearSpaceSymbol + PartialOrd,
648{
649 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
650 write!(f, "{}", self.main())
651 }
652}
653
654impl<S> PartialEq for DecomposedSymbol<S>
655where
656 S: LinearSpaceSymbol + PartialOrd,
657{
658 fn eq(&self, other: &Self) -> bool {
659 let self_subspaces = self.sorted_subspaces();
660 let other_subspaces = other.sorted_subspaces();
661 self_subspaces == other_subspaces
662 }
663}
664
665pub(crate) fn disambiguate_linspace_symbols<S>(
681 raw_symbols: impl Iterator<Item = S> + Clone,
682) -> Vec<S>
683where
684 S: LinearSpaceSymbol,
685{
686 let raw_symbol_count = raw_symbols.clone().collect::<Counter<S>>();
687 let mut raw_symbols_to_full_symbols: HashMap<S, VecDeque<S>> = raw_symbol_count
688 .iter()
689 .map(|(raw_symbol, &duplicate_count)| {
690 if duplicate_count == 1 {
691 let mut symbols: VecDeque<S> = VecDeque::new();
692 symbols.push_back(raw_symbol.clone());
693 (raw_symbol.clone(), symbols)
694 } else {
695 let symbols: VecDeque<S> = (0..duplicate_count)
696 .map(|i| {
697 let mut new_symbol = S::from_str(&format!(
698 "|^({})_({})|{}|^({})_({}{})|",
699 raw_symbol.presuper(),
700 raw_symbol.presub(),
701 raw_symbol.main(),
702 raw_symbol.postsuper(),
703 i + 1,
704 raw_symbol.postsub(),
705 ))
706 .unwrap_or_else(|_| {
707 panic!(
708 "Unable to construct symmetry symbol `|^({})|{}|^({})_({}{})|`.",
709 raw_symbol.presuper(),
710 raw_symbol.main(),
711 raw_symbol.postsuper(),
712 i + 1,
713 raw_symbol.postsub(),
714 )
715 });
716 new_symbol.set_dimensionality(raw_symbol.dimensionality());
717 new_symbol
718 })
719 .collect();
720 (raw_symbol.clone(), symbols)
721 }
722 })
723 .collect();
724
725 let symbols: Vec<S> = raw_symbols
726 .map(|raw_symbol| {
727 raw_symbols_to_full_symbols
728 .get_mut(&raw_symbol)
729 .unwrap_or_else(|| {
730 panic!(
731 "Unknown conversion of raw symbol `{}` to full symbol.",
732 &raw_symbol
733 )
734 })
735 .pop_front()
736 .unwrap_or_else(|| {
737 panic!(
738 "No conversion to full symbol possible for `{}`",
739 &raw_symbol
740 )
741 })
742 })
743 .collect();
744
745 symbols
746}