qsym2/target/noci/
multideterminant_transformation.rs

1//! Implementation of symmetry transformations for multi-determinantal wavefunctions.
2
3use std::fmt;
4use std::hash::Hash;
5
6use ndarray::Array2;
7use ndarray_linalg::types::Lapack;
8use num_complex::{Complex, ComplexFloat};
9
10use crate::angmom::spinor_rotation_3d::{SpinOrbitCoupled, StructureConstraint};
11use crate::group::GroupProperties;
12use crate::permutation::Permutation;
13use crate::symmetry::symmetry_element::{SpecialSymmetryTransformation, SymmetryOperation};
14use crate::symmetry::symmetry_transformation::{
15    ComplexConjugationTransformable, DefaultTimeReversalTransformable, SpatialUnitaryTransformable,
16    SpinUnitaryTransformable, SymmetryTransformable, TimeReversalTransformable,
17    TransformationError,
18};
19use crate::target::determinant::SlaterDeterminant;
20use crate::target::noci::basis::{Basis, EagerBasis, OrbitBasis};
21use crate::target::noci::multideterminant::MultiDeterminant;
22
23// ---------------------------
24// SpatialUnitaryTransformable
25// ---------------------------
26
27impl<'a, T, B, SC> SpatialUnitaryTransformable for MultiDeterminant<'a, T, B, SC>
28where
29    T: ComplexFloat + Lapack,
30    SC: StructureConstraint + Hash + Eq + Clone + fmt::Display,
31    B: Basis<SlaterDeterminant<'a, T, SC>> + SpatialUnitaryTransformable + Clone,
32{
33    fn transform_spatial_mut(
34        &mut self,
35        rmat: &Array2<f64>,
36        perm: Option<&Permutation<usize>>,
37    ) -> Result<&mut Self, TransformationError> {
38        self.basis.transform_spatial_mut(rmat, perm)?;
39        Ok(self)
40    }
41}
42
43// ------------------------
44// SpinUnitaryTransformable
45// ------------------------
46
47impl<'a, T, B, SC> SpinUnitaryTransformable for MultiDeterminant<'a, T, B, SC>
48where
49    T: ComplexFloat + Lapack,
50    SC: StructureConstraint + Hash + Eq + Clone + fmt::Display,
51    B: Basis<SlaterDeterminant<'a, T, SC>> + SpinUnitaryTransformable + Clone,
52{
53    fn transform_spin_mut(
54        &mut self,
55        dmat: &Array2<Complex<f64>>,
56    ) -> Result<&mut Self, TransformationError> {
57        self.basis.transform_spin_mut(dmat)?;
58        Ok(self)
59    }
60}
61
62// -------------------------------
63// ComplexConjugationTransformable
64// -------------------------------
65
66impl<'a, T, B, SC> ComplexConjugationTransformable for MultiDeterminant<'a, T, B, SC>
67where
68    T: ComplexFloat + Lapack,
69    SC: StructureConstraint + Hash + Eq + Clone + fmt::Display,
70    B: Basis<SlaterDeterminant<'a, T, SC>> + ComplexConjugationTransformable + Clone,
71{
72    /// Performs a complex conjugation in-place.
73    fn transform_cc_mut(&mut self) -> Result<&mut Self, TransformationError> {
74        self.basis.transform_cc_mut()?;
75        self.coefficients.iter_mut().for_each(|v| *v = v.conj());
76        self.complex_conjugated = !self.complex_conjugated;
77        Ok(self)
78    }
79}
80
81// --------------------------------
82// DefaultTimeReversalTransformable
83// --------------------------------
84
85impl<'a, T, B, SC> DefaultTimeReversalTransformable for MultiDeterminant<'a, T, B, SC>
86where
87    T: ComplexFloat + Lapack,
88    SC: StructureConstraint + Hash + Eq + Clone + fmt::Display,
89    B: Basis<SlaterDeterminant<'a, T, SC>> + DefaultTimeReversalTransformable + Clone,
90{
91}
92
93// ---------------------------------------
94// TimeReversalTransformable (non-default)
95// ---------------------------------------
96// `SlaterDeterminant<_, _, SpinOrbitCoupled>` does not implement
97// `DefaultTimeReversalTransformable` and so the surrounding `OrbitBasis` does not get a blanket
98// implementation of `TimeReversalTransformable`, and neither does the surrounding
99// `MultiDeterminant`.
100impl<'a, 'g, G> TimeReversalTransformable
101    for MultiDeterminant<
102        'a,
103        Complex<f64>,
104        OrbitBasis<'g, G, SlaterDeterminant<'a, Complex<f64>, SpinOrbitCoupled>>,
105        SpinOrbitCoupled,
106    >
107where
108    G: GroupProperties<GroupElement = SymmetryOperation> + Clone,
109{
110    fn transform_timerev_mut(&mut self) -> Result<&mut Self, TransformationError> {
111        self.basis.transform_timerev_mut()?;
112        self.coefficients.mapv_inplace(|v| v.conj());
113        self.complex_conjugated = !self.complex_conjugated;
114        Ok(self)
115    }
116}
117
118// `SlaterDeterminant<_, _, SpinOrbitCoupled>` does not implement
119// `DefaultTimeReversalTransformable` and so the surrounding `EagerBasis` does not get a blanket
120// implementation of `TimeReversalTransformable`, and neither does the surrounding
121// `MultiDeterminant`.
122impl<'a> TimeReversalTransformable
123    for MultiDeterminant<
124        'a,
125        Complex<f64>,
126        EagerBasis<SlaterDeterminant<'a, Complex<f64>, SpinOrbitCoupled>>,
127        SpinOrbitCoupled,
128    >
129{
130    fn transform_timerev_mut(&mut self) -> Result<&mut Self, TransformationError> {
131        self.basis.transform_timerev_mut()?;
132        self.coefficients.mapv_inplace(|v| v.conj());
133        self.complex_conjugated = !self.complex_conjugated;
134        Ok(self)
135    }
136}
137
138// ---------------------
139// SymmetryTransformable
140// ---------------------
141
142impl<'a, 'go, G, T, SC> SymmetryTransformable
143    for MultiDeterminant<'a, T, OrbitBasis<'go, G, SlaterDeterminant<'a, T, SC>>, SC>
144where
145    T: ComplexFloat + Lapack,
146    G: GroupProperties<GroupElement = SymmetryOperation> + Clone,
147    SC: StructureConstraint + Hash + Eq + Clone + fmt::Display,
148    SlaterDeterminant<'a, T, SC>: SymmetryTransformable,
149    Self: TimeReversalTransformable,
150    OrbitBasis<'go, G, SlaterDeterminant<'a, T, SC>>: TimeReversalTransformable,
151{
152    fn sym_permute_sites_spatial(
153        &self,
154        symop: &SymmetryOperation,
155    ) -> Result<Permutation<usize>, TransformationError> {
156        self.basis.sym_permute_sites_spatial(symop)
157    }
158
159    // --------------------------
160    // Overriden provided methods
161    // --------------------------
162    fn sym_transform_spatial_mut(
163        &mut self,
164        symop: &SymmetryOperation,
165    ) -> Result<&mut Self, TransformationError> {
166        self.basis.sym_transform_spatial_mut(symop)?;
167        if symop.contains_time_reversal() {
168            self.coefficients.iter_mut().for_each(|v| *v = v.conj());
169            self.complex_conjugated = !self.complex_conjugated;
170        }
171        Ok(self)
172    }
173
174    fn sym_transform_spatial_with_spintimerev_mut(
175        &mut self,
176        symop: &SymmetryOperation,
177    ) -> Result<&mut Self, TransformationError> {
178        self.basis
179            .sym_transform_spatial_with_spintimerev_mut(symop)?;
180        if symop.contains_time_reversal() {
181            self.coefficients.iter_mut().for_each(|v| *v = v.conj());
182            self.complex_conjugated = !self.complex_conjugated;
183        }
184        Ok(self)
185    }
186
187    fn sym_transform_spin_mut(
188        &mut self,
189        symop: &SymmetryOperation,
190    ) -> Result<&mut Self, TransformationError> {
191        self.basis.sym_transform_spin_mut(symop)?;
192        if symop.contains_time_reversal() {
193            self.coefficients.iter_mut().for_each(|v| *v = v.conj());
194            self.complex_conjugated = !self.complex_conjugated;
195        }
196        Ok(self)
197    }
198
199    fn sym_transform_spin_spatial_mut(
200        &mut self,
201        symop: &SymmetryOperation,
202    ) -> Result<&mut Self, TransformationError> {
203        self.basis.sym_transform_spin_spatial_mut(symop)?;
204        if symop.contains_time_reversal() {
205            self.coefficients.iter_mut().for_each(|v| *v = v.conj());
206            self.complex_conjugated = !self.complex_conjugated;
207        }
208        Ok(self)
209    }
210}
211
212impl<'a, T, SC> SymmetryTransformable
213    for MultiDeterminant<'a, T, EagerBasis<SlaterDeterminant<'a, T, SC>>, SC>
214where
215    T: ComplexFloat + Lapack,
216    SC: StructureConstraint + Hash + Eq + Clone + fmt::Display,
217    SlaterDeterminant<'a, T, SC>: SymmetryTransformable,
218    Self: TimeReversalTransformable,
219    EagerBasis<SlaterDeterminant<'a, T, SC>>: TimeReversalTransformable,
220{
221    fn sym_permute_sites_spatial(
222        &self,
223        symop: &SymmetryOperation,
224    ) -> Result<Permutation<usize>, TransformationError> {
225        self.basis.sym_permute_sites_spatial(symop)
226    }
227}