1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
//! Implementation of symmetry transformation for axial vectors.

use nalgebra::Vector3;
use ndarray::{Array1, Array2, Axis, LinalgScalar, ScalarOperand};
use ndarray_linalg::solve::Determinant;
use ndarray_linalg::types::Lapack;
use num_complex::{Complex, ComplexFloat};

use crate::permutation::Permutation;
use crate::symmetry::symmetry_element::SymmetryOperation;
use crate::symmetry::symmetry_transformation::{
    ComplexConjugationTransformable, SpatialUnitaryTransformable, SpinUnitaryTransformable,
    SymmetryTransformable, TimeReversalTransformable, TransformationError,
};
use crate::target::tensor::axialvector::{AxialVector3, TimeParity};

// ---------------------------
// SpatialUnitaryTransformable
// ---------------------------
impl<T> SpatialUnitaryTransformable for AxialVector3<T>
where
    T: ComplexFloat + LinalgScalar + ScalarOperand + Copy + Lapack,
    f64: Into<T>,
{
    fn transform_spatial_mut(
        &mut self,
        rmat: &Array2<f64>,
        _perm: Option<&Permutation<usize>>,
    ) -> Result<&mut Self, TransformationError> {
        // rmat is in (y, z, x) order. We must first reorder into (x, y, z) order.
        let rmat_xyz = rmat.select(Axis(0), &[2, 0, 1]).select(Axis(1), &[2, 0, 1]);
        let det = rmat_xyz
            .det()
            .expect("Unable to obtain the determinant of the transformation matrix.");
        let old_components = Array1::from_iter(self.components.iter().cloned());
        let new_components = rmat_xyz.mapv(|x| (det * x).into()).dot(&old_components);
        self.components = Vector3::from_iterator(new_components.into_iter());
        Ok(self)
    }
}

// ------------------------
// SpinUnitaryTransformable
// ------------------------

impl<T> SpinUnitaryTransformable for AxialVector3<T>
where
    T: ComplexFloat + Lapack,
{
    /// Axial vectors are spatial quantities, therefore spin transformations have no effects on
    /// them.
    fn transform_spin_mut(
        &mut self,
        _dmat: &Array2<Complex<f64>>,
    ) -> Result<&mut Self, TransformationError> {
        Ok(self)
    }
}

// -------------------------------
// ComplexConjugationTransformable
// -------------------------------

impl<T> ComplexConjugationTransformable for AxialVector3<T>
where
    T: ComplexFloat + Lapack,
{
    fn transform_cc_mut(&mut self) -> Result<&mut Self, TransformationError> {
        self.components = self.components.map(|x| x.conj());
        Ok(self)
    }
}

// -------------------------
// TimeReversalTransformable
// -------------------------

impl<T> TimeReversalTransformable for AxialVector3<T>
where
    T: ComplexFloat + Lapack,
{
    /// Provides a custom implementation of time reversal where the axial vector is kept invariant
    /// or inverted based on its time-parity. The components of the vector are also
    /// complex-conjugated to respect the antiunitarity of time reversal.
    fn transform_timerev_mut(&mut self) -> Result<&mut Self, TransformationError> {
        self.transform_cc_mut()?;
        match self.time_parity {
            TimeParity::Even => {}
            TimeParity::Odd => self.components = -self.components,
        }
        Ok(self)
    }
}

// ---------------------
// SymmetryTransformable
// ---------------------
impl<T> SymmetryTransformable for AxialVector3<T>
where
    T: ComplexFloat + Lapack,
    AxialVector3<T>: SpatialUnitaryTransformable + TimeReversalTransformable,
{
    fn sym_permute_sites_spatial(
        &self,
        _symop: &SymmetryOperation,
    ) -> Result<Permutation<usize>, TransformationError> {
        Permutation::from_image(vec![0]).map_err(|err| TransformationError(err.to_string()))
    }
}