1use std::fmt;
4use std::ops::Mul;
5
6use anyhow::{self, Context, ensure, format_err};
7use approx;
8use derive_builder::Builder;
9use itertools::{Itertools, izip};
10use log;
11use ndarray::{Array1, Array2, Axis, Ix2, s};
12use ndarray_linalg::{
13 UPLO,
14 eig::Eig,
15 eigh::Eigh,
16 solve::Determinant,
17 types::{Lapack, Scalar},
18};
19use num_complex::{Complex, ComplexFloat};
20use num_traits::{Float, ToPrimitive, Zero};
21
22use crate::analysis::{
23 EigenvalueComparisonMode, Orbit, OrbitIterator, Overlap, RepAnalysis, fn_calc_xmat_complex,
24 fn_calc_xmat_real,
25};
26use crate::angmom::spinor_rotation_3d::StructureConstraint;
27use crate::auxiliary::misc::{ProductRepeat, complex_modified_gram_schmidt};
28use crate::chartab::chartab_group::CharacterProperties;
29use crate::chartab::{DecompositionError, SubspaceDecomposable};
30use crate::group::GroupType;
31use crate::symmetry::symmetry_element::symmetry_operation::SpecialSymmetryTransformation;
32use crate::symmetry::symmetry_group::SymmetryGroupProperties;
33use crate::symmetry::symmetry_transformation::{SymmetryTransformable, SymmetryTransformationKind};
34use crate::target::determinant::SlaterDeterminant;
35use crate::target::determinant::determinant_analysis::SlaterDeterminantSymmetryOrbit;
36use crate::target::orbital::MolecularOrbital;
37
38impl<'a, T, SC> Overlap<T, Ix2> for MolecularOrbital<'a, T, SC>
43where
44 T: Lapack
45 + ComplexFloat<Real = <T as Scalar>::Real>
46 + fmt::Debug
47 + Mul<<T as ComplexFloat>::Real, Output = T>,
48 <T as ComplexFloat>::Real: fmt::Debug
49 + approx::RelativeEq<<T as ComplexFloat>::Real>
50 + approx::AbsDiffEq<Epsilon = <T as Scalar>::Real>,
51 SC: StructureConstraint + Eq + fmt::Display,
52{
53 fn complex_symmetric(&self) -> bool {
54 self.complex_symmetric
55 }
56
57 fn overlap(
66 &self,
67 other: &Self,
68 metric: Option<&Array2<T>>,
69 metric_h: Option<&Array2<T>>,
70 ) -> Result<T, anyhow::Error> {
71 ensure!(
72 self.structure_constraint == other.structure_constraint,
73 "Inconsistent spin constraints between `self` and `other`."
74 );
75 ensure!(
76 self.coefficients.len() == other.coefficients.len(),
77 "Inconsistent numbers of coefficient matrices between `self` and `other`."
78 );
79
80 let sao = metric.ok_or_else(|| format_err!("No atomic-orbital metric found."))?;
81 let sao_h = metric_h.unwrap_or(sao);
82 let ov = if self.component_index != other.component_index {
83 T::zero()
84 } else if self.complex_symmetric() {
85 match (self.complex_conjugated, other.complex_conjugated) {
86 (false, false) => self.coefficients.t().dot(sao_h).dot(&other.coefficients),
87 (true, false) => self.coefficients.t().dot(sao).dot(&other.coefficients),
88 (false, true) => other.coefficients.t().dot(sao).dot(&self.coefficients),
89 (true, true) => self
90 .coefficients
91 .t()
92 .dot(&sao_h.t())
93 .dot(&other.coefficients),
94 }
95 } else {
96 match (self.complex_conjugated, other.complex_conjugated) {
97 (false, false) => self
98 .coefficients
99 .t()
100 .mapv(|x| x.conj()) .dot(sao)
102 .dot(&other.coefficients),
103 (true, false) => self
104 .coefficients
105 .t()
106 .mapv(|x| x.conj()) .dot(sao_h)
108 .dot(&other.coefficients),
109 (false, true) => other
110 .coefficients
111 .t()
112 .mapv(|x| x.conj()) .dot(sao_h)
114 .dot(&self.coefficients)
115 .conj(),
116 (true, true) => self
117 .coefficients
118 .t()
119 .mapv(|x| x.conj()) .dot(&sao.t())
121 .dot(&other.coefficients),
122 }
123 };
124 Ok(ov)
125 }
126
127 fn overlap_definition(&self) -> String {
129 let k = if self.complex_symmetric() { "κ " } else { "" };
130 format!("⟨{k}ψ_1|ψ_2⟩ = ∫ [{k}ψ_1(x)]* ψ_2(x) dx")
131 }
132}
133
134#[derive(Builder, Clone)]
145pub struct MolecularOrbitalSymmetryOrbit<'a, G, T, SC>
146where
147 G: SymmetryGroupProperties,
148 T: ComplexFloat + fmt::Debug + Lapack,
149 SC: StructureConstraint + fmt::Display,
150 MolecularOrbital<'a, T, SC>: SymmetryTransformable,
151{
152 group: &'a G,
154
155 origin: &'a MolecularOrbital<'a, T, SC>,
157
158 integrality_threshold: <T as ComplexFloat>::Real,
161
162 pub(crate) linear_independence_threshold: <T as ComplexFloat>::Real,
164
165 orbit_overlap_symmetry_threshold: <T as ComplexFloat>::Real,
167
168 symmetry_transformation_kind: SymmetryTransformationKind,
171
172 #[builder(setter(skip), default = "None")]
174 smat: Option<Array2<T>>,
175
176 #[builder(setter(skip), default = "None")]
179 pub(crate) smat_eigvals: Option<Array1<T>>,
180
181 #[builder(setter(skip), default = "None")]
186 xmat: Option<Array2<T>>,
187
188 pub(crate) eigenvalue_comparison_mode: EigenvalueComparisonMode,
191}
192
193impl<'a, G, T, SC> MolecularOrbitalSymmetryOrbit<'a, G, T, SC>
198where
199 G: SymmetryGroupProperties + Clone,
200 T: ComplexFloat + fmt::Debug + Lapack,
201 SC: StructureConstraint + Clone + fmt::Display,
202 MolecularOrbital<'a, T, SC>: SymmetryTransformable,
203{
204 pub fn builder() -> MolecularOrbitalSymmetryOrbitBuilder<'a, G, T, SC> {
206 MolecularOrbitalSymmetryOrbitBuilder::default()
207 }
208
209 pub fn from_orbitals(
224 group: &'a G,
225 orbitals: &'a [Vec<MolecularOrbital<'a, T, SC>>],
226 sym_kind: SymmetryTransformationKind,
227 eig_comp_mode: EigenvalueComparisonMode,
228 integrality_thresh: <T as ComplexFloat>::Real,
229 linear_independence_thresh: <T as ComplexFloat>::Real,
230 orbit_overlap_symmetry_threshold: <T as ComplexFloat>::Real,
231 ) -> Vec<Vec<Self>> {
232 orbitals
233 .iter()
234 .map(|orbs_spin| {
235 orbs_spin
236 .iter()
237 .map(|orb| {
238 MolecularOrbitalSymmetryOrbit::builder()
239 .group(group)
240 .origin(orb)
241 .integrality_threshold(integrality_thresh)
242 .linear_independence_threshold(linear_independence_thresh)
243 .orbit_overlap_symmetry_threshold(orbit_overlap_symmetry_threshold)
244 .symmetry_transformation_kind(sym_kind.clone())
245 .eigenvalue_comparison_mode(eig_comp_mode.clone())
246 .build()
247 .expect("Unable to construct a molecular orbital symmetry orbit.")
248 })
249 .collect_vec()
250 })
251 .collect_vec()
252 }
253}
254
255impl<'a, G, SC> MolecularOrbitalSymmetryOrbit<'a, G, f64, SC>
256where
257 G: SymmetryGroupProperties,
258 SC: StructureConstraint + fmt::Display,
259 MolecularOrbital<'a, f64, SC>: SymmetryTransformable,
260{
261 fn_calc_xmat_real!(
262 pub calc_xmat
274 );
275}
276
277impl<'a, G, T, SC> MolecularOrbitalSymmetryOrbit<'a, G, Complex<T>, SC>
278where
279 G: SymmetryGroupProperties,
280 T: Float + Scalar<Complex = Complex<T>>,
281 Complex<T>: ComplexFloat<Real = T> + Scalar<Real = T, Complex = Complex<T>> + Lapack,
282 SC: StructureConstraint + fmt::Display,
283 MolecularOrbital<'a, Complex<T>, SC>: SymmetryTransformable + Overlap<Complex<T>, Ix2>,
284{
285 fn_calc_xmat_complex!(
286 pub calc_xmat
298 );
299}
300
301impl<'a, G, T, SC> Orbit<G, MolecularOrbital<'a, T, SC>>
310 for MolecularOrbitalSymmetryOrbit<'a, G, T, SC>
311where
312 G: SymmetryGroupProperties,
313 T: ComplexFloat + fmt::Debug + Lapack,
314 SC: StructureConstraint + fmt::Display,
315 MolecularOrbital<'a, T, SC>: SymmetryTransformable,
316{
317 type OrbitIter = OrbitIterator<'a, G, MolecularOrbital<'a, T, SC>>;
318
319 fn group(&self) -> &G {
320 self.group
321 }
322
323 fn origin(&self) -> &MolecularOrbital<'a, T, SC> {
324 self.origin
325 }
326
327 fn iter(&self) -> Self::OrbitIter {
328 OrbitIterator::new(
329 self.group,
330 self.origin,
331 match self.symmetry_transformation_kind {
332 SymmetryTransformationKind::Spatial => |op, orb| {
333 orb.sym_transform_spatial(op).with_context(|| {
334 format!("Unable to apply `{op}` spatially on the origin orbital")
335 })
336 },
337 SymmetryTransformationKind::SpatialWithSpinTimeReversal => |op, orb| {
338 orb.sym_transform_spatial_with_spintimerev(op).with_context(|| {
339 format!("Unable to apply `{op}` spatially (with spin-including time reversal) on the origin orbital")
340 })
341 },
342 SymmetryTransformationKind::Spin => |op, orb| {
343 orb.sym_transform_spin(op).with_context(|| {
344 format!("Unable to apply `{op}` spin-wise on the origin orbital")
345 })
346 },
347 SymmetryTransformationKind::SpinSpatial => |op, orb| {
348 orb.sym_transform_spin_spatial(op).with_context(|| {
349 format!("Unable to apply `{op}` spin-spatially on the origin orbital",)
350 })
351 },
352 },
353 )
354 }
355}
356
357impl<'a, G, T, SC> RepAnalysis<G, MolecularOrbital<'a, T, SC>, T, Ix2>
362 for MolecularOrbitalSymmetryOrbit<'a, G, T, SC>
363where
364 G: SymmetryGroupProperties,
365 G::CharTab: SubspaceDecomposable<T>,
366 T: Lapack
367 + ComplexFloat<Real = <T as Scalar>::Real>
368 + fmt::Debug
369 + Mul<<T as ComplexFloat>::Real, Output = T>,
370 <T as ComplexFloat>::Real: fmt::Debug
371 + Zero
372 + approx::RelativeEq<<T as ComplexFloat>::Real>
373 + approx::AbsDiffEq<Epsilon = <T as Scalar>::Real>,
374 SC: StructureConstraint + Eq + fmt::Display,
375 MolecularOrbital<'a, T, SC>: SymmetryTransformable,
376{
377 fn set_smat(&mut self, smat: Array2<T>) {
378 self.smat = Some(smat)
379 }
380
381 fn smat(&self) -> Option<&Array2<T>> {
382 self.smat.as_ref()
383 }
384
385 fn xmat(&self) -> &Array2<T> {
386 self.xmat
387 .as_ref()
388 .expect("Orbit overlap orthogonalisation matrix not found.")
389 }
390
391 fn norm_preserving_scalar_map(&self, i: usize) -> Result<fn(T) -> T, anyhow::Error> {
392 if self.origin.complex_symmetric {
393 Err(format_err!(
394 "`norm_preserving_scalar_map` is currently not implemented for complex-symmetric overlaps. This thus precludes the use of the Cayley table to speed up the computation of the orbit overlap matrix."
395 ))
396 } else if self
397 .group
398 .get_index(i)
399 .unwrap_or_else(|| panic!("Group operation index `{i}` not found."))
400 .contains_time_reversal()
401 {
402 Ok(ComplexFloat::conj)
403 } else {
404 Ok(|x| x)
405 }
406 }
407
408 fn orbit_overlap_symmetry_threshold(&self) -> <T as ComplexFloat>::Real {
409 self.orbit_overlap_symmetry_threshold
410 }
411
412 fn integrality_threshold(&self) -> <T as ComplexFloat>::Real {
413 self.integrality_threshold
414 }
415
416 fn eigenvalue_comparison_mode(&self) -> &EigenvalueComparisonMode {
417 &self.eigenvalue_comparison_mode
418 }
419
420 fn analyse_rep(
436 &self,
437 ) -> Result<
438 <<G as CharacterProperties>::CharTab as SubspaceDecomposable<T>>::Decomposition,
439 DecompositionError,
440 > {
441 let (valid_symmetry, err_str) = match self.symmetry_transformation_kind {
443 SymmetryTransformationKind::Spatial => (true, String::new()),
444 SymmetryTransformationKind::SpatialWithSpinTimeReversal
445 | SymmetryTransformationKind::Spin
446 | SymmetryTransformationKind::SpinSpatial => {
447 match self.group().group_type() {
448 GroupType::Ordinary(_) => (true, String::new()),
449 GroupType::MagneticGrey(_) | GroupType::MagneticBlackWhite(_) => {
450 (!self.group().unitary_represented(),
451 "Unitary-represented magnetic groups cannot be used for symmetry analysis of a one-electron molecular orbital where spin is treated explicitly.".to_string())
452 }
453 }
454 }
455 };
456 if valid_symmetry {
457 log::debug!("Analysing representation symmetry for an MO...");
458 let chis = self
459 .calc_characters()
460 .map_err(|err| DecompositionError(err.to_string()))?;
461 let res = self.group().character_table().reduce_characters(
462 &chis.iter().map(|(cc, chi)| (cc, *chi)).collect::<Vec<_>>(),
463 self.integrality_threshold(),
464 );
465 log::debug!("Analysing representation symmetry for an MO... Done.");
466 res
467 } else {
468 Err(DecompositionError(err_str))
469 }
470 }
471}
472
473#[allow(clippy::too_many_arguments, clippy::type_complexity)]
508pub fn generate_det_mo_orbits<'a, G, T, SC>(
509 det: &'a SlaterDeterminant<'a, T, SC>,
510 mos: &'a [Vec<MolecularOrbital<'a, T, SC>>],
511 group: &'a G,
512 metric: &Array2<T>,
513 metric_h: Option<&Array2<T>>,
514 integrality_threshold: <T as ComplexFloat>::Real,
515 linear_independence_threshold: <T as ComplexFloat>::Real,
516 orbit_overlap_symmetry_threshold: <T as ComplexFloat>::Real,
517 symmetry_transformation_kind: SymmetryTransformationKind,
518 eigenvalue_comparison_mode: EigenvalueComparisonMode,
519 use_cayley_table: bool,
520) -> Result<
521 (
522 SlaterDeterminantSymmetryOrbit<'a, 'a, G, T, SC>,
523 Vec<Vec<MolecularOrbitalSymmetryOrbit<'a, G, T, SC>>>,
524 ),
525 anyhow::Error,
526>
527where
528 G: SymmetryGroupProperties + Clone,
529 G::CharTab: SubspaceDecomposable<T>,
530 T: Lapack
531 + ComplexFloat<Real = <T as Scalar>::Real>
532 + fmt::Debug
533 + Mul<<T as ComplexFloat>::Real, Output = T>,
534 <T as ComplexFloat>::Real: fmt::Debug
535 + Zero
536 + From<u16>
537 + ToPrimitive
538 + approx::RelativeEq<<T as ComplexFloat>::Real>
539 + approx::AbsDiffEq<Epsilon = <T as Scalar>::Real>,
540 SC: StructureConstraint + Clone + Eq + fmt::Display,
541 SlaterDeterminant<'a, T, SC>: SymmetryTransformable,
542 MolecularOrbital<'a, T, SC>: SymmetryTransformable,
543{
544 log::debug!("Constructing determinant and MO orbits in tandem...");
545 let order = group.order();
546 let mut det_orbit = SlaterDeterminantSymmetryOrbit::<G, T, SC>::builder()
547 .group(group)
548 .origin(det)
549 .integrality_threshold(integrality_threshold)
550 .linear_independence_threshold(linear_independence_threshold)
551 .orbit_overlap_symmetry_threshold(orbit_overlap_symmetry_threshold)
552 .symmetry_transformation_kind(symmetry_transformation_kind.clone())
553 .eigenvalue_comparison_mode(eigenvalue_comparison_mode.clone())
554 .build()
555 .map_err(|err| format_err!(err))?;
556 let mut mo_orbitss = MolecularOrbitalSymmetryOrbit::from_orbitals(
557 group,
558 mos,
559 symmetry_transformation_kind,
560 eigenvalue_comparison_mode,
561 integrality_threshold,
562 linear_independence_threshold,
563 orbit_overlap_symmetry_threshold
564 );
565
566 let mut det_smat = Array2::<T>::zeros((order, order));
567 let mut mo_smatss = mo_orbitss
568 .iter()
569 .map(|mo_orbits| {
570 mo_orbits
571 .iter()
572 .map(|_| Array2::<T>::zeros((order, order)))
573 .collect::<Vec<_>>()
574 })
575 .collect::<Vec<_>>();
576
577 let thresh = det.threshold();
578
579 let sao = metric;
580 let sao_h = metric_h.unwrap_or(sao);
581
582 if let (Some(ctb), true) = (group.cayley_table(), use_cayley_table) {
583 log::debug!(
584 "Cayley table available. Group closure will be used to speed up overlap matrix computation."
585 );
586 let mut det_smatw0 = Array1::<T>::zeros(order);
587 let mut mo_smatw0ss = mo_orbitss
588 .iter()
589 .map(|mo_orbits| {
590 mo_orbits
591 .iter()
592 .map(|_| Array1::<T>::zeros(order))
593 .collect::<Vec<_>>()
594 })
595 .collect::<Vec<_>>();
596 let det_0 = det_orbit.origin();
597 for (w, det_w_res) in det_orbit.iter().enumerate() {
598 let det_w = det_w_res?;
599 let w0_ov = izip!(
600 det_w.coefficients(),
601 det_w.occupations(),
602 det_0.coefficients(),
603 det_0.occupations(),
604 )
605 .enumerate()
606 .map(|(ispin, (cw, occw, c0, occ0))| {
607 let nonzero_occ_w = occw.iter().positions(|&occ| occ > thresh).collect_vec();
608 let nonzero_occ_0 = occ0.iter().positions(|&occ| occ > thresh).collect_vec();
609
610 let all_mo_w0_ov_mat = if det.complex_symmetric() {
611 match (det_w.complex_conjugated(), det_0.complex_conjugated()) {
612 (false, false) => cw.t().dot(sao_h).dot(c0),
613 (true, false) => cw.t().dot(sao).dot(c0),
614 (false, true) => c0.t().dot(sao).dot(cw),
615 (true, true) => cw.t().dot(&sao_h.t()).dot(c0),
616 }
617 } else {
618 match (det_w.complex_conjugated(), det_0.complex_conjugated()) {
619 (false, false) => cw.t().mapv(|x| x.conj()).dot(sao).dot(c0),
620 (true, false) => cw.t().mapv(|x| x.conj()).dot(sao_h).dot(c0),
621 (false, true) => c0
622 .t()
623 .mapv(|x| x.conj())
624 .dot(sao_h)
625 .dot(cw)
626 .mapv(|x| x.conj()),
627 (true, true) => cw.t().mapv(|x| x.conj()).dot(&sao.t()).dot(c0),
628 }
629 };
630
631 all_mo_w0_ov_mat
632 .diag()
633 .iter()
634 .enumerate()
635 .for_each(|(imo, mo_w0_ov)| {
636 mo_smatw0ss[ispin][imo][w] = *mo_w0_ov;
637 });
638
639 let occ_mo_w0_ov_mat = all_mo_w0_ov_mat
640 .select(Axis(0), &nonzero_occ_w)
641 .select(Axis(1), &nonzero_occ_0);
642
643 occ_mo_w0_ov_mat
644 .det()
645 .expect("The determinant of the MO overlap matrix `w0` could not be found.")
646 })
647 .fold(T::one(), |acc, x| acc * x);
648
649 let implicit_factor = det.structure_constraint().implicit_factor()?;
650 let w0_ov = if implicit_factor > 1 {
651 let p_i32 = i32::try_from(implicit_factor)?;
652 ComplexFloat::powi(w0_ov, p_i32)
653 } else {
654 w0_ov
655 };
656 det_smatw0[w] = w0_ov;
657 }
658
659 for (i, j) in (0..order).cartesian_product(0..order) {
660 let jinv = ctb
661 .slice(s![.., j])
662 .iter()
663 .position(|&x| x == 0)
664 .ok_or(format_err!(
665 "Unable to find the inverse of group element `{j}`."
666 ))?;
667 let jinv_i = ctb[(jinv, i)];
668
669 for (ispin, mo_smatw0s) in mo_smatw0ss.iter().enumerate() {
670 for (imo, mo_smat_w0) in mo_smatw0s.iter().enumerate() {
671 mo_smatss[ispin][imo][(i, j)] =
672 mo_orbitss[ispin][imo].norm_preserving_scalar_map(jinv)?(mo_smat_w0[jinv_i])
673 }
674 }
675
676 det_smat[(i, j)] = det_orbit.norm_preserving_scalar_map(jinv)?(det_smatw0[jinv_i]);
677 }
678 } else {
679 log::debug!(
680 "Cayley table not available or the use of Cayley table not requested. Overlap matrix will be constructed without group-closure speed-up."
681 );
682 let indexed_dets = det_orbit
683 .iter()
684 .map(|det_res| det_res.map_err(|err| err.to_string()))
685 .enumerate()
686 .collect::<Vec<_>>();
687 for det_pair in indexed_dets.iter().product_repeat(2) {
688 let (w, det_w_res) = &det_pair[0];
689 let (x, det_x_res) = &det_pair[1];
690 let det_w = det_w_res
691 .as_ref()
692 .map_err(|err| format_err!(err.to_owned()))
693 .with_context(|| "One of the determinants in the orbit is not available")?;
694 let det_x = det_x_res
695 .as_ref()
696 .map_err(|err| format_err!(err.to_owned()))
697 .with_context(|| "One of the determinants in the orbit is not available")?;
698
699 let wx_ov = izip!(
700 det_w.coefficients(),
701 det_w.occupations(),
702 det_x.coefficients(),
703 det_x.occupations(),
704 )
705 .enumerate()
706 .map(|(ispin, (cw, occw, cx, occx))| {
707 let nonzero_occ_w = occw.iter().positions(|&occ| occ > thresh).collect_vec();
708 let nonzero_occ_x = occx.iter().positions(|&occ| occ > thresh).collect_vec();
709
710 let all_mo_wx_ov_mat = if det.complex_symmetric() {
716 match (det_w.complex_conjugated(), det_x.complex_conjugated()) {
717 (false, false) => cw.t().dot(sao_h).dot(cx),
718 (true, false) => cw.t().dot(sao).dot(cx),
719 (false, true) => cx.t().dot(sao).dot(cw),
720 (true, true) => cw.t().dot(&sao_h.t()).dot(cx),
721 }
722 } else {
723 match (det_w.complex_conjugated(), det_x.complex_conjugated()) {
724 (false, false) => cw.t().mapv(|x| x.conj()).dot(sao).dot(cx),
725 (true, false) => cw.t().mapv(|x| x.conj()).dot(sao_h).dot(cx),
726 (false, true) => cx
727 .t()
728 .mapv(|x| x.conj())
729 .dot(sao_h)
730 .dot(cw)
731 .mapv(|x| x.conj()),
732 (true, true) => cw.t().mapv(|x| x.conj()).dot(&sao.t()).dot(cx),
733 }
734 };
735
736 all_mo_wx_ov_mat
737 .diag()
738 .iter()
739 .enumerate()
740 .for_each(|(imo, mo_wx_ov)| {
741 mo_smatss[ispin][imo][(*w, *x)] = *mo_wx_ov;
742 });
743
744 let occ_mo_wx_ov_mat = all_mo_wx_ov_mat
745 .select(Axis(0), &nonzero_occ_w)
746 .select(Axis(1), &nonzero_occ_x);
747
748 occ_mo_wx_ov_mat
749 .det()
750 .expect("The determinant of the MO overlap matrix could not be found.")
751 })
752 .fold(T::one(), |acc, x| acc * x);
753
754 let implicit_factor = det.structure_constraint().implicit_factor()?;
755 let wx_ov = if implicit_factor > 1 {
756 let p_i32 = i32::try_from(implicit_factor)?;
757 ComplexFloat::powi(wx_ov, p_i32)
758 } else {
759 wx_ov
760 };
761 det_smat[(*w, *x)] = wx_ov;
762 }
763 }
764
765 if det_orbit.origin().complex_symmetric() {
766 det_orbit.set_smat(
767 (det_smat.clone() + det_smat.t().to_owned()).mapv(|x| x / (T::one() + T::one())),
768 );
769 } else {
770 det_orbit.set_smat(
771 (det_smat.clone() + det_smat.t().to_owned().mapv(|x| x.conj()))
772 .mapv(|x| x / (T::one() + T::one())),
773 );
774 };
775
776 mo_orbitss
777 .iter_mut()
778 .enumerate()
779 .for_each(|(ispin, mo_orbits)| {
780 mo_orbits
781 .iter_mut()
782 .enumerate()
783 .for_each(|(imo, mo_orbit)| {
784 if mo_orbit.origin().complex_symmetric() {
785 mo_orbit.set_smat(
786 (mo_smatss[ispin][imo].clone() + mo_smatss[ispin][imo].t().to_owned())
787 .mapv(|x| x / (T::one() + T::one())),
788 )
789 } else {
790 mo_orbit.set_smat(
791 (mo_smatss[ispin][imo].clone()
792 + mo_smatss[ispin][imo].t().to_owned().mapv(|x| x.conj()))
793 .mapv(|x| x / (T::one() + T::one())),
794 )
795 }
796 })
797 });
798
799 log::debug!("Constructing determinant and MO orbits in tandem... Done.");
800 Ok((det_orbit, mo_orbitss))
801}