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(|&(ref 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(|&(ref 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}