1use std::fmt;
4use std::ops::Mul;
5
6use approx;
7use nalgebra::Vector3;
8use ndarray::{array, concatenate, s, Array2, Axis, LinalgScalar, ScalarOperand};
9use ndarray_linalg::types::Lapack;
10use num_complex::{Complex, ComplexFloat};
11
12use crate::angmom::spinor_rotation_3d::{SpinConstraint, SpinOrbitCoupled, StructureConstraint};
13use crate::permutation::{IntoPermutation, PermutableCollection, Permutation};
14use crate::symmetry::symmetry_element::symmetry_operation::SpecialSymmetryTransformation;
15use crate::symmetry::symmetry_element::{RotationGroup, SymmetryElement, SymmetryOperation, TRROT};
16use crate::symmetry::symmetry_element_order::ElementOrder;
17use crate::symmetry::symmetry_transformation::{
18 assemble_sh_rotation_3d_matrices, assemble_spinor_rotation_matrices, permute_array_by_atoms,
19 ComplexConjugationTransformable, DefaultTimeReversalTransformable, SpatialUnitaryTransformable,
20 SpinUnitaryTransformable, SymmetryTransformable, TimeReversalTransformable,
21 TransformationError,
22};
23use crate::target::determinant::SlaterDeterminant;
24
25impl<'a, T> SpatialUnitaryTransformable for SlaterDeterminant<'a, T, SpinConstraint>
33where
34 T: ComplexFloat + LinalgScalar + ScalarOperand + Copy + Lapack,
35 f64: Into<T>,
36{
37 fn transform_spatial_mut(
38 &mut self,
39 rmat: &Array2<f64>,
40 perm: Option<&Permutation<usize>>,
41 ) -> Result<&mut Self, TransformationError> {
42 let tmats: Vec<Array2<T>> = assemble_sh_rotation_3d_matrices(self.bao, rmat, perm)
43 .map_err(|err| TransformationError(err.to_string()))?
44 .iter()
45 .map(|tmat| tmat.map(|&x| x.into()))
46 .collect();
47 let pbao = if let Some(p) = perm {
48 self.bao
49 .permute(p)
50 .map_err(|err| TransformationError(err.to_string()))?
51 } else {
52 self.bao.clone()
53 };
54 let new_coefficients = self
55 .coefficients
56 .iter()
57 .map(|old_coeff| match self.structure_constraint {
58 SpinConstraint::Restricted(_) | SpinConstraint::Unrestricted(_, _) => {
59 let p_coeff = if let Some(p) = perm {
60 permute_array_by_atoms(old_coeff, p, &[Axis(0)], self.bao)
61 } else {
62 old_coeff.clone()
63 };
64 let t_p_blocks = pbao
65 .shell_boundary_indices()
66 .into_iter()
67 .zip(tmats.iter())
68 .map(|((shl_start, shl_end), tmat)| {
69 tmat.dot(&p_coeff.slice(s![shl_start..shl_end, ..]))
70 })
71 .collect::<Vec<_>>();
72 concatenate(
73 Axis(0),
74 &t_p_blocks.iter().map(|t_p_block| t_p_block.view()).collect::<Vec<_>>(),
75 )
76 .expect("Unable to concatenate the transformed rows for the various shells.")
77 }
78 SpinConstraint::Generalised(nspins, _) => {
79 let nspatial = self.bao.n_funcs();
80 let t_p_spin_blocks = (0..nspins).map(|ispin| {
81 let spin_start = usize::from(ispin) * nspatial;
83 let spin_end = (usize::from(ispin) + 1) * nspatial;
84 let spin_block = old_coeff.slice(s![spin_start..spin_end, ..]).to_owned();
85
86 let p_spin_block = if let Some(p) = perm {
88 permute_array_by_atoms(&spin_block, p, &[Axis(0)], self.bao)
89 } else {
90 spin_block
91 };
92
93 let t_p_blocks = pbao
95 .shell_boundary_indices()
96 .into_iter()
97 .zip(tmats.iter())
98 .map(|((shl_start, shl_end), tmat)| {
99 tmat.dot(&p_spin_block.slice(s![shl_start..shl_end, ..]))
100 })
101 .collect::<Vec<_>>();
102
103 concatenate(
105 Axis(0),
106 &t_p_blocks.iter().map(|t_p_block| t_p_block.view()).collect::<Vec<_>>(),
107 )
108 .expect("Unable to concatenate the transformed rows for the various shells.")
109 }).collect::<Vec<_>>();
110
111 concatenate(
113 Axis(0),
114 &t_p_spin_blocks
115 .iter()
116 .map(|t_p_spin_block| t_p_spin_block.view())
117 .collect::<Vec<_>>(),
118 )
119 .expect("Unable to concatenate the transformed spin blocks.")
120 }
121 })
122 .collect::<Vec<Array2<T>>>();
123 self.coefficients = new_coefficients;
124 Ok(self)
125 }
126}
127
128impl<'a> SpinUnitaryTransformable for SlaterDeterminant<'a, f64, SpinConstraint> {
137 fn transform_spin_mut(
144 &mut self,
145 dmat: &Array2<Complex<f64>>,
146 ) -> Result<&mut Self, TransformationError> {
147 let cdmat = dmat.view().split_complex();
148 if approx::relative_ne!(
149 cdmat.im.map(|x| x.powi(2)).sum().sqrt(),
150 0.0,
151 epsilon = 1e-14,
152 max_relative = 1e-14,
153 ) {
154 log::error!("Spin transformation matrix is complex-valued:\n{dmat}");
155 Err(TransformationError(
156 "Complex spin transformations cannot be performed with real coefficients."
157 .to_string(),
158 ))
159 } else {
160 let rdmat = cdmat.re.to_owned();
161 match self.structure_constraint {
162 SpinConstraint::Restricted(_) => {
163 if approx::relative_eq!(
164 (&rdmat - Array2::<f64>::eye(2))
165 .map(|x| x.abs().powi(2))
166 .sum()
167 .sqrt(),
168 0.0,
169 epsilon = 1e-14,
170 max_relative = 1e-14,
171 ) {
172 Ok(self)
174 } else if approx::relative_eq!(
175 (&rdmat + Array2::<f64>::eye(2))
176 .map(|x| x.abs().powi(2))
177 .sum()
178 .sqrt(),
179 0.0,
180 epsilon = 1e-14,
181 max_relative = 1e-14,
182 ) {
183 self.coefficients
185 .iter_mut()
186 .for_each(|coeff| *coeff *= -1.0);
187 Ok(self)
188 } else {
189 log::error!("Unsupported spin transformation matrix:\n{}", &rdmat);
190 Err(TransformationError(
191 "Only the identity or negative identity spin transformations are possible with restricted spin constraint."
192 .to_string(),
193 ))
194 }
195 }
196 SpinConstraint::Unrestricted(nspins, increasingm) => {
197 if nspins != 2 {
200 return Err(TransformationError(
201 "Only two-component spinor transformations are supported for now."
202 .to_string(),
203 ));
204 }
205 let dmat_y = array![[0.0, -1.0], [1.0, 0.0]];
206 if approx::relative_eq!(
207 (&rdmat - Array2::<f64>::eye(2))
208 .map(|x| x.abs().powi(2))
209 .sum()
210 .sqrt(),
211 0.0,
212 epsilon = 1e-14,
213 max_relative = 1e-14,
214 ) {
215 Ok(self)
217 } else if approx::relative_eq!(
218 (&rdmat + Array2::<f64>::eye(2))
219 .map(|x| x.abs().powi(2))
220 .sum()
221 .sqrt(),
222 0.0,
223 epsilon = 1e-14,
224 max_relative = 1e-14,
225 ) {
226 self.coefficients
228 .iter_mut()
229 .for_each(|coeff| *coeff = -coeff.clone());
230 Ok(self)
231 } else if approx::relative_eq!(
232 (&rdmat - &dmat_y).map(|x| x.abs().powi(2)).sum().sqrt(),
233 0.0,
234 epsilon = 1e-14,
235 max_relative = 1e-14,
236 ) {
237 let new_coefficients = if increasingm {
239 vec![self.coefficients[1].clone(), -self.coefficients[0].clone()]
240 } else {
241 vec![-self.coefficients[1].clone(), self.coefficients[0].clone()]
242 };
243 let new_occupations =
244 vec![self.occupations[1].clone(), self.occupations[0].clone()];
245 self.coefficients = new_coefficients;
246 self.occupations = new_occupations;
247 Ok(self)
248 } else if approx::relative_eq!(
249 (&rdmat + &dmat_y).map(|x| x.abs().powi(2)).sum().sqrt(),
250 0.0,
251 epsilon = 1e-14,
252 max_relative = 1e-14,
253 ) {
254 let new_coefficients = if increasingm {
256 vec![-self.coefficients[1].clone(), self.coefficients[0].clone()]
257 } else {
258 vec![self.coefficients[1].clone(), -self.coefficients[0].clone()]
259 };
260 let new_occupations =
261 vec![self.occupations[1].clone(), self.occupations[0].clone()];
262 self.coefficients = new_coefficients;
263 self.occupations = new_occupations;
264 Ok(self)
265 } else {
266 log::error!("Unsupported spin transformation matrix:\n{rdmat}");
267 Err(TransformationError(
268 "Only the identity or πy spin transformations are possible with unrestricted spin constraint."
269 .to_string(),
270 ))
271 }
272 }
273 SpinConstraint::Generalised(nspins, increasingm) => {
274 if nspins != 2 {
275 return Err(TransformationError(
276 "Only two-component spinor transformations are supported for now."
277 .to_string(),
278 ));
279 }
280
281 let nspatial = self.bao.n_funcs();
282 let new_coefficients = self
283 .coefficients
284 .iter()
285 .map(|old_coeff| {
286 if !increasingm {
287 let a_coeff = old_coeff.slice(s![0..nspatial, ..]).to_owned();
288 let b_coeff = old_coeff.slice(s![nspatial..2 * nspatial, ..]).to_owned();
289 let t_a_coeff = &a_coeff * rdmat[[0, 0]] + &b_coeff * rdmat[[0, 1]];
290 let t_b_coeff = &a_coeff * rdmat[[1, 0]] + &b_coeff * rdmat[[1, 1]];
291 concatenate(Axis(0), &[t_a_coeff.view(), t_b_coeff.view()]).expect(
292 "Unable to concatenate the transformed rows for the various shells.",
293 )
294 } else {
295 let b_coeff = old_coeff.slice(s![0..nspatial, ..]).to_owned();
296 let a_coeff = old_coeff.slice(s![nspatial..2 * nspatial, ..]).to_owned();
297 let t_a_coeff = &a_coeff * rdmat[[0, 0]] + &b_coeff * rdmat[[0, 1]];
298 let t_b_coeff = &a_coeff * rdmat[[1, 0]] + &b_coeff * rdmat[[1, 1]];
299 concatenate(Axis(0), &[t_b_coeff.view(), t_a_coeff.view()]).expect(
300 "Unable to concatenate the transformed rows for the various shells.",
301 )
302 }
303 })
304 .collect::<Vec<Array2<f64>>>();
305 self.coefficients = new_coefficients;
306 Ok(self)
307 }
308 }
309 }
310 }
311}
312
313impl<'a, T> SpinUnitaryTransformable for SlaterDeterminant<'a, Complex<T>, SpinConstraint>
318where
319 T: Clone,
320 Complex<T>: ComplexFloat<Real = T>
321 + LinalgScalar
322 + ScalarOperand
323 + Lapack
324 + Mul<Complex<T>, Output = Complex<T>>
325 + Mul<Complex<f64>, Output = Complex<T>>,
326{
327 fn transform_spin_mut(
339 &mut self,
340 dmat: &Array2<Complex<f64>>,
341 ) -> Result<&mut Self, TransformationError> {
342 match self.structure_constraint {
343 SpinConstraint::Restricted(_) => {
344 if approx::relative_eq!(
345 (dmat - Array2::<Complex<f64>>::eye(2))
346 .map(|x| x.abs().powi(2))
347 .sum()
348 .sqrt(),
349 0.0,
350 epsilon = 1e-14,
351 max_relative = 1e-14,
352 ) {
353 Ok(self)
355 } else if approx::relative_eq!(
356 (dmat + Array2::<Complex<f64>>::eye(2))
357 .map(|x| x.abs().powi(2))
358 .sum()
359 .sqrt(),
360 0.0,
361 epsilon = 1e-14,
362 max_relative = 1e-14,
363 ) {
364 self.coefficients
366 .iter_mut()
367 .for_each(|coeff| *coeff = -coeff.clone());
368 Ok(self)
369 } else {
370 log::error!("Unsupported spin transformation matrix:\n{}", dmat);
371 Err(TransformationError(
372 "Only the identity or negative identity spin transformations are possible with restricted spin constraint."
373 .to_string(),
374 ))
375 }
376 }
377 SpinConstraint::Unrestricted(nspins, increasingm) => {
378 if nspins != 2 {
381 return Err(TransformationError(
382 "Only two-component spinor transformations are supported for now."
383 .to_string(),
384 ));
385 }
386 let dmat_y = array![
387 [Complex::from(0.0), Complex::from(-1.0)],
388 [Complex::from(1.0), Complex::from(0.0)],
389 ];
390 if approx::relative_eq!(
391 (dmat - Array2::<Complex<f64>>::eye(2))
392 .map(|x| x.abs().powi(2))
393 .sum()
394 .sqrt(),
395 0.0,
396 epsilon = 1e-14,
397 max_relative = 1e-14,
398 ) {
399 Ok(self)
401 } else if approx::relative_eq!(
402 (dmat + Array2::<Complex<f64>>::eye(2))
403 .map(|x| x.abs().powi(2))
404 .sum()
405 .sqrt(),
406 0.0,
407 epsilon = 1e-14,
408 max_relative = 1e-14,
409 ) {
410 self.coefficients
412 .iter_mut()
413 .for_each(|coeff| *coeff = -coeff.clone());
414 Ok(self)
415 } else if approx::relative_eq!(
416 (dmat - &dmat_y).map(|x| x.abs().powi(2)).sum().sqrt(),
417 0.0,
418 epsilon = 1e-14,
419 max_relative = 1e-14,
420 ) {
421 let new_coefficients = if increasingm {
423 vec![self.coefficients[1].clone(), -self.coefficients[0].clone()]
424 } else {
425 vec![-self.coefficients[1].clone(), self.coefficients[0].clone()]
426 };
427 let new_occupations =
428 vec![self.occupations[1].clone(), self.occupations[0].clone()];
429 self.coefficients = new_coefficients;
430 self.occupations = new_occupations;
431 Ok(self)
432 } else if approx::relative_eq!(
433 (dmat + &dmat_y).map(|x| x.abs().powi(2)).sum().sqrt(),
434 0.0,
435 epsilon = 1e-14,
436 max_relative = 1e-14,
437 ) {
438 let new_coefficients = if increasingm {
440 vec![-self.coefficients[1].clone(), self.coefficients[0].clone()]
441 } else {
442 vec![self.coefficients[1].clone(), -self.coefficients[0].clone()]
443 };
444 let new_occupations =
445 vec![self.occupations[1].clone(), self.occupations[0].clone()];
446 self.coefficients = new_coefficients;
447 self.occupations = new_occupations;
448 Ok(self)
449 } else {
450 log::error!("Unsupported spin transformation matrix:\n{dmat}");
451 Err(TransformationError(
452 "Only the identity or πy spin transformations are possible with unrestricted spin constraint."
453 .to_string(),
454 ))
455 }
456 }
457 SpinConstraint::Generalised(nspins, increasingm) => {
458 if nspins != 2 {
459 panic!("Only two-component spinor transformations are supported for now.");
460 }
461
462 let nspatial = self.bao.n_funcs();
463
464 let new_coefficients = self
465 .coefficients
466 .iter()
467 .map(|old_coeff| {
468 if increasingm {
469 let b_coeff = old_coeff.slice(s![0..nspatial, ..]).to_owned();
470 let a_coeff = old_coeff.slice(s![nspatial..2 * nspatial, ..]).to_owned();
471 let t_a_coeff = &a_coeff * dmat[[0, 0]] + &b_coeff * dmat[[0, 1]];
472 let t_b_coeff = &a_coeff * dmat[[1, 0]] + &b_coeff * dmat[[1, 1]];
473 concatenate(Axis(0), &[t_b_coeff.view(), t_a_coeff.view()]).expect(
474 "Unable to concatenate the transformed rows for the various shells.",
475 )
476 } else {
477 let a_coeff = old_coeff.slice(s![0..nspatial, ..]).to_owned();
478 let b_coeff = old_coeff.slice(s![nspatial..2 * nspatial, ..]).to_owned();
479 let t_a_coeff = &a_coeff * dmat[[0, 0]] + &b_coeff * dmat[[0, 1]];
480 let t_b_coeff = &a_coeff * dmat[[1, 0]] + &b_coeff * dmat[[1, 1]];
481 concatenate(Axis(0), &[t_a_coeff.view(), t_b_coeff.view()]).expect(
482 "Unable to concatenate the transformed rows for the various shells.",
483 )
484 }
485 })
486 .collect::<Vec<Array2<Complex<T>>>>();
487 self.coefficients = new_coefficients;
488 Ok(self)
489 }
490 }
491 }
492}
493
494impl<'a, T> DefaultTimeReversalTransformable for SlaterDeterminant<'a, T, SpinConstraint> where
498 T: ComplexFloat + Lapack
499{
500}
501
502impl<'a, T> SymmetryTransformable for SlaterDeterminant<'a, T, SpinConstraint>
506where
507 T: ComplexFloat + Lapack,
508 SlaterDeterminant<'a, T, SpinConstraint>:
509 SpatialUnitaryTransformable + SpinUnitaryTransformable + TimeReversalTransformable,
510{
511 fn sym_permute_sites_spatial(
512 &self,
513 symop: &SymmetryOperation,
514 ) -> Result<Permutation<usize>, TransformationError> {
515 if (symop.generating_element.threshold().log10() - self.mol.threshold.log10()).abs() >= 3.0
516 {
517 log::warn!(
518 "Symmetry operation threshold ({:.3e}) and molecule threshold ({:.3e}) \
519 differ by more than three orders of magnitudes.",
520 symop.generating_element.threshold(),
521 self.mol.threshold
522 )
523 }
524 symop
525 .act_permute(&self.mol.molecule_ordinary_atoms())
526 .ok_or(TransformationError(format!(
527 "Unable to determine the atom permutation corresponding to the operation `{symop}`.",
528 )))
529 }
530}
531
532impl<'a, T> SpatialUnitaryTransformable for SlaterDeterminant<'a, T, SpinOrbitCoupled>
540where
541 T: ComplexFloat + Lapack,
542{
543 fn transform_spatial_mut(
544 &mut self,
545 _rmat: &Array2<f64>,
546 _perm: Option<&Permutation<usize>>,
547 ) -> Result<&mut Self, TransformationError> {
548 Err(TransformationError(
549 "Unable to apply only spatial transformations to a spin--orbit-coupled determinant."
550 .to_string(),
551 ))
552 }
553}
554
555impl<'a, T> SpinUnitaryTransformable for SlaterDeterminant<'a, T, SpinOrbitCoupled>
559where
560 T: ComplexFloat + Lapack,
561{
562 fn transform_spin_mut(
563 &mut self,
564 _dmat: &Array2<Complex<f64>>,
565 ) -> Result<&mut Self, TransformationError> {
566 Err(TransformationError(
567 "Unable to apply only spin transformations to a spin--orbit-coupled determinant."
568 .to_string(),
569 ))
570 }
571}
572
573impl<'a> TimeReversalTransformable for SlaterDeterminant<'a, Complex<f64>, SpinOrbitCoupled> {
577 fn transform_timerev_mut(&mut self) -> Result<&mut Self, TransformationError> {
578 let t_element = SymmetryElement::builder()
579 .threshold(1e-12)
580 .proper_order(ElementOrder::Int(1))
581 .proper_power(1)
582 .raw_axis(Vector3::new(0.0, 0.0, 1.0))
583 .kind(TRROT)
584 .rotation_group(RotationGroup::SU2(true))
585 .build()
586 .unwrap();
587 let t = SymmetryOperation::builder()
588 .generating_element(t_element)
589 .power(1)
590 .build()
591 .unwrap();
592 let tmats: Vec<Array2<Complex<f64>>> =
593 assemble_spinor_rotation_matrices(self.bao, &t, None)
594 .map_err(|err| TransformationError(err.to_string()))?
595 .iter()
596 .map(|tmat| tmat.map(|&x| x.into()))
597 .collect();
598
599 let new_coefficients = self
600 .coefficients
601 .iter()
602 .map(|old_coeff| match self.structure_constraint {
603 SpinOrbitCoupled::JAdapted(ncomps) => {
604 let nfuncs_per_comp = self.bao.n_funcs();
605 let t_comp_blocks = (0..ncomps).map(|icomp| {
606 let comp_start = usize::from(icomp) * nfuncs_per_comp;
608 let comp_end = (usize::from(icomp) + 1) * nfuncs_per_comp;
609 let comp_block = old_coeff.slice(s![comp_start..comp_end, ..]).to_owned();
610
611 let t_blocks = self.bao
613 .shell_boundary_indices()
614 .iter()
615 .zip(tmats.iter())
616 .map(|((shl_start, shl_end), tmat)| {
617 tmat.dot(&comp_block.slice(s![*shl_start..*shl_end, ..]))
618 })
619 .collect::<Vec<_>>();
620
621 concatenate(
623 Axis(0),
624 &t_blocks.iter().map(|t_block| t_block.view()).collect::<Vec<_>>(),
625 )
626 .expect("Unable to concatenate the transformed rows for the various shells.")
627 }).collect::<Vec<_>>();
628
629 concatenate(
631 Axis(0),
632 &t_comp_blocks
633 .iter()
634 .map(|t_spin_block| t_spin_block.view())
635 .collect::<Vec<_>>(),
636 )
637 .expect("Unable to concatenate the transformed component blocks.")
638 }
639 })
640 .collect::<Vec<Array2<Complex<f64>>>>();
641 self.coefficients = new_coefficients;
642
643 self.transform_cc_mut()?;
644 Ok(self)
645 }
646}
647
648impl<'a> SymmetryTransformable for SlaterDeterminant<'a, Complex<f64>, SpinOrbitCoupled> {
652 fn sym_permute_sites_spatial(
656 &self,
657 symop: &SymmetryOperation,
658 ) -> Result<Permutation<usize>, TransformationError> {
659 if (symop.generating_element.threshold().log10() - self.mol.threshold.log10()).abs() >= 3.0
660 {
661 log::warn!(
662 "Symmetry operation threshold ({:.3e}) and molecule threshold ({:.3e}) \
663 differ by more than three orders of magnitudes.",
664 symop.generating_element.threshold(),
665 self.mol.threshold
666 )
667 }
668 symop
669 .act_permute(&self.mol.molecule_ordinary_atoms())
670 .ok_or(TransformationError(format!(
671 "Unable to determine the atom permutation corresponding to the operation `{symop}`.",
672 )))
673 }
674
675 fn sym_transform_spin_spatial_mut(
679 &mut self,
680 symop: &SymmetryOperation,
681 ) -> Result<&mut Self, TransformationError> {
682 let perm = self.sym_permute_sites_spatial(symop)?;
683 let pbao = self
684 .bao
685 .permute(&perm)
686 .map_err(|err| TransformationError(err.to_string()))?;
687
688 let tmats: Vec<Array2<Complex<f64>>> =
689 assemble_spinor_rotation_matrices(&pbao, symop, Some(&perm))
690 .map_err(|err| TransformationError(err.to_string()))?
691 .iter()
692 .map(|tmat| tmat.map(|&x| x.into()))
693 .collect();
694
695 if symop.contains_time_reversal() {
697 self.transform_cc_mut()?;
702 }
703
704 let new_coefficients = self
705 .coefficients
706 .iter()
707 .map(|old_coeff| match self.structure_constraint {
708 SpinOrbitCoupled::JAdapted(ncomps) => {
709 let nfuncs_per_comp = self.bao.n_funcs();
710 let t_p_comp_blocks = (0..ncomps).map(|icomp| {
711 let comp_start = usize::from(icomp) * nfuncs_per_comp;
713 let comp_end = (usize::from(icomp) + 1) * nfuncs_per_comp;
714 let comp_block = old_coeff.slice(s![comp_start..comp_end, ..]).to_owned();
715
716 let p_comp_block = permute_array_by_atoms(&comp_block, &perm, &[Axis(0)], self.bao);
718
719 let t_p_blocks = pbao
721 .shell_boundary_indices()
722 .into_iter()
723 .zip(tmats.iter())
724 .map(|((shl_start, shl_end), tmat)| {
725 tmat.dot(&p_comp_block.slice(s![shl_start..shl_end, ..]))
726 })
727 .collect::<Vec<_>>();
728
729 concatenate(
731 Axis(0),
732 &t_p_blocks.iter().map(|t_p_block| t_p_block.view()).collect::<Vec<_>>(),
733 )
734 .expect("Unable to concatenate the transformed rows for the various shells.")
735 }).collect::<Vec<_>>();
736
737 concatenate(
739 Axis(0),
740 &t_p_comp_blocks
741 .iter()
742 .map(|t_p_comp_block| t_p_comp_block.view())
743 .collect::<Vec<_>>(),
744 )
745 .expect("Unable to concatenate the transformed comp blocks.")
746 }
747 })
748 .collect::<Vec<Array2<Complex<f64>>>>();
749 self.coefficients = new_coefficients;
750
751 Ok(self)
752 }
753}
754
755impl<'a, T, SC> ComplexConjugationTransformable for SlaterDeterminant<'a, T, SC>
764where
765 T: ComplexFloat + Lapack,
766 SC: StructureConstraint + Clone + fmt::Display,
767{
768 fn transform_cc_mut(&mut self) -> Result<&mut Self, TransformationError> {
770 self.coefficients
771 .iter_mut()
772 .for_each(|coeff| coeff.mapv_inplace(|x| x.conj()));
773 self.complex_conjugated = !self.complex_conjugated;
774 Ok(self)
775 }
776}