qsym2/target/noci/
basis_transformation.rs

1//! Implementation of symmetry transformations for bases for non-orthogonal configuration
2//! interaction of Slater determinants.
3
4use std::collections::{HashSet, VecDeque};
5
6use anyhow::format_err;
7use nalgebra::Vector3;
8use ndarray::Array2;
9use num_complex::Complex;
10
11use crate::angmom::spinor_rotation_3d::SpinOrbitCoupled;
12use crate::group::GroupProperties;
13use crate::permutation::Permutation;
14use crate::symmetry::symmetry_element::{RotationGroup, SymmetryElement, SymmetryOperation, TRROT};
15use crate::symmetry::symmetry_element_order::ElementOrder;
16use crate::symmetry::symmetry_transformation::{
17    ComplexConjugationTransformable, DefaultTimeReversalTransformable, SpatialUnitaryTransformable,
18    SpinUnitaryTransformable, SymmetryTransformable, TimeReversalTransformable,
19    TransformationError,
20};
21use crate::target::determinant::SlaterDeterminant;
22use crate::target::noci::basis::{EagerBasis, OrbitBasis};
23
24// ~~~~~~~~~~~~~~~~~~~~~~
25// ~~~~~~~~~~~~~~~~~~~~~~
26// Lazy basis from orbits
27// ~~~~~~~~~~~~~~~~~~~~~~
28// ~~~~~~~~~~~~~~~~~~~~~~
29
30// ---------------------------
31// SpatialUnitaryTransformable
32// ---------------------------
33impl<'g, G, I> SpatialUnitaryTransformable for OrbitBasis<'g, G, I>
34where
35    G: GroupProperties + Clone,
36    I: SpatialUnitaryTransformable,
37{
38    fn transform_spatial_mut(
39        &mut self,
40        _: &Array2<f64>,
41        _: Option<&Permutation<usize>>,
42    ) -> Result<&mut Self, TransformationError> {
43        Err(TransformationError("Transforming an orbit basis by an arbitrary spatial transformation matrix is not supported.".to_string()))
44    }
45}
46
47// ------------------------
48// SpinUnitaryTransformable
49// ------------------------
50impl<'g, G, I> SpinUnitaryTransformable for OrbitBasis<'g, G, I>
51where
52    G: GroupProperties + Clone,
53    I: SpinUnitaryTransformable,
54{
55    fn transform_spin_mut(
56        &mut self,
57        _: &Array2<Complex<f64>>,
58    ) -> Result<&mut Self, TransformationError> {
59        Err(TransformationError("Transforming an orbit basis by an arbitrary spin transformation matrix is not supported.".to_string()))
60    }
61}
62
63// -------------------------------
64// ComplexConjugationTransformable
65// -------------------------------
66
67impl<'g, G, I> ComplexConjugationTransformable for OrbitBasis<'g, G, I>
68where
69    G: GroupProperties + Clone,
70    I: ComplexConjugationTransformable,
71{
72    /// Performs a complex conjugation in-place.
73    fn transform_cc_mut(&mut self) -> Result<&mut Self, TransformationError> {
74        Err(TransformationError(
75            "Transforming an orbit basis by an explicit complex conjugation is not supported."
76                .to_string(),
77        ))
78    }
79}
80
81// --------------------------------
82// DefaultTimeReversalTransformable
83// --------------------------------
84impl<'g, G, I> DefaultTimeReversalTransformable for OrbitBasis<'g, G, I>
85where
86    G: GroupProperties + Clone,
87    I: DefaultTimeReversalTransformable,
88{
89}
90
91// ---------------------------------------
92// TimeReversalTransformable (non-default)
93// ---------------------------------------
94// `SlaterDeterminant<_, _, SpinOrbitCoupled>` does not implement
95// `DefaultTimeReversalTransformable` and so the surrounding `OrbitBasis` does not get a blanket
96// implementation of `TimeReversalTransformable`.
97impl<'a, 'g, G> TimeReversalTransformable
98    for OrbitBasis<'g, G, SlaterDeterminant<'a, Complex<f64>, SpinOrbitCoupled>>
99where
100    G: GroupProperties<GroupElement = SymmetryOperation> + Clone,
101{
102    fn transform_timerev_mut(&mut self) -> Result<&mut Self, TransformationError> {
103        let t_element = SymmetryElement::builder()
104            .threshold(1e-14)
105            .proper_order(ElementOrder::Int(1))
106            .proper_power(1)
107            .raw_axis(Vector3::new(0.0, 0.0, 1.0))
108            .kind(TRROT)
109            .rotation_group(RotationGroup::SU2(true))
110            .build()
111            .map_err(|err| TransformationError(err.to_string()))?;
112        let t = SymmetryOperation::builder()
113            .generating_element(t_element)
114            .power(1)
115            .build()
116            .map_err(|err| TransformationError(err.to_string()))?;
117        if let Some(prefactors) = self.prefactors.as_mut() {
118            prefactors.push_front((t.clone(), |g, item| {
119                item.sym_transform_spin_spatial(g)
120                    .map_err(|err| format_err!(err))
121            }));
122        } else {
123            let mut v = VecDeque::<(
124                G::GroupElement,
125                fn(
126                    &G::GroupElement,
127                    &SlaterDeterminant<'a, Complex<f64>, SpinOrbitCoupled>,
128                )
129                    -> Result<SlaterDeterminant<'a, Complex<f64>, SpinOrbitCoupled>, anyhow::Error>,
130            )>::new();
131            v.push_front((t.clone(), |g, item| {
132                item.sym_transform_spin_spatial(g)
133                    .map_err(|err| format_err!(err))
134            }));
135            self.prefactors = Some(v);
136        }
137        Ok(self)
138    }
139}
140
141// ---------------------
142// SymmetryTransformable
143// ---------------------
144impl<'g, G, I> SymmetryTransformable for OrbitBasis<'g, G, I>
145where
146    G: GroupProperties<GroupElement = SymmetryOperation> + Clone,
147    I: SymmetryTransformable,
148    OrbitBasis<'g, G, I>: TimeReversalTransformable,
149{
150    fn sym_permute_sites_spatial(
151        &self,
152        symop: &SymmetryOperation,
153    ) -> Result<Permutation<usize>, TransformationError> {
154        let mut perms = self
155            .origins
156            .iter()
157            .map(|origin| origin.sym_permute_sites_spatial(symop))
158            .collect::<Result<HashSet<_>, _>>()?;
159        if perms.len() == 1 {
160            perms.drain().next().ok_or(TransformationError(
161                "Unable to retrieve the site permutation.".to_string(),
162            ))
163        } else {
164            Err(TransformationError(
165                "Mismatched site permutations across the origins.".to_string(),
166            ))
167        }
168    }
169
170    // --------------------------
171    // Overriden provided methods
172    // --------------------------
173    fn sym_transform_spatial_mut(
174        &mut self,
175        symop: &SymmetryOperation,
176    ) -> Result<&mut Self, TransformationError> {
177        if let Some(prefactors) = self.prefactors.as_mut() {
178            prefactors.push_front((symop.clone(), |g, item| {
179                item.sym_transform_spatial(g)
180                    .map_err(|err| format_err!(err))
181            }));
182        } else {
183            let mut v = VecDeque::<(
184                G::GroupElement,
185                fn(&G::GroupElement, &I) -> Result<I, anyhow::Error>,
186            )>::new();
187            v.push_front((symop.clone(), |g, item| {
188                item.sym_transform_spatial(g)
189                    .map_err(|err| format_err!(err))
190            }));
191            self.prefactors = Some(v);
192        }
193        Ok(self)
194    }
195
196    fn sym_transform_spatial_with_spintimerev_mut(
197        &mut self,
198        symop: &SymmetryOperation,
199    ) -> Result<&mut Self, TransformationError> {
200        if let Some(prefactors) = self.prefactors.as_mut() {
201            prefactors.push_front((symop.clone(), |g, item| {
202                item.sym_transform_spatial_with_spintimerev(g)
203                    .map_err(|err| format_err!(err))
204            }));
205        } else {
206            let mut v = VecDeque::<(
207                G::GroupElement,
208                fn(&G::GroupElement, &I) -> Result<I, anyhow::Error>,
209            )>::new();
210            v.push_front((symop.clone(), |g, item| {
211                item.sym_transform_spatial_with_spintimerev(g)
212                    .map_err(|err| format_err!(err))
213            }));
214            self.prefactors = Some(v);
215        }
216        Ok(self)
217    }
218
219    fn sym_transform_spin_mut(
220        &mut self,
221        symop: &SymmetryOperation,
222    ) -> Result<&mut Self, TransformationError> {
223        if let Some(prefactors) = self.prefactors.as_mut() {
224            prefactors.push_front((symop.clone(), |g, item| {
225                item.sym_transform_spin(g).map_err(|err| format_err!(err))
226            }));
227        } else {
228            let mut v = VecDeque::<(
229                G::GroupElement,
230                fn(&G::GroupElement, &I) -> Result<I, anyhow::Error>,
231            )>::new();
232            v.push_front((symop.clone(), |g, item| {
233                item.sym_transform_spin(g).map_err(|err| format_err!(err))
234            }));
235            self.prefactors = Some(v);
236        }
237        Ok(self)
238    }
239
240    fn sym_transform_spin_spatial_mut(
241        &mut self,
242        symop: &SymmetryOperation,
243    ) -> Result<&mut Self, TransformationError> {
244        if let Some(prefactors) = self.prefactors.as_mut() {
245            prefactors.push_front((symop.clone(), |g, item| {
246                item.sym_transform_spin_spatial(g)
247                    .map_err(|err| format_err!(err))
248            }));
249        } else {
250            let mut v = VecDeque::<(
251                G::GroupElement,
252                fn(&G::GroupElement, &I) -> Result<I, anyhow::Error>,
253            )>::new();
254            v.push_front((symop.clone(), |g, item| {
255                item.sym_transform_spin_spatial(g)
256                    .map_err(|err| format_err!(err))
257            }));
258            self.prefactors = Some(v);
259        }
260        Ok(self)
261    }
262}
263
264// ~~~~~~~~~~~
265// ~~~~~~~~~~~
266// Eager basis
267// ~~~~~~~~~~~
268// ~~~~~~~~~~~
269
270// ---------------------------
271// SpatialUnitaryTransformable
272// ---------------------------
273impl<I> SpatialUnitaryTransformable for EagerBasis<I>
274where
275    I: SpatialUnitaryTransformable,
276{
277    fn transform_spatial_mut(
278        &mut self,
279        rmat: &Array2<f64>,
280        perm: Option<&Permutation<usize>>,
281    ) -> Result<&mut Self, TransformationError> {
282        self.elements
283            .iter_mut()
284            .map(|origin| origin.transform_spatial_mut(rmat, perm))
285            .collect::<Result<Vec<_>, _>>()?;
286        Ok(self)
287    }
288}
289
290// ------------------------
291// SpinUnitaryTransformable
292// ------------------------
293impl<I> SpinUnitaryTransformable for EagerBasis<I>
294where
295    I: SpinUnitaryTransformable,
296{
297    fn transform_spin_mut(
298        &mut self,
299        dmat: &Array2<Complex<f64>>,
300    ) -> Result<&mut Self, TransformationError> {
301        self.elements
302            .iter_mut()
303            .map(|origin| origin.transform_spin_mut(dmat))
304            .collect::<Result<Vec<_>, _>>()?;
305        Ok(self)
306    }
307}
308
309// -------------------------------
310// ComplexConjugationTransformable
311// -------------------------------
312
313impl<I> ComplexConjugationTransformable for EagerBasis<I>
314where
315    I: ComplexConjugationTransformable,
316{
317    /// Performs a complex conjugation in-place.
318    fn transform_cc_mut(&mut self) -> Result<&mut Self, TransformationError> {
319        for origin in self.elements.iter_mut() {
320            origin.transform_cc_mut()?;
321        }
322        Ok(self)
323    }
324}
325
326// --------------------------------
327// DefaultTimeReversalTransformable
328// --------------------------------
329impl<I> DefaultTimeReversalTransformable for EagerBasis<I> where
330    I: DefaultTimeReversalTransformable + Clone
331{
332}
333
334// ---------------------------------------
335// TimeReversalTransformable (non-default)
336// ---------------------------------------
337// `SlaterDeterminant<_, _, SpinOrbitCoupled>` does not implement
338// `DefaultTimeReversalTransformable` and so the surrounding `EagerBasis` does not get a blanket
339// implementation of `TimeReversalTransformable`.
340impl<'a> TimeReversalTransformable
341    for EagerBasis<SlaterDeterminant<'a, Complex<f64>, SpinOrbitCoupled>>
342{
343    fn transform_timerev_mut(&mut self) -> Result<&mut Self, TransformationError> {
344        for det in self.elements.iter_mut() {
345            det.transform_timerev_mut()?;
346        }
347        Ok(self)
348    }
349}
350
351// ---------------------
352// SymmetryTransformable
353// ---------------------
354impl<I> SymmetryTransformable for EagerBasis<I>
355where
356    I: SymmetryTransformable,
357    EagerBasis<I>: TimeReversalTransformable,
358{
359    fn sym_permute_sites_spatial(
360        &self,
361        symop: &SymmetryOperation,
362    ) -> Result<Permutation<usize>, TransformationError> {
363        let mut perms = self
364            .elements
365            .iter()
366            .map(|origin| origin.sym_permute_sites_spatial(symop))
367            .collect::<Result<HashSet<_>, _>>()?;
368        if perms.len() == 1 {
369            perms.drain().next().ok_or(TransformationError(
370                "Unable to retrieve the site permutation.".to_string(),
371            ))
372        } else {
373            Err(TransformationError(
374                "Mismatched site permutations across the elements in the basis.".to_string(),
375            ))
376        }
377    }
378}