1use std::collections::{HashSet, VecDeque};
5use std::fmt;
6
7use anyhow::format_err;
8use nalgebra::Vector3;
9use ndarray::Array2;
10use ndarray_linalg::types::Lapack;
11use num_complex::{Complex, ComplexFloat};
12
13use crate::angmom::spinor_rotation_3d::{SpinOrbitCoupled, StructureConstraint};
14use crate::group::GroupProperties;
15use crate::permutation::Permutation;
16use crate::symmetry::symmetry_element::{RotationGroup, SymmetryElement, SymmetryOperation, TRROT};
17use crate::symmetry::symmetry_element_order::ElementOrder;
18use crate::symmetry::symmetry_transformation::{
19 ComplexConjugationTransformable, DefaultTimeReversalTransformable, SpatialUnitaryTransformable,
20 SpinUnitaryTransformable, SymmetryTransformable, TimeReversalTransformable,
21 TransformationError,
22};
23use crate::target::determinant::SlaterDeterminant;
24use crate::target::noci::basis::{EagerBasis, FCIBasis, OrbitBasis};
25
26impl<'g, G, I> SpatialUnitaryTransformable for OrbitBasis<'g, G, I>
36where
37 G: GroupProperties + Clone,
38 I: SpatialUnitaryTransformable,
39{
40 fn transform_spatial_mut(
41 &mut self,
42 _: &Array2<f64>,
43 _: Option<&Permutation<usize>>,
44 ) -> Result<&mut Self, TransformationError> {
45 Err(TransformationError("Transforming an orbit basis by an arbitrary spatial transformation matrix is not supported.".to_string()))
46 }
47}
48
49impl<'g, G, I> SpinUnitaryTransformable for OrbitBasis<'g, G, I>
53where
54 G: GroupProperties + Clone,
55 I: SpinUnitaryTransformable,
56{
57 fn transform_spin_mut(
58 &mut self,
59 _: &Array2<Complex<f64>>,
60 ) -> Result<&mut Self, TransformationError> {
61 Err(TransformationError("Transforming an orbit basis by an arbitrary spin transformation matrix is not supported.".to_string()))
62 }
63}
64
65impl<'g, G, I> ComplexConjugationTransformable for OrbitBasis<'g, G, I>
70where
71 G: GroupProperties + Clone,
72 I: ComplexConjugationTransformable,
73{
74 fn transform_cc_mut(&mut self) -> Result<&mut Self, TransformationError> {
76 Err(TransformationError(
77 "Transforming an orbit basis by an explicit complex conjugation is not supported."
78 .to_string(),
79 ))
80 }
81}
82
83impl<'g, G, I> DefaultTimeReversalTransformable for OrbitBasis<'g, G, I>
87where
88 G: GroupProperties + Clone,
89 I: DefaultTimeReversalTransformable,
90{
91}
92
93impl<'a, 'g, G> TimeReversalTransformable
100 for OrbitBasis<'g, G, SlaterDeterminant<'a, Complex<f64>, SpinOrbitCoupled>>
101where
102 G: GroupProperties<GroupElement = SymmetryOperation> + Clone,
103{
104 fn transform_timerev_mut(&mut self) -> Result<&mut Self, TransformationError> {
105 let t_element = SymmetryElement::builder()
106 .threshold(1e-14)
107 .proper_order(ElementOrder::Int(1))
108 .proper_power(1)
109 .raw_axis(Vector3::new(0.0, 0.0, 1.0))
110 .kind(TRROT)
111 .rotation_group(RotationGroup::SU2(true))
112 .build()
113 .map_err(|err| TransformationError(err.to_string()))?;
114 let t = SymmetryOperation::builder()
115 .generating_element(t_element)
116 .power(1)
117 .build()
118 .map_err(|err| TransformationError(err.to_string()))?;
119 if let Some(prefactors) = self.prefactors.as_mut() {
120 prefactors.push_front((t.clone(), |g, item| {
121 item.sym_transform_spin_spatial(g)
122 .map_err(|err| format_err!(err))
123 }));
124 } else {
125 let mut v = VecDeque::<(
126 G::GroupElement,
127 fn(
128 &G::GroupElement,
129 &SlaterDeterminant<'a, Complex<f64>, SpinOrbitCoupled>,
130 )
131 -> Result<SlaterDeterminant<'a, Complex<f64>, SpinOrbitCoupled>, anyhow::Error>,
132 )>::new();
133 v.push_front((t.clone(), |g, item| {
134 item.sym_transform_spin_spatial(g)
135 .map_err(|err| format_err!(err))
136 }));
137 self.prefactors = Some(v);
138 }
139 Ok(self)
140 }
141}
142
143impl<'g, G, I> SymmetryTransformable for OrbitBasis<'g, G, I>
147where
148 G: GroupProperties<GroupElement = SymmetryOperation> + Clone,
149 I: SymmetryTransformable,
150 OrbitBasis<'g, G, I>: TimeReversalTransformable,
151{
152 fn sym_permute_sites_spatial(
153 &self,
154 symop: &SymmetryOperation,
155 ) -> Result<Permutation<usize>, TransformationError> {
156 let mut perms = self
157 .origins
158 .iter()
159 .map(|origin| origin.sym_permute_sites_spatial(symop))
160 .collect::<Result<HashSet<_>, _>>()?;
161 if perms.len() == 1 {
162 perms.drain().next().ok_or(TransformationError(
163 "Unable to retrieve the site permutation.".to_string(),
164 ))
165 } else {
166 Err(TransformationError(
167 "Mismatched site permutations across the origins.".to_string(),
168 ))
169 }
170 }
171
172 fn sym_transform_spatial_mut(
176 &mut self,
177 symop: &SymmetryOperation,
178 ) -> Result<&mut Self, TransformationError> {
179 if let Some(prefactors) = self.prefactors.as_mut() {
180 prefactors.push_front((symop.clone(), |g, item| {
181 item.sym_transform_spatial(g)
182 .map_err(|err| format_err!(err))
183 }));
184 } else {
185 let mut v = VecDeque::<(
186 G::GroupElement,
187 fn(&G::GroupElement, &I) -> Result<I, anyhow::Error>,
188 )>::new();
189 v.push_front((symop.clone(), |g, item| {
190 item.sym_transform_spatial(g)
191 .map_err(|err| format_err!(err))
192 }));
193 self.prefactors = Some(v);
194 }
195 Ok(self)
196 }
197
198 fn sym_transform_spatial_with_spintimerev_mut(
199 &mut self,
200 symop: &SymmetryOperation,
201 ) -> Result<&mut Self, TransformationError> {
202 if let Some(prefactors) = self.prefactors.as_mut() {
203 prefactors.push_front((symop.clone(), |g, item| {
204 item.sym_transform_spatial_with_spintimerev(g)
205 .map_err(|err| format_err!(err))
206 }));
207 } else {
208 let mut v = VecDeque::<(
209 G::GroupElement,
210 fn(&G::GroupElement, &I) -> Result<I, anyhow::Error>,
211 )>::new();
212 v.push_front((symop.clone(), |g, item| {
213 item.sym_transform_spatial_with_spintimerev(g)
214 .map_err(|err| format_err!(err))
215 }));
216 self.prefactors = Some(v);
217 }
218 Ok(self)
219 }
220
221 fn sym_transform_spin_mut(
222 &mut self,
223 symop: &SymmetryOperation,
224 ) -> Result<&mut Self, TransformationError> {
225 if let Some(prefactors) = self.prefactors.as_mut() {
226 prefactors.push_front((symop.clone(), |g, item| {
227 item.sym_transform_spin(g).map_err(|err| format_err!(err))
228 }));
229 } else {
230 let mut v = VecDeque::<(
231 G::GroupElement,
232 fn(&G::GroupElement, &I) -> Result<I, anyhow::Error>,
233 )>::new();
234 v.push_front((symop.clone(), |g, item| {
235 item.sym_transform_spin(g).map_err(|err| format_err!(err))
236 }));
237 self.prefactors = Some(v);
238 }
239 Ok(self)
240 }
241
242 fn sym_transform_spin_spatial_mut(
243 &mut self,
244 symop: &SymmetryOperation,
245 ) -> Result<&mut Self, TransformationError> {
246 if let Some(prefactors) = self.prefactors.as_mut() {
247 prefactors.push_front((symop.clone(), |g, item| {
248 item.sym_transform_spin_spatial(g)
249 .map_err(|err| format_err!(err))
250 }));
251 } else {
252 let mut v = VecDeque::<(
253 G::GroupElement,
254 fn(&G::GroupElement, &I) -> Result<I, anyhow::Error>,
255 )>::new();
256 v.push_front((symop.clone(), |g, item| {
257 item.sym_transform_spin_spatial(g)
258 .map_err(|err| format_err!(err))
259 }));
260 self.prefactors = Some(v);
261 }
262 Ok(self)
263 }
264}
265
266impl<I> SpatialUnitaryTransformable for EagerBasis<I>
276where
277 I: SpatialUnitaryTransformable,
278{
279 fn transform_spatial_mut(
280 &mut self,
281 rmat: &Array2<f64>,
282 perm: Option<&Permutation<usize>>,
283 ) -> Result<&mut Self, TransformationError> {
284 self.elements
285 .iter_mut()
286 .map(|origin| origin.transform_spatial_mut(rmat, perm))
287 .collect::<Result<Vec<_>, _>>()?;
288 Ok(self)
289 }
290}
291
292impl<I> SpinUnitaryTransformable for EagerBasis<I>
296where
297 I: SpinUnitaryTransformable,
298{
299 fn transform_spin_mut(
300 &mut self,
301 dmat: &Array2<Complex<f64>>,
302 ) -> Result<&mut Self, TransformationError> {
303 self.elements
304 .iter_mut()
305 .map(|origin| origin.transform_spin_mut(dmat))
306 .collect::<Result<Vec<_>, _>>()?;
307 Ok(self)
308 }
309}
310
311impl<I> ComplexConjugationTransformable for EagerBasis<I>
316where
317 I: ComplexConjugationTransformable,
318{
319 fn transform_cc_mut(&mut self) -> Result<&mut Self, TransformationError> {
321 for origin in self.elements.iter_mut() {
322 origin.transform_cc_mut()?;
323 }
324 Ok(self)
325 }
326}
327
328impl<I> DefaultTimeReversalTransformable for EagerBasis<I> where
332 I: DefaultTimeReversalTransformable + Clone
333{
334}
335
336impl<'a> TimeReversalTransformable
343 for EagerBasis<SlaterDeterminant<'a, Complex<f64>, SpinOrbitCoupled>>
344{
345 fn transform_timerev_mut(&mut self) -> Result<&mut Self, TransformationError> {
346 for det in self.elements.iter_mut() {
347 det.transform_timerev_mut()?;
348 }
349 Ok(self)
350 }
351}
352
353impl<I> SymmetryTransformable for EagerBasis<I>
357where
358 I: SymmetryTransformable,
359 EagerBasis<I>: TimeReversalTransformable,
360{
361 fn sym_permute_sites_spatial(
365 &self,
366 symop: &SymmetryOperation,
367 ) -> Result<Permutation<usize>, TransformationError> {
368 let mut perms = self
369 .elements
370 .iter()
371 .map(|origin| origin.sym_permute_sites_spatial(symop))
372 .collect::<Result<HashSet<_>, _>>()?;
373 if perms.len() == 1 {
374 perms.drain().next().ok_or(TransformationError(
375 "Unable to retrieve the site permutation.".to_string(),
376 ))
377 } else {
378 Err(TransformationError(
379 "Mismatched site permutations across the elements in the basis.".to_string(),
380 ))
381 }
382 }
383
384 fn sym_transform_spin_spatial_mut(
393 &mut self,
394 symop: &SymmetryOperation,
395 ) -> Result<&mut Self, TransformationError> {
396 self.elements
397 .iter_mut()
398 .map(|item| item.sym_transform_spin_spatial_mut(symop))
399 .collect::<Result<Vec<_>, _>>()?;
400 Ok(self)
401 }
402}
403
404impl<'a, T, SC> SpatialUnitaryTransformable for FCIBasis<'a, T, SC>
414where
415 T: ComplexFloat + Lapack,
416 SC: StructureConstraint + fmt::Display + Clone,
417 SlaterDeterminant<'a, T, SC>: SpatialUnitaryTransformable,
418{
419 fn transform_spatial_mut(
420 &mut self,
421 rmat: &Array2<f64>,
422 perm: Option<&Permutation<usize>>,
423 ) -> Result<&mut Self, TransformationError> {
424 self.reference.transform_spatial_mut(rmat, perm)?;
425 Ok(self)
426 }
427}
428
429impl<'a, T, SC> SpinUnitaryTransformable for FCIBasis<'a, T, SC>
433where
434 T: ComplexFloat + Lapack,
435 SC: StructureConstraint + fmt::Display + Clone,
436 SlaterDeterminant<'a, T, SC>: SpinUnitaryTransformable,
437{
438 fn transform_spin_mut(
439 &mut self,
440 rmat: &Array2<Complex<f64>>,
441 ) -> Result<&mut Self, TransformationError> {
442 self.reference.transform_spin_mut(rmat)?;
443 Ok(self)
444 }
445}
446
447impl<'a, T, SC> ComplexConjugationTransformable for FCIBasis<'a, T, SC>
452where
453 T: ComplexFloat + Lapack,
454 SC: StructureConstraint + fmt::Display + Clone,
455 SlaterDeterminant<'a, T, SC>: ComplexConjugationTransformable,
456{
457 fn transform_cc_mut(&mut self) -> Result<&mut Self, TransformationError> {
459 self.reference.transform_cc_mut()?;
460 Ok(self)
461 }
462}
463
464impl<'a, T, SC> DefaultTimeReversalTransformable for FCIBasis<'a, T, SC>
468where
469 T: ComplexFloat + Lapack,
470 SC: StructureConstraint + fmt::Display + Clone,
471 SlaterDeterminant<'a, T, SC>: DefaultTimeReversalTransformable,
472{
473}
474
475impl<'a> TimeReversalTransformable for FCIBasis<'a, Complex<f64>, SpinOrbitCoupled> {
482 fn transform_timerev_mut(&mut self) -> Result<&mut Self, TransformationError> {
483 self.reference.transform_timerev_mut()?;
484 Ok(self)
485 }
486}
487
488impl<'a, T, SC> SymmetryTransformable for FCIBasis<'a, T, SC>
492where
493 T: ComplexFloat + Lapack,
494 SC: StructureConstraint + fmt::Display + Clone,
495 SlaterDeterminant<'a, T, SC>: SymmetryTransformable,
496 FCIBasis<'a, T, SC>: TimeReversalTransformable,
497{
498 fn sym_permute_sites_spatial(
499 &self,
500 symop: &SymmetryOperation,
501 ) -> Result<Permutation<usize>, TransformationError> {
502 self.reference.sym_permute_sites_spatial(symop)
503 }
504
505 fn sym_transform_spin_spatial_mut(
514 &mut self,
515 symop: &SymmetryOperation,
516 ) -> Result<&mut Self, TransformationError> {
517 self.reference.sym_transform_spin_spatial_mut(symop)?;
518 Ok(self)
519 }
520}