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 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
20// ~~~~~~~~~~~~~~~~~~~~~~
21// Lazy basis from orbits
22// ~~~~~~~~~~~~~~~~~~~~~~
23
24// ---------------------------
25// SpatialUnitaryTransformable
26// ---------------------------
27impl<'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
41// ------------------------
42// SpinUnitaryTransformable
43// ------------------------
44impl<'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
57// -------------------------------
58// ComplexConjugationTransformable
59// -------------------------------
60
61impl<'g, G, I> ComplexConjugationTransformable for OrbitBasis<'g, G, I>
62where
63    G: GroupProperties + Clone,
64    I: ComplexConjugationTransformable,
65{
66    /// Performs a complex conjugation in-place.
67    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
75// --------------------------------
76// DefaultTimeReversalTransformable
77// --------------------------------
78impl<'g, G, I> DefaultTimeReversalTransformable for OrbitBasis<'g, G, I>
79where
80    G: GroupProperties + Clone,
81    I: DefaultTimeReversalTransformable,
82{
83}
84
85// ---------------------
86// SymmetryTransformable
87// ---------------------
88impl<'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    // --------------------------
115    // Overriden provided methods
116    // --------------------------
117    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
208// ~~~~~~~~~~~
209// Eager basis
210// ~~~~~~~~~~~
211
212// ---------------------------
213// SpatialUnitaryTransformable
214// ---------------------------
215impl<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
232// ------------------------
233// SpinUnitaryTransformable
234// ------------------------
235impl<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
251// -------------------------------
252// ComplexConjugationTransformable
253// -------------------------------
254
255impl<I> ComplexConjugationTransformable for EagerBasis<I>
256where
257    I: ComplexConjugationTransformable,
258{
259    /// Performs a complex conjugation in-place.
260    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
268// --------------------------------
269// DefaultTimeReversalTransformable
270// --------------------------------
271impl<I> DefaultTimeReversalTransformable for EagerBasis<I> where
272    I: DefaultTimeReversalTransformable + Clone
273{
274}
275
276// ---------------------
277// SymmetryTransformable
278// ---------------------
279impl<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}