1use std::collections::HashSet;
4use std::fmt;
5use std::hash::Hash;
6use std::str::FromStr;
7
8use anyhow::{bail, ensure, format_err};
9use derive_builder::Builder;
10use duplicate::duplicate_item;
11use indexmap::IndexMap;
12use ndarray::{Array2, Ix2, s};
13use ndarray_linalg::Lapack;
14use num::Complex;
15use num_complex::ComplexFloat;
16use serde::{Deserialize, Serialize, de::DeserializeOwned};
17
18use crate::analysis::{EigenvalueComparisonMode, Overlap};
19use crate::angmom::spinor_rotation_3d::{SpinConstraint, SpinOrbitCoupled, StructureConstraint};
20use crate::chartab::CharacterTable;
21use crate::chartab::chartab_group::CharacterProperties;
22use crate::drivers::QSym2Driver;
23use crate::drivers::representation_analysis::{
24 CharacterTableDisplay, MagneticSymmetryAnalysisKind, fn_construct_unitary_group, log_bao,
25 log_cc_transversal,
26};
27use crate::drivers::symmetry_group_detection::SymmetryGroupDetectionResult;
28use crate::group::{GroupProperties, UnitaryRepresentedGroup};
29use crate::io::format::{
30 QSym2Output, log_subtitle, nice_bool, qsym2_output, write_subtitle, write_title,
31};
32use crate::projection::Projectable;
33use crate::symmetry::symmetry_group::{SymmetryGroupProperties, UnitaryRepresentedSymmetryGroup};
34use crate::symmetry::symmetry_symbols::MullikenIrrepSymbol;
35use crate::symmetry::symmetry_transformation::{SymmetryTransformable, SymmetryTransformationKind};
36use crate::target::determinant::SlaterDeterminant;
37use crate::target::determinant::determinant_analysis::SlaterDeterminantSymmetryOrbit;
38use crate::target::noci::basis::{Basis, EagerBasis};
39use crate::target::noci::multideterminant::MultiDeterminant;
40
41#[cfg(test)]
42#[path = "slater_determinant_tests.rs"]
43mod slater_determinant_tests;
44
45const fn default_symbolic() -> Option<CharacterTableDisplay> {
50 Some(CharacterTableDisplay::Symbolic)
51}
52
53#[derive(Clone, Builder, Debug, Serialize, Deserialize)]
55pub struct SlaterDeterminantProjectionParams {
56 #[builder(default = "None")]
59 #[serde(default)]
60 pub use_magnetic_group: Option<MagneticSymmetryAnalysisKind>,
61
62 #[builder(default = "false")]
64 #[serde(default)]
65 pub use_double_group: bool,
66
67 #[builder(default = "Some(CharacterTableDisplay::Symbolic)")]
70 #[serde(default = "default_symbolic")]
71 pub write_character_table: Option<CharacterTableDisplay>,
72
73 #[builder(default = "SymmetryTransformationKind::Spatial")]
76 #[serde(default)]
77 pub symmetry_transformation_kind: SymmetryTransformationKind,
78
79 #[builder(default = "None")]
82 #[serde(default)]
83 pub infinite_order_to_finite: Option<u32>,
84
85 #[builder(default = "None")]
87 #[serde(default)]
88 pub symbolic_projection_targets: Option<Vec<String>>,
89
90 #[builder(default = "None")]
93 #[serde(default)]
94 pub numeric_projection_targets: Option<Vec<usize>>,
95}
96
97impl SlaterDeterminantProjectionParams {
98 pub fn builder() -> SlaterDeterminantProjectionParamsBuilder {
100 SlaterDeterminantProjectionParamsBuilder::default()
101 }
102}
103
104impl fmt::Display for SlaterDeterminantProjectionParams {
105 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
106 if let Some(symbolic_projection_targets) = self.symbolic_projection_targets.as_ref() {
107 writeln!(f, "Projection subspaces (symbolic):")?;
108 for projection_target in symbolic_projection_targets.iter() {
109 writeln!(f, " {projection_target}")?;
110 }
111 writeln!(f)?;
112 }
113 if let Some(numeric_projection_targets) = self.numeric_projection_targets.as_ref() {
114 writeln!(f, "Projection subspaces (numeric):")?;
115 for projection_target in numeric_projection_targets.iter() {
116 writeln!(f, " {projection_target}")?;
117 }
118 writeln!(f)?;
119 }
120 writeln!(
121 f,
122 "Use magnetic group for projection: {}",
123 match self.use_magnetic_group {
124 None => "no",
125 Some(MagneticSymmetryAnalysisKind::Representation) =>
126 "yes, using unitary representations",
127 Some(MagneticSymmetryAnalysisKind::Corepresentation) =>
128 "yes, using magnetic corepresentations",
129 }
130 )?;
131 writeln!(
132 f,
133 "Use double group for projection: {}",
134 nice_bool(self.use_double_group)
135 )?;
136 if let Some(finite_order) = self.infinite_order_to_finite {
137 writeln!(f, "Infinite order to finite: {finite_order}")?;
138 }
139 writeln!(
140 f,
141 "Symmetry transformation kind: {}",
142 self.symmetry_transformation_kind
143 )?;
144 writeln!(f)?;
145 writeln!(
146 f,
147 "Write character table: {}",
148 if let Some(chartab_display) = self.write_character_table.as_ref() {
149 format!("yes, {}", chartab_display.to_string().to_lowercase())
150 } else {
151 "no".to_string()
152 }
153 )?;
154
155 Ok(())
156 }
157}
158
159#[derive(Clone, Builder)]
165pub struct SlaterDeterminantProjectionResult<'a, G, T, SC>
166where
167 G: SymmetryGroupProperties + Clone + 'a,
168 T: ComplexFloat + Lapack,
169 SC: StructureConstraint + Hash + Eq + fmt::Display + 'a,
170 SlaterDeterminant<'a, T, SC>: SymmetryTransformable,
171 SlaterDeterminantSymmetryOrbit<'a, G, T, SC>: Projectable<G, SlaterDeterminant<'a, T, SC>>,
172{
173 parameters: &'a SlaterDeterminantProjectionParams,
175
176 determinant: &'a SlaterDeterminant<'a, T, SC>,
178
179 group: G,
181
182 #[allow(clippy::type_complexity)]
185 projected_determinants: IndexMap<
186 G::RowSymbol,
187 Result<MultiDeterminant<'a, T, EagerBasis<SlaterDeterminant<'a, T, SC>>, SC>, String>,
188 >,
189
190 #[builder(default = "None")]
197 sao: Option<Array2<T>>,
198
199 #[builder(default = "None")]
206 sao_h: Option<Array2<T>>,
207}
208
209impl<'a, G, T, SC> SlaterDeterminantProjectionResult<'a, G, T, SC>
210where
211 G: SymmetryGroupProperties + Clone,
212 G::RowSymbol: Serialize + DeserializeOwned,
213 T: ComplexFloat + Lapack,
214 SC: StructureConstraint + Hash + Eq + Clone + fmt::Display,
215 SlaterDeterminant<'a, T, SC>: SymmetryTransformable,
216 SlaterDeterminantSymmetryOrbit<'a, G, T, SC>: Projectable<G, SlaterDeterminant<'a, T, SC>>,
217{
218 pub fn builder() -> SlaterDeterminantProjectionResultBuilder<'a, G, T, SC> {
219 SlaterDeterminantProjectionResultBuilder::default()
220 }
221
222 pub fn parameters(&self) -> &SlaterDeterminantProjectionParams {
224 self.parameters
225 }
226
227 pub fn determinant(&self) -> &SlaterDeterminant<'a, T, SC> {
229 self.determinant
230 }
231
232 #[allow(clippy::type_complexity)]
234 pub fn projected_determinants(
235 &self,
236 ) -> &IndexMap<
237 G::RowSymbol,
238 Result<MultiDeterminant<'a, T, EagerBasis<SlaterDeterminant<'a, T, SC>>, SC>, String>,
239 > {
240 &self.projected_determinants
241 }
242}
243
244impl<'a, G, T, SC> fmt::Display for SlaterDeterminantProjectionResult<'a, G, T, SC>
245where
246 G: SymmetryGroupProperties + Clone,
247 T: ComplexFloat + Lapack,
248 SC: StructureConstraint + Hash + Eq + fmt::Display,
249 SlaterDeterminant<'a, T, SC>: SymmetryTransformable,
250 SlaterDeterminantSymmetryOrbit<'a, G, T, SC>: Projectable<G, SlaterDeterminant<'a, T, SC>>,
251 MultiDeterminant<'a, T, EagerBasis<SlaterDeterminant<'a, T, SC>>, SC>: Overlap<T, Ix2>,
252{
253 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
254 write_subtitle(f, "Orbit-based symmetry projection summary")?;
255 writeln!(f)?;
256 writeln!(
257 f,
258 "> Group: {} ({})",
259 self.group
260 .finite_subgroup_name()
261 .map(|subgroup_name| format!("{} > {}", self.group.name(), subgroup_name))
262 .unwrap_or(self.group.name()),
263 self.group.group_type().to_string().to_lowercase()
264 )?;
265 writeln!(f)?;
266
267 let (rows, sq_norms): (Vec<_>, Vec<_>) = self
268 .projected_determinants
269 .iter()
270 .map(|(row, psd_res)| {
271 let sq_norm = psd_res
272 .as_ref()
273 .map_err(|err| err.to_string())
274 .and_then(|psd| {
275 psd.overlap(psd, self.sao.as_ref(), self.sao_h.as_ref())
276 .map(|norm_sq| format!("{norm_sq:+.3e}"))
277 .map_err(|err| err.to_string())
278 })
279 .unwrap_or_else(|err| err);
280 (row.to_string(), sq_norm)
281 })
282 .unzip();
283
284 let overlap_definition = self
285 .projected_determinants
286 .iter()
287 .next()
288 .and_then(|(_, psd_res)| psd_res.as_ref().ok().map(|psd| psd.overlap_definition()))
289 .unwrap_or("--".to_string());
290
291 writeln!(
292 f,
293 " Squared norms are computed w.r.t. the following inner product:"
294 )?;
295 writeln!(f, " {overlap_definition}")?;
296 writeln!(f)?;
297
298 let row_length = rows
299 .iter()
300 .map(|row| row.chars().count())
301 .max()
302 .unwrap_or(8)
303 .max(8);
304 let sq_norm_length = sq_norms
305 .iter()
306 .map(|sq_norm| sq_norm.chars().count())
307 .max()
308 .unwrap_or(12)
309 .max(12);
310 let table_width = 4 + row_length + sq_norm_length;
311 writeln!(f, "{}", "┈".repeat(table_width))?;
312 writeln!(f, " {:<row_length$} Squared norm", "Subspace",)?;
313 writeln!(f, "{}", "┈".repeat(table_width))?;
314 for (row, sq_norm) in rows.iter().zip(sq_norms) {
315 writeln!(f, " {:<row_length$} {:<}", row, sq_norm)?;
316 }
317 writeln!(f, "{}", "┈".repeat(table_width))?;
318
319 writeln!(f)?;
320 Ok(())
321 }
322}
323
324impl<'a, G, T, SC> fmt::Debug for SlaterDeterminantProjectionResult<'a, G, T, SC>
325where
326 G: SymmetryGroupProperties + Clone,
327 T: ComplexFloat + Lapack,
328 SC: StructureConstraint + Hash + Eq + fmt::Display,
329 SlaterDeterminant<'a, T, SC>: SymmetryTransformable,
330 SlaterDeterminantSymmetryOrbit<'a, G, T, SC>: Projectable<G, SlaterDeterminant<'a, T, SC>>,
331 MultiDeterminant<'a, T, EagerBasis<SlaterDeterminant<'a, T, SC>>, SC>: Overlap<T, Ix2>,
332{
333 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
334 writeln!(f, "{self}")
335 }
336}
337
338#[derive(Clone, Builder)]
348#[builder(build_fn(validate = "Self::validate"))]
349pub struct SlaterDeterminantProjectionDriver<'a, G, T, SC>
350where
351 G: SymmetryGroupProperties + Clone,
352 G::RowSymbol: Serialize + DeserializeOwned,
353 T: ComplexFloat + Lapack,
354 SC: StructureConstraint + Hash + Eq + fmt::Display,
355 SlaterDeterminant<'a, T, SC>: SymmetryTransformable,
356 SlaterDeterminantSymmetryOrbit<'a, G, T, SC>: Projectable<G, SlaterDeterminant<'a, T, SC>>,
357{
358 parameters: &'a SlaterDeterminantProjectionParams,
360
361 determinant: &'a SlaterDeterminant<'a, T, SC>,
363
364 symmetry_group: &'a SymmetryGroupDetectionResult,
368
369 #[builder(setter(skip), default = "None")]
371 result: Option<SlaterDeterminantProjectionResult<'a, G, T, SC>>,
372
373 #[builder(default = "None")]
380 sao: Option<&'a Array2<T>>,
381
382 #[builder(default = "None")]
389 sao_h: Option<&'a Array2<T>>,
390}
391
392impl<'a, G, T, SC> SlaterDeterminantProjectionDriverBuilder<'a, G, T, SC>
393where
394 G: SymmetryGroupProperties + Clone,
395 G::RowSymbol: Serialize + DeserializeOwned,
396 T: ComplexFloat + Lapack,
397 SC: StructureConstraint + Hash + Eq + fmt::Display,
398 SlaterDeterminant<'a, T, SC>: SymmetryTransformable,
399 SlaterDeterminantSymmetryOrbit<'a, G, T, SC>: Projectable<G, SlaterDeterminant<'a, T, SC>>,
400{
401 fn validate(&self) -> Result<(), String> {
402 let params = self
403 .parameters
404 .ok_or("No Slater determinant projection parameters found.".to_string())?;
405
406 let sym_res = self
407 .symmetry_group
408 .ok_or("No symmetry group information found.".to_string())?;
409
410 let _sd = self
411 .determinant
412 .as_ref()
413 .ok_or("No Slater determinant found.".to_string())?;
414
415 let sym = if params.use_magnetic_group.is_some() {
416 sym_res
417 .magnetic_symmetry
418 .as_ref()
419 .ok_or("Magnetic symmetry requested for symmetry projection, but no magnetic symmetry found.")?
420 } else {
421 &sym_res.unitary_symmetry
422 };
423
424 if sym.is_infinite() && params.infinite_order_to_finite.is_none() {
425 Err(format!(
426 "Projection cannot be performed using the entirety of the infinite group `{}`. \
427 Consider setting the parameter `infinite_order_to_finite` to restrict to a finite subgroup instead.",
428 sym.group_name
429 .as_ref()
430 .expect("No symmetry group name found.")
431 ))
432 } else {
433 Ok(())
434 }
435 }
436}
437
438impl<'a, G, T, SC> SlaterDeterminantProjectionDriver<'a, G, T, SC>
446where
447 G: SymmetryGroupProperties + Clone,
448 G::RowSymbol: Serialize + DeserializeOwned,
449 T: ComplexFloat + Lapack,
450 SC: StructureConstraint + Hash + Eq + Clone + fmt::Display,
451 SlaterDeterminant<'a, T, SC>: SymmetryTransformable,
452 SlaterDeterminantSymmetryOrbit<'a, G, T, SC>: Projectable<G, SlaterDeterminant<'a, T, SC>>,
453{
454 pub fn builder() -> SlaterDeterminantProjectionDriverBuilder<'a, G, T, SC> {
456 SlaterDeterminantProjectionDriverBuilder::default()
457 }
458
459 #[allow(clippy::type_complexity)]
462 fn construct_sao(&self) -> Result<(Option<Array2<T>>, Option<Array2<T>>), anyhow::Error> {
463 if let Some(provided_sao) = self.sao {
464 let nbas_set = self
465 .determinant
466 .baos()
467 .iter()
468 .map(|bao| bao.n_funcs())
469 .collect::<HashSet<_>>();
470 let uniform_component = nbas_set.len() == 1;
471 let ncomps = self
472 .determinant
473 .structure_constraint()
474 .n_explicit_comps_per_coefficient_matrix();
475 let provided_dim = provided_sao.nrows();
476
477 if uniform_component {
478 let nbas = nbas_set.iter().next().ok_or_else(|| format_err!("Unable to extract the uniform number of basis functions per explicit component."))?;
479 if provided_dim == *nbas {
480 let sao = {
481 let mut sao_mut = Array2::zeros((ncomps * nbas, ncomps * nbas));
482 (0..ncomps).for_each(|icomp| {
483 let start = icomp * nbas;
484 let end = (icomp + 1) * nbas;
485 sao_mut
486 .slice_mut(s![start..end, start..end])
487 .assign(provided_sao);
488 });
489 sao_mut
490 };
491
492 let sao_h_opt = self.sao_h.map(|sao_h| {
493 let mut sao_h_mut = Array2::zeros((ncomps * nbas, ncomps * nbas));
494 (0..ncomps).for_each(|icomp| {
495 let start = icomp * nbas;
496 let end = (icomp + 1) * nbas;
497 sao_h_mut
498 .slice_mut(s![start..end, start..end])
499 .assign(sao_h);
500 });
501 sao_h_mut
502 });
503
504 Ok((Some(sao), sao_h_opt))
505 } else {
506 ensure!(provided_dim == nbas * ncomps);
507 Ok((self.sao.cloned(), self.sao_h.cloned()))
508 }
509 } else {
510 let nbas_tot = self
511 .determinant
512 .baos()
513 .iter()
514 .map(|bao| bao.n_funcs())
515 .sum::<usize>();
516 ensure!(provided_dim == nbas_tot);
517 Ok((self.sao.cloned(), self.sao_h.cloned()))
518 }
519 } else {
520 Ok((None, None))
521 }
522 }
523}
524
525impl<'a, T, SC> SlaterDeterminantProjectionDriver<'a, UnitaryRepresentedSymmetryGroup, T, SC>
529where
530 T: ComplexFloat + Lapack,
531 SC: StructureConstraint + Hash + Eq + Clone + fmt::Display,
532 SlaterDeterminant<'a, T, SC>: SymmetryTransformable,
533 SlaterDeterminantSymmetryOrbit<'a, UnitaryRepresentedSymmetryGroup, T, SC>:
534 Projectable<UnitaryRepresentedSymmetryGroup, SlaterDeterminant<'a, T, SC>>,
535{
536 fn_construct_unitary_group!(
537 construct_unitary_group
540 );
541}
542
543#[duplicate_item(
547 duplicate!{
548 [
549 dtype_nested sctype_nested;
550 [ f64 ] [ SpinConstraint ];
551 [ Complex<f64> ] [ SpinConstraint ];
552 [ Complex<f64> ] [ SpinOrbitCoupled ];
553 ]
554 [
555 gtype_ [ UnitaryRepresentedSymmetryGroup ]
556 dtype_ [ dtype_nested ]
557 sctype_ [ sctype_nested ]
558 doc_sub_ [ "Performs projection using a unitary-represented group and stores the result." ]
559 projection_fn_ [ projection_representation ]
560 construct_group_ [ self.construct_unitary_group()? ]
561 ]
562 }
563)]
564impl<'a> SlaterDeterminantProjectionDriver<'a, gtype_, dtype_, sctype_> {
565 #[doc = doc_sub_]
566 fn projection_fn_(&mut self) -> Result<(), anyhow::Error> {
567 let params = self.parameters;
568 let group = construct_group_;
569 let original_sd = self.determinant;
570 log_cc_transversal(&group);
571 let baos = original_sd.baos();
572 for (bao_i, bao) in baos.iter().enumerate() {
573 log_bao(bao, Some(bao_i));
574 }
575
576 let all_rows = group.character_table().get_all_rows();
577 let rows = params
578 .symbolic_projection_targets
579 .as_ref()
580 .unwrap_or(&vec![])
581 .iter()
582 .map(|row_str| MullikenIrrepSymbol::from_str(row_str).map_err(|err| format_err!(err)))
583 .chain(
584 params
585 .numeric_projection_targets
586 .as_ref()
587 .unwrap_or(&vec![])
588 .iter()
589 .map(|row_index| {
590 all_rows.get_index(*row_index).cloned().ok_or_else(|| {
591 format_err!(
592 "Unable to retrieve the subspace label with index {row_index}."
593 )
594 })
595 }),
596 )
597 .collect::<Result<Vec<_>, _>>()?;
598
599 let projected_determinants = SlaterDeterminantSymmetryOrbit::builder()
600 .group(&group)
601 .origin(original_sd)
602 .symmetry_transformation_kind(params.symmetry_transformation_kind.clone())
603 .integrality_threshold(1e-14)
604 .linear_independence_threshold(1e-14)
605 .eigenvalue_comparison_mode(EigenvalueComparisonMode::Modulus)
606 .build()
607 .map_err(|err| format_err!(err))
608 .and_then(|sd_orbit| {
609 rows.iter()
610 .map(|row| {
611 sd_orbit.project_onto(row).and_then(|temp_projected_sd| {
612 let basis_dets = temp_projected_sd
613 .basis()
614 .iter()
615 .map(|det_res| {
616 det_res.and_then(|det| {
617 SlaterDeterminant::builder()
618 .structure_constraint(
619 det.structure_constraint().clone(),
620 )
621 .baos(baos.clone())
622 .complex_symmetric(det.complex_symmetric())
623 .complex_conjugated(det.complex_conjugated())
624 .mol(original_sd.mol())
625 .coefficients(&det.coefficients().clone())
626 .occupations(&det.occupations().clone())
627 .mo_energies(det.mo_energies().cloned())
628 .energy(
629 det.energy()
630 .cloned()
631 .map_err(|err| err.to_string()),
632 )
633 .threshold(original_sd.threshold())
634 .build()
635 .map_err(|err| format_err!(err))
636 })
637 })
638 .collect::<Result<Vec<_>, _>>()?;
639 let basis = EagerBasis::builder()
640 .elements(basis_dets)
641 .build()
642 .map_err(|err| format_err!(err))?;
643 Ok((
644 row.clone(),
645 MultiDeterminant::builder()
646 .basis(basis)
647 .complex_conjugated(temp_projected_sd.complex_conjugated())
648 .coefficients(temp_projected_sd.coefficients().clone())
649 .threshold(temp_projected_sd.threshold())
650 .build()
651 .map_err(|err| err.to_string()),
652 ))
653 })
654 })
655 .collect::<Result<IndexMap<_, _>, _>>()
656 })?;
657
658 let (sao_opt, sao_h_opt) = self.construct_sao()?;
659 let result = SlaterDeterminantProjectionResult::builder()
660 .parameters(params)
661 .determinant(self.determinant)
662 .group(group.clone())
663 .projected_determinants(projected_determinants)
664 .sao(sao_opt)
665 .sao_h(sao_h_opt)
666 .build()?;
667 self.result = Some(result);
668
669 Ok(())
670 }
671}
672
673impl<'a, G, T, SC> fmt::Display for SlaterDeterminantProjectionDriver<'a, G, T, SC>
681where
682 G: SymmetryGroupProperties + Clone,
683 G::RowSymbol: Serialize + DeserializeOwned,
684 T: ComplexFloat + Lapack,
685 SC: StructureConstraint + Hash + Eq + fmt::Display,
686 SlaterDeterminant<'a, T, SC>: SymmetryTransformable,
687 SlaterDeterminantSymmetryOrbit<'a, G, T, SC>: Projectable<G, SlaterDeterminant<'a, T, SC>>,
688{
689 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
690 write_title(f, "Slater Determinant Symmetry Projection")?;
691 writeln!(f)?;
692 writeln!(f, "{}", self.parameters)?;
693 Ok(())
694 }
695}
696
697impl<'a, G, T, SC> fmt::Debug for SlaterDeterminantProjectionDriver<'a, G, T, SC>
698where
699 G: SymmetryGroupProperties + Clone,
700 G::RowSymbol: Serialize + DeserializeOwned,
701 T: ComplexFloat + Lapack,
702 SC: StructureConstraint + Hash + Eq + fmt::Display,
703 SlaterDeterminant<'a, T, SC>: SymmetryTransformable,
704 SlaterDeterminantSymmetryOrbit<'a, G, T, SC>: Projectable<G, SlaterDeterminant<'a, T, SC>>,
705{
706 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
707 writeln!(f, "{self}")
708 }
709}
710
711#[duplicate_item(
715 duplicate!{
716 [
717 dtype_nested sctype_nested;
718 [ f64 ] [ SpinConstraint ];
719 [ Complex<f64> ] [ SpinConstraint ];
720 [ Complex<f64> ] [ SpinOrbitCoupled ];
721 ]
722 [
723 gtype_ [ UnitaryRepresentedSymmetryGroup ]
724 dtype_ [ dtype_nested ]
725 sctype_ [ sctype_nested ]
726 doc_sub_ [ "Performs projection using a unitary-represented group and stores the result." ]
727 projection_fn_ [ projection_representation ]
728 construct_group_ [ self.construct_unitary_group()? ]
729 ]
730 }
731)]
732impl<'a> QSym2Driver for SlaterDeterminantProjectionDriver<'a, gtype_, dtype_, sctype_> {
733 type Params = SlaterDeterminantProjectionParams;
734
735 type Outcome = SlaterDeterminantProjectionResult<'a, gtype_, dtype_, sctype_>;
736
737 fn result(&self) -> Result<&Self::Outcome, anyhow::Error> {
738 self.result
739 .as_ref()
740 .ok_or_else(|| format_err!("No Slater determinant projection results found."))
741 }
742
743 fn run(&mut self) -> Result<(), anyhow::Error> {
744 self.log_output_display();
745 self.projection_fn_()?;
746 self.result()?.log_output_display();
747 Ok(())
748 }
749}