1use std::collections::{HashSet, VecDeque};
5
6use anyhow::format_err;
7use ndarray::Array2;
8use num_complex::Complex;
9
10use crate::group::GroupProperties;
11use crate::permutation::Permutation;
12use crate::symmetry::symmetry_element::SymmetryOperation;
13use crate::symmetry::symmetry_transformation::{
14 ComplexConjugationTransformable, DefaultTimeReversalTransformable, SpatialUnitaryTransformable,
15 SpinUnitaryTransformable, SymmetryTransformable, TimeReversalTransformable,
16 TransformationError,
17};
18use crate::target::noci::basis::{EagerBasis, OrbitBasis};
19
20impl<'g, G, I> SpatialUnitaryTransformable for OrbitBasis<'g, G, I>
28where
29 G: GroupProperties + Clone,
30 I: SpatialUnitaryTransformable,
31{
32 fn transform_spatial_mut(
33 &mut self,
34 _: &Array2<f64>,
35 _: Option<&Permutation<usize>>,
36 ) -> Result<&mut Self, TransformationError> {
37 Err(TransformationError("Transforming an orbit basis by an arbitrary spatial transformation matrix is not supported.".to_string()))
38 }
39}
40
41impl<'g, G, I> SpinUnitaryTransformable for OrbitBasis<'g, G, I>
45where
46 G: GroupProperties + Clone,
47 I: SpinUnitaryTransformable,
48{
49 fn transform_spin_mut(
50 &mut self,
51 _: &Array2<Complex<f64>>,
52 ) -> Result<&mut Self, TransformationError> {
53 Err(TransformationError("Transforming an orbit basis by an arbitrary spin transformation matrix is not supported.".to_string()))
54 }
55}
56
57impl<'g, G, I> ComplexConjugationTransformable for OrbitBasis<'g, G, I>
62where
63 G: GroupProperties + Clone,
64 I: ComplexConjugationTransformable,
65{
66 fn transform_cc_mut(&mut self) -> Result<&mut Self, TransformationError> {
68 Err(TransformationError(
69 "Transforming an orbit basis by an explicit complex conjugation is not supported."
70 .to_string(),
71 ))
72 }
73}
74
75impl<'g, G, I> DefaultTimeReversalTransformable for OrbitBasis<'g, G, I>
79where
80 G: GroupProperties + Clone,
81 I: DefaultTimeReversalTransformable,
82{
83}
84
85impl<'g, G, I> SymmetryTransformable for OrbitBasis<'g, G, I>
89where
90 G: GroupProperties<GroupElement = SymmetryOperation> + Clone,
91 I: SymmetryTransformable,
92 OrbitBasis<'g, G, I>: TimeReversalTransformable,
93{
94 fn sym_permute_sites_spatial(
95 &self,
96 symop: &SymmetryOperation,
97 ) -> Result<Permutation<usize>, TransformationError> {
98 let mut perms = self
99 .origins
100 .iter()
101 .map(|origin| origin.sym_permute_sites_spatial(symop))
102 .collect::<Result<HashSet<_>, _>>()?;
103 if perms.len() == 1 {
104 perms.drain().next().ok_or(TransformationError(
105 "Unable to retrieve the site permutation.".to_string(),
106 ))
107 } else {
108 Err(TransformationError(
109 "Mismatched site permutations across the origins.".to_string(),
110 ))
111 }
112 }
113
114 fn sym_transform_spatial_mut(
118 &mut self,
119 symop: &SymmetryOperation,
120 ) -> Result<&mut Self, TransformationError> {
121 if let Some(prefactors) = self.prefactors.as_mut() {
122 prefactors.push_front((symop.clone(), |g, item| {
123 item.sym_transform_spatial(g)
124 .map_err(|err| format_err!(err))
125 }));
126 } else {
127 let mut v = VecDeque::<(
128 G::GroupElement,
129 fn(&G::GroupElement, &I) -> Result<I, anyhow::Error>,
130 )>::new();
131 v.push_front((symop.clone(), |g, item| {
132 item.sym_transform_spatial(g)
133 .map_err(|err| format_err!(err))
134 }));
135 self.prefactors = Some(v);
136 }
137 Ok(self)
138 }
139
140 fn sym_transform_spatial_with_spintimerev_mut(
141 &mut self,
142 symop: &SymmetryOperation,
143 ) -> Result<&mut Self, TransformationError> {
144 if let Some(prefactors) = self.prefactors.as_mut() {
145 prefactors.push_front((symop.clone(), |g, item| {
146 item.sym_transform_spatial_with_spintimerev(g)
147 .map_err(|err| format_err!(err))
148 }));
149 } else {
150 let mut v = VecDeque::<(
151 G::GroupElement,
152 fn(&G::GroupElement, &I) -> Result<I, anyhow::Error>,
153 )>::new();
154 v.push_front((symop.clone(), |g, item| {
155 item.sym_transform_spatial_with_spintimerev(g)
156 .map_err(|err| format_err!(err))
157 }));
158 self.prefactors = Some(v);
159 }
160 Ok(self)
161 }
162
163 fn sym_transform_spin_mut(
164 &mut self,
165 symop: &SymmetryOperation,
166 ) -> Result<&mut Self, TransformationError> {
167 if let Some(prefactors) = self.prefactors.as_mut() {
168 prefactors.push_front((symop.clone(), |g, item| {
169 item.sym_transform_spin(g).map_err(|err| format_err!(err))
170 }));
171 } else {
172 let mut v = VecDeque::<(
173 G::GroupElement,
174 fn(&G::GroupElement, &I) -> Result<I, anyhow::Error>,
175 )>::new();
176 v.push_front((symop.clone(), |g, item| {
177 item.sym_transform_spin(g).map_err(|err| format_err!(err))
178 }));
179 self.prefactors = Some(v);
180 }
181 Ok(self)
182 }
183
184 fn sym_transform_spin_spatial_mut(
185 &mut self,
186 symop: &SymmetryOperation,
187 ) -> Result<&mut Self, TransformationError> {
188 if let Some(prefactors) = self.prefactors.as_mut() {
189 prefactors.push_front((symop.clone(), |g, item| {
190 item.sym_transform_spin_spatial(g)
191 .map_err(|err| format_err!(err))
192 }));
193 } else {
194 let mut v = VecDeque::<(
195 G::GroupElement,
196 fn(&G::GroupElement, &I) -> Result<I, anyhow::Error>,
197 )>::new();
198 v.push_front((symop.clone(), |g, item| {
199 item.sym_transform_spin_spatial(g)
200 .map_err(|err| format_err!(err))
201 }));
202 self.prefactors = Some(v);
203 }
204 Ok(self)
205 }
206}
207
208impl<I> SpatialUnitaryTransformable for EagerBasis<I>
216where
217 I: SpatialUnitaryTransformable,
218{
219 fn transform_spatial_mut(
220 &mut self,
221 rmat: &Array2<f64>,
222 perm: Option<&Permutation<usize>>,
223 ) -> Result<&mut Self, TransformationError> {
224 self.elements
225 .iter_mut()
226 .map(|origin| origin.transform_spatial_mut(rmat, perm))
227 .collect::<Result<Vec<_>, _>>()?;
228 Ok(self)
229 }
230}
231
232impl<I> SpinUnitaryTransformable for EagerBasis<I>
236where
237 I: SpinUnitaryTransformable,
238{
239 fn transform_spin_mut(
240 &mut self,
241 dmat: &Array2<Complex<f64>>,
242 ) -> Result<&mut Self, TransformationError> {
243 self.elements
244 .iter_mut()
245 .map(|origin| origin.transform_spin_mut(dmat))
246 .collect::<Result<Vec<_>, _>>()?;
247 Ok(self)
248 }
249}
250
251impl<I> ComplexConjugationTransformable for EagerBasis<I>
256where
257 I: ComplexConjugationTransformable,
258{
259 fn transform_cc_mut(&mut self) -> Result<&mut Self, TransformationError> {
261 for origin in self.elements.iter_mut() {
262 origin.transform_cc_mut()?;
263 }
264 Ok(self)
265 }
266}
267
268impl<I> DefaultTimeReversalTransformable for EagerBasis<I> where
272 I: DefaultTimeReversalTransformable + Clone
273{
274}
275
276impl<I> SymmetryTransformable for EagerBasis<I>
280where
281 I: SymmetryTransformable,
282 EagerBasis<I>: TimeReversalTransformable,
283{
284 fn sym_permute_sites_spatial(
285 &self,
286 symop: &SymmetryOperation,
287 ) -> Result<Permutation<usize>, TransformationError> {
288 let mut perms = self
289 .elements
290 .iter()
291 .map(|origin| origin.sym_permute_sites_spatial(symop))
292 .collect::<Result<HashSet<_>, _>>()?;
293 if perms.len() == 1 {
294 perms.drain().next().ok_or(TransformationError(
295 "Unable to retrieve the site permutation.".to_string(),
296 ))
297 } else {
298 Err(TransformationError(
299 "Mismatched site permutations across the elements in the basis.".to_string(),
300 ))
301 }
302 }
303}