Skip to main content

qsym2/target/noci/
multideterminants_transformation.rs

1//! Implementation of symmetry transformations for multi-determinantal wavefunction collections.
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, FCIBasis, OrbitBasis};
21use crate::target::noci::multideterminants::MultiDeterminants;
22
23// ---------------------------
24// SpatialUnitaryTransformable
25// ---------------------------
26
27impl<'a, T, B, SC> SpatialUnitaryTransformable for MultiDeterminants<'a, T, B, SC>
28where
29    T: ComplexFloat + Lapack,
30    SC: StructureConstraint + Hash + Eq + Clone + fmt::Display,
31    B: Basis<Item = 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 MultiDeterminants<'a, T, B, SC>
48where
49    T: ComplexFloat + Lapack,
50    SC: StructureConstraint + Hash + Eq + Clone + fmt::Display,
51    B: Basis<Item = 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 MultiDeterminants<'a, T, B, SC>
67where
68    T: ComplexFloat + Lapack,
69    SC: StructureConstraint + Hash + Eq + Clone + fmt::Display,
70    B: Basis<Item = 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 MultiDeterminants<'a, T, B, SC>
86where
87    T: ComplexFloat + Lapack,
88    SC: StructureConstraint + Hash + Eq + Clone + fmt::Display,
89    B: Basis<Item = 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// `MultiDeterminants`.
100impl<'a, 'g, G> TimeReversalTransformable
101    for MultiDeterminants<
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// `MultiDeterminants`.
122impl<'a> TimeReversalTransformable
123    for MultiDeterminants<
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// `SlaterDeterminant<_, _, SpinOrbitCoupled>` does not implement
139// `DefaultTimeReversalTransformable` and so the surrounding `FCIBasis` does not get a blanket
140// implementation of `TimeReversalTransformable`, and neither does the surrounding
141// `MultiDeterminants`.
142impl<'a> TimeReversalTransformable
143    for MultiDeterminants<
144        'a,
145        Complex<f64>,
146        FCIBasis<'a, Complex<f64>, SpinOrbitCoupled>,
147        SpinOrbitCoupled,
148    >
149{
150    fn transform_timerev_mut(&mut self) -> Result<&mut Self, TransformationError> {
151        self.basis.transform_timerev_mut()?;
152        self.coefficients.mapv_inplace(|v| v.conj());
153        self.complex_conjugated = !self.complex_conjugated;
154        Ok(self)
155    }
156}
157
158// ---------------------
159// SymmetryTransformable
160// ---------------------
161
162impl<'a, T, B, SC> SymmetryTransformable for MultiDeterminants<'a, T, B, SC>
163where
164    T: ComplexFloat + Lapack,
165    B: Basis<Item = SlaterDeterminant<'a, T, SC>> + Clone + SymmetryTransformable,
166    SC: StructureConstraint + Hash + Eq + Clone + fmt::Display,
167    SlaterDeterminant<'a, T, SC>: SymmetryTransformable,
168    Self: TimeReversalTransformable,
169{
170    fn sym_permute_sites_spatial(
171        &self,
172        symop: &SymmetryOperation,
173    ) -> Result<Permutation<usize>, TransformationError> {
174        self.basis.sym_permute_sites_spatial(symop)
175    }
176
177    // --------------------------
178    // Overriden provided methods
179    // --------------------------
180    fn sym_transform_spatial_mut(
181        &mut self,
182        symop: &SymmetryOperation,
183    ) -> Result<&mut Self, TransformationError> {
184        self.basis.sym_transform_spatial_mut(symop)?;
185        if symop.contains_time_reversal() {
186            self.coefficients.iter_mut().for_each(|v| *v = v.conj());
187            self.complex_conjugated = !self.complex_conjugated;
188        }
189        Ok(self)
190    }
191
192    fn sym_transform_spatial_with_spintimerev_mut(
193        &mut self,
194        symop: &SymmetryOperation,
195    ) -> Result<&mut Self, TransformationError> {
196        self.basis
197            .sym_transform_spatial_with_spintimerev_mut(symop)?;
198        if symop.contains_time_reversal() {
199            self.coefficients.iter_mut().for_each(|v| *v = v.conj());
200            self.complex_conjugated = !self.complex_conjugated;
201        }
202        Ok(self)
203    }
204
205    fn sym_transform_spin_mut(
206        &mut self,
207        symop: &SymmetryOperation,
208    ) -> Result<&mut Self, TransformationError> {
209        self.basis.sym_transform_spin_mut(symop)?;
210        if symop.contains_time_reversal() {
211            self.coefficients.iter_mut().for_each(|v| *v = v.conj());
212            self.complex_conjugated = !self.complex_conjugated;
213        }
214        Ok(self)
215    }
216
217    fn sym_transform_spin_spatial_mut(
218        &mut self,
219        symop: &SymmetryOperation,
220    ) -> Result<&mut Self, TransformationError> {
221        self.basis.sym_transform_spin_spatial_mut(symop)?;
222        if symop.contains_time_reversal() {
223            self.coefficients.iter_mut().for_each(|v| *v = v.conj());
224            self.complex_conjugated = !self.complex_conjugated;
225        }
226        Ok(self)
227    }
228}