qsym2/symmetry/
symmetry_element_order.rs1use std::cmp::Ordering;
4use std::fmt;
5use std::hash::{Hash, Hasher};
6
7use serde::{Deserialize, Serialize};
8
9use crate::auxiliary::misc::HashableFloat;
10
11#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
13pub enum ElementOrder {
14 Int(u32),
16
17 Inf,
19}
20
21impl ElementOrder {
22 #[must_use]
38 pub fn new(order: f64, thresh: f64) -> Self {
39 assert!(
40 order.is_sign_positive(),
41 "Order value `{order}` is invalid. Order values must be strictly positive.",
42 );
43 if order.is_infinite() {
44 return Self::Inf;
45 }
46 let rounded_order = order.round_factor(thresh);
47 if approx::relative_eq!(
48 rounded_order,
49 rounded_order.round(),
50 epsilon = thresh,
51 max_relative = thresh
52 ) {
53 #[allow(clippy::cast_possible_truncation, clippy::cast_sign_loss)]
54 return Self::Int(rounded_order as u32);
55 }
56 panic!("The input order is not an integer.");
57 }
58
59 #[must_use]
65 pub fn to_float(&self) -> f64 {
66 match self {
67 Self::Int(s_i) => f64::from(*s_i),
68 Self::Inf => f64::INFINITY,
69 }
70 }
71}
72
73impl PartialEq for ElementOrder {
74 fn eq(&self, other: &Self) -> bool {
75 match &self {
76 Self::Int(s_i) => match &other {
77 Self::Int(o_i) => s_i == o_i,
78 Self::Inf => false,
79 },
80 Self::Inf => match &other {
81 Self::Int(_) => false,
82 Self::Inf => true,
83 },
84 }
85 }
86}
87
88impl Eq for ElementOrder {}
89
90impl PartialOrd for ElementOrder {
91 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
92 self.to_float().partial_cmp(&other.to_float())
93 }
94}
95
96impl Ord for ElementOrder {
97 fn cmp(&self, other: &Self) -> Ordering {
98 self.to_float().total_cmp(&other.to_float())
99 }
100}
101
102impl Hash for ElementOrder {
103 fn hash<H: Hasher>(&self, state: &mut H) {
104 match &self {
105 Self::Int(s_i) => {
106 s_i.hash(state);
107 }
108 Self::Inf => {
109 f64::INFINITY.integer_decode().hash(state);
110 }
111 }
112 }
113}
114
115impl fmt::Display for ElementOrder {
116 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
117 match &self {
118 Self::Int(s_i) => write!(f, "{s_i}"),
119 Self::Inf => write!(f, "∞"),
120 }
121 }
122}
123
124pub const ORDER_1: ElementOrder = ElementOrder::Int(1);
126
127pub const ORDER_2: ElementOrder = ElementOrder::Int(2);
129
130
131pub const ORDER_I: ElementOrder = ElementOrder::Inf;