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 #[allow(clippy::type_complexity)]
224 pub fn projected_determinants(
225 &self,
226 ) -> &IndexMap<
227 G::RowSymbol,
228 Result<MultiDeterminant<'a, T, EagerBasis<SlaterDeterminant<'a, T, SC>>, SC>, String>,
229 > {
230 &self.projected_determinants
231 }
232}
233
234impl<'a, G, T, SC> fmt::Display for SlaterDeterminantProjectionResult<'a, G, T, SC>
235where
236 G: SymmetryGroupProperties + Clone,
237 T: ComplexFloat + Lapack,
238 SC: StructureConstraint + Hash + Eq + fmt::Display,
239 SlaterDeterminant<'a, T, SC>: SymmetryTransformable,
240 SlaterDeterminantSymmetryOrbit<'a, G, T, SC>: Projectable<G, SlaterDeterminant<'a, T, SC>>,
241 MultiDeterminant<'a, T, EagerBasis<SlaterDeterminant<'a, T, SC>>, SC>: Overlap<T, Ix2>,
242{
243 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
244 write_subtitle(f, "Orbit-based symmetry projection summary")?;
245 writeln!(f)?;
246 writeln!(
247 f,
248 "> Group: {} ({})",
249 self.group
250 .finite_subgroup_name()
251 .map(|subgroup_name| format!("{} > {}", self.group.name(), subgroup_name))
252 .unwrap_or(self.group.name()),
253 self.group.group_type().to_string().to_lowercase()
254 )?;
255 writeln!(f)?;
256
257 let (rows, sq_norms): (Vec<_>, Vec<_>) = self
258 .projected_determinants
259 .iter()
260 .map(|(row, psd_res)| {
261 let sq_norm = psd_res
262 .as_ref()
263 .map_err(|err| err.to_string())
264 .and_then(|psd| {
265 psd.overlap(psd, self.sao.as_ref(), self.sao_h.as_ref())
266 .map(|norm_sq| format!("{norm_sq:+.3e}"))
267 .map_err(|err| err.to_string())
268 })
269 .unwrap_or_else(|err| err);
270 (row.to_string(), sq_norm)
271 })
272 .unzip();
273
274 let overlap_definition = self
275 .projected_determinants
276 .iter()
277 .next()
278 .and_then(|(_, psd_res)| psd_res.as_ref().ok().map(|psd| psd.overlap_definition()))
279 .unwrap_or("--".to_string());
280
281 writeln!(
282 f,
283 " Squared norms are computed w.r.t. the following inner product:"
284 )?;
285 writeln!(f, " {overlap_definition}")?;
286 writeln!(f)?;
287
288 let row_length = rows
289 .iter()
290 .map(|row| row.chars().count())
291 .max()
292 .unwrap_or(8)
293 .max(8);
294 let sq_norm_length = sq_norms
295 .iter()
296 .map(|sq_norm| sq_norm.chars().count())
297 .max()
298 .unwrap_or(12)
299 .max(12);
300 let table_width = 4 + row_length + sq_norm_length;
301 writeln!(f, "{}", "┈".repeat(table_width))?;
302 writeln!(f, " {:<row_length$} Squared norm", "Subspace",)?;
303 writeln!(f, "{}", "┈".repeat(table_width))?;
304 for (row, sq_norm) in rows.iter().zip(sq_norms) {
305 writeln!(f, " {:<row_length$} {:<}", row, sq_norm)?;
306 }
307 writeln!(f, "{}", "┈".repeat(table_width))?;
308
309 writeln!(f)?;
310 Ok(())
311 }
312}
313
314impl<'a, G, T, SC> fmt::Debug for SlaterDeterminantProjectionResult<'a, G, T, SC>
315where
316 G: SymmetryGroupProperties + Clone,
317 T: ComplexFloat + Lapack,
318 SC: StructureConstraint + Hash + Eq + fmt::Display,
319 SlaterDeterminant<'a, T, SC>: SymmetryTransformable,
320 SlaterDeterminantSymmetryOrbit<'a, G, T, SC>: Projectable<G, SlaterDeterminant<'a, T, SC>>,
321 MultiDeterminant<'a, T, EagerBasis<SlaterDeterminant<'a, T, SC>>, SC>: Overlap<T, Ix2>,
322{
323 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
324 writeln!(f, "{self}")
325 }
326}
327
328#[derive(Clone, Builder)]
338#[builder(build_fn(validate = "Self::validate"))]
339pub struct SlaterDeterminantProjectionDriver<'a, G, T, SC>
340where
341 G: SymmetryGroupProperties + Clone,
342 G::RowSymbol: Serialize + DeserializeOwned,
343 T: ComplexFloat + Lapack,
344 SC: StructureConstraint + Hash + Eq + fmt::Display,
345 SlaterDeterminant<'a, T, SC>: SymmetryTransformable,
346 SlaterDeterminantSymmetryOrbit<'a, G, T, SC>: Projectable<G, SlaterDeterminant<'a, T, SC>>,
347{
348 parameters: &'a SlaterDeterminantProjectionParams,
350
351 determinant: &'a SlaterDeterminant<'a, T, SC>,
353
354 symmetry_group: &'a SymmetryGroupDetectionResult,
358
359 #[builder(setter(skip), default = "None")]
361 result: Option<SlaterDeterminantProjectionResult<'a, G, T, SC>>,
362
363 #[builder(default = "None")]
370 sao: Option<&'a Array2<T>>,
371
372 #[builder(default = "None")]
379 sao_h: Option<&'a Array2<T>>,
380}
381
382impl<'a, G, T, SC> SlaterDeterminantProjectionDriverBuilder<'a, G, T, SC>
383where
384 G: SymmetryGroupProperties + Clone,
385 G::RowSymbol: Serialize + DeserializeOwned,
386 T: ComplexFloat + Lapack,
387 SC: StructureConstraint + Hash + Eq + fmt::Display,
388 SlaterDeterminant<'a, T, SC>: SymmetryTransformable,
389 SlaterDeterminantSymmetryOrbit<'a, G, T, SC>: Projectable<G, SlaterDeterminant<'a, T, SC>>,
390{
391 fn validate(&self) -> Result<(), String> {
392 let params = self
393 .parameters
394 .ok_or("No Slater determinant projection parameters found.".to_string())?;
395
396 let sym_res = self
397 .symmetry_group
398 .ok_or("No symmetry group information found.".to_string())?;
399
400 let _sd = self
401 .determinant
402 .as_ref()
403 .ok_or("No Slater determinant found.".to_string())?;
404
405 let sym = if params.use_magnetic_group.is_some() {
406 sym_res
407 .magnetic_symmetry
408 .as_ref()
409 .ok_or("Magnetic symmetry requested for symmetry projection, but no magnetic symmetry found.")?
410 } else {
411 &sym_res.unitary_symmetry
412 };
413
414 if sym.is_infinite() && params.infinite_order_to_finite.is_none() {
415 Err(format!(
416 "Projection cannot be performed using the entirety of the infinite group `{}`. \
417 Consider setting the parameter `infinite_order_to_finite` to restrict to a finite subgroup instead.",
418 sym.group_name
419 .as_ref()
420 .expect("No symmetry group name found.")
421 ))
422 } else {
423 Ok(())
424 }
425 }
426}
427
428impl<'a, G, T, SC> SlaterDeterminantProjectionDriver<'a, G, T, SC>
436where
437 G: SymmetryGroupProperties + Clone,
438 G::RowSymbol: Serialize + DeserializeOwned,
439 T: ComplexFloat + Lapack,
440 SC: StructureConstraint + Hash + Eq + Clone + fmt::Display,
441 SlaterDeterminant<'a, T, SC>: SymmetryTransformable,
442 SlaterDeterminantSymmetryOrbit<'a, G, T, SC>: Projectable<G, SlaterDeterminant<'a, T, SC>>,
443{
444 pub fn builder() -> SlaterDeterminantProjectionDriverBuilder<'a, G, T, SC> {
446 SlaterDeterminantProjectionDriverBuilder::default()
447 }
448
449 #[allow(clippy::type_complexity)]
452 fn construct_sao(&self) -> Result<(Option<Array2<T>>, Option<Array2<T>>), anyhow::Error> {
453 if let Some(provided_sao) = self.sao {
454 let nbas_set = self
455 .determinant
456 .baos()
457 .iter()
458 .map(|bao| bao.n_funcs())
459 .collect::<HashSet<_>>();
460 let uniform_component = nbas_set.len() == 1;
461 let ncomps = self
462 .determinant
463 .structure_constraint()
464 .n_explicit_comps_per_coefficient_matrix();
465 let provided_dim = provided_sao.nrows();
466
467 if uniform_component {
468 let nbas = nbas_set.iter().next().ok_or_else(|| format_err!("Unable to extract the uniform number of basis functions per explicit component."))?;
469 if provided_dim == *nbas {
470 let sao = {
471 let mut sao_mut = Array2::zeros((ncomps * nbas, ncomps * nbas));
472 (0..ncomps).for_each(|icomp| {
473 let start = icomp * nbas;
474 let end = (icomp + 1) * nbas;
475 sao_mut
476 .slice_mut(s![start..end, start..end])
477 .assign(provided_sao);
478 });
479 sao_mut
480 };
481
482 let sao_h_opt = self.sao_h.map(|sao_h| {
483 let mut sao_h_mut = Array2::zeros((ncomps * nbas, ncomps * nbas));
484 (0..ncomps).for_each(|icomp| {
485 let start = icomp * nbas;
486 let end = (icomp + 1) * nbas;
487 sao_h_mut
488 .slice_mut(s![start..end, start..end])
489 .assign(sao_h);
490 });
491 sao_h_mut
492 });
493
494 Ok((Some(sao), sao_h_opt))
495 } else {
496 ensure!(provided_dim == nbas * ncomps);
497 Ok((self.sao.cloned(), self.sao_h.cloned()))
498 }
499 } else {
500 let nbas_tot = self
501 .determinant
502 .baos()
503 .iter()
504 .map(|bao| bao.n_funcs())
505 .sum::<usize>();
506 ensure!(provided_dim == nbas_tot);
507 Ok((self.sao.cloned(), self.sao_h.cloned()))
508 }
509 } else {
510 Ok((None, None))
511 }
512 }
513}
514
515impl<'a, T, SC> SlaterDeterminantProjectionDriver<'a, UnitaryRepresentedSymmetryGroup, T, SC>
519where
520 T: ComplexFloat + Lapack,
521 SC: StructureConstraint + Hash + Eq + Clone + fmt::Display,
522 SlaterDeterminant<'a, T, SC>: SymmetryTransformable,
523 SlaterDeterminantSymmetryOrbit<'a, UnitaryRepresentedSymmetryGroup, T, SC>:
524 Projectable<UnitaryRepresentedSymmetryGroup, SlaterDeterminant<'a, T, SC>>,
525{
526 fn_construct_unitary_group!(
527 construct_unitary_group
530 );
531}
532
533#[duplicate_item(
537 duplicate!{
538 [
539 dtype_nested sctype_nested;
540 [ f64 ] [ SpinConstraint ];
541 [ Complex<f64> ] [ SpinConstraint ];
542 [ Complex<f64> ] [ SpinOrbitCoupled ];
543 ]
544 [
545 gtype_ [ UnitaryRepresentedSymmetryGroup ]
546 dtype_ [ dtype_nested ]
547 sctype_ [ sctype_nested ]
548 doc_sub_ [ "Performs projection using a unitary-represented group and stores the result." ]
549 projection_fn_ [ projection_representation ]
550 construct_group_ [ self.construct_unitary_group()? ]
551 ]
552 }
553)]
554impl<'a> SlaterDeterminantProjectionDriver<'a, gtype_, dtype_, sctype_> {
555 #[doc = doc_sub_]
556 fn projection_fn_(&mut self) -> Result<(), anyhow::Error> {
557 let params = self.parameters;
558 let group = construct_group_;
559 let original_sd = self.determinant;
560 log_cc_transversal(&group);
561 let baos = original_sd.baos();
562 for (bao_i, bao) in baos.iter().enumerate() {
563 log_bao(bao, Some(bao_i));
564 }
565
566 let all_rows = group.character_table().get_all_rows();
567 let rows = params
568 .symbolic_projection_targets
569 .as_ref()
570 .unwrap_or(&vec![])
571 .iter()
572 .map(|row_str| MullikenIrrepSymbol::from_str(row_str).map_err(|err| format_err!(err)))
573 .chain(
574 params
575 .numeric_projection_targets
576 .as_ref()
577 .unwrap_or(&vec![])
578 .iter()
579 .map(|row_index| {
580 all_rows.get_index(*row_index).cloned().ok_or_else(|| {
581 format_err!(
582 "Unable to retrieve the subspace label with index {row_index}."
583 )
584 })
585 }),
586 )
587 .collect::<Result<Vec<_>, _>>()?;
588
589 let projected_determinants = SlaterDeterminantSymmetryOrbit::builder()
590 .group(&group)
591 .origin(original_sd)
592 .symmetry_transformation_kind(params.symmetry_transformation_kind.clone())
593 .integrality_threshold(1e-14)
594 .linear_independence_threshold(1e-14)
595 .eigenvalue_comparison_mode(EigenvalueComparisonMode::Modulus)
596 .build()
597 .map_err(|err| format_err!(err))
598 .and_then(|sd_orbit| {
599 rows.iter()
600 .map(|row| {
601 sd_orbit.project_onto(row).and_then(|temp_projected_sd| {
602 let basis_dets = temp_projected_sd
603 .basis()
604 .iter()
605 .map(|det_res| {
606 det_res.and_then(|det| {
607 SlaterDeterminant::builder()
608 .structure_constraint(
609 det.structure_constraint().clone(),
610 )
611 .baos(baos.clone())
612 .complex_symmetric(det.complex_symmetric())
613 .complex_conjugated(det.complex_conjugated())
614 .mol(original_sd.mol())
615 .coefficients(&det.coefficients().clone())
616 .occupations(&det.occupations().clone())
617 .mo_energies(det.mo_energies().cloned())
618 .energy(
619 det.energy()
620 .cloned()
621 .map_err(|err| err.to_string()),
622 )
623 .threshold(original_sd.threshold())
624 .build()
625 .map_err(|err| format_err!(err))
626 })
627 })
628 .collect::<Result<Vec<_>, _>>()?;
629 let basis = EagerBasis::builder()
630 .elements(basis_dets)
631 .build()
632 .map_err(|err| format_err!(err))?;
633 Ok((
634 row.clone(),
635 MultiDeterminant::builder()
636 .basis(basis)
637 .complex_conjugated(temp_projected_sd.complex_conjugated())
638 .coefficients(temp_projected_sd.coefficients().clone())
639 .threshold(temp_projected_sd.threshold())
640 .build()
641 .map_err(|err| err.to_string()),
642 ))
643 })
644 })
645 .collect::<Result<IndexMap<_, _>, _>>()
646 })?;
647
648 let (sao_opt, sao_h_opt) = self.construct_sao()?;
649 let result = SlaterDeterminantProjectionResult::builder()
650 .parameters(params)
651 .determinant(self.determinant)
652 .group(group.clone())
653 .projected_determinants(projected_determinants)
654 .sao(sao_opt)
655 .sao_h(sao_h_opt)
656 .build()?;
657 self.result = Some(result);
658
659 Ok(())
660 }
661}
662
663impl<'a, G, T, SC> fmt::Display for SlaterDeterminantProjectionDriver<'a, G, T, SC>
671where
672 G: SymmetryGroupProperties + Clone,
673 G::RowSymbol: Serialize + DeserializeOwned,
674 T: ComplexFloat + Lapack,
675 SC: StructureConstraint + Hash + Eq + fmt::Display,
676 SlaterDeterminant<'a, T, SC>: SymmetryTransformable,
677 SlaterDeterminantSymmetryOrbit<'a, G, T, SC>: Projectable<G, SlaterDeterminant<'a, T, SC>>,
678{
679 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
680 write_title(f, "Slater Determinant Symmetry Projection")?;
681 writeln!(f)?;
682 writeln!(f, "{}", self.parameters)?;
683 Ok(())
684 }
685}
686
687impl<'a, G, T, SC> fmt::Debug for SlaterDeterminantProjectionDriver<'a, G, T, SC>
688where
689 G: SymmetryGroupProperties + Clone,
690 G::RowSymbol: Serialize + DeserializeOwned,
691 T: ComplexFloat + Lapack,
692 SC: StructureConstraint + Hash + Eq + fmt::Display,
693 SlaterDeterminant<'a, T, SC>: SymmetryTransformable,
694 SlaterDeterminantSymmetryOrbit<'a, G, T, SC>: Projectable<G, SlaterDeterminant<'a, T, SC>>,
695{
696 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
697 writeln!(f, "{self}")
698 }
699}
700
701#[duplicate_item(
705 duplicate!{
706 [
707 dtype_nested sctype_nested;
708 [ f64 ] [ SpinConstraint ];
709 [ Complex<f64> ] [ SpinConstraint ];
710 [ Complex<f64> ] [ SpinOrbitCoupled ];
711 ]
712 [
713 gtype_ [ UnitaryRepresentedSymmetryGroup ]
714 dtype_ [ dtype_nested ]
715 sctype_ [ sctype_nested ]
716 doc_sub_ [ "Performs projection using a unitary-represented group and stores the result." ]
717 projection_fn_ [ projection_representation ]
718 construct_group_ [ self.construct_unitary_group()? ]
719 ]
720 }
721)]
722impl<'a> QSym2Driver for SlaterDeterminantProjectionDriver<'a, gtype_, dtype_, sctype_> {
723 type Params = SlaterDeterminantProjectionParams;
724
725 type Outcome = SlaterDeterminantProjectionResult<'a, gtype_, dtype_, sctype_>;
726
727 fn result(&self) -> Result<&Self::Outcome, anyhow::Error> {
728 self.result
729 .as_ref()
730 .ok_or_else(|| format_err!("No Slater determinant projection results found."))
731 }
732
733 fn run(&mut self) -> Result<(), anyhow::Error> {
734 self.log_output_display();
735 self.projection_fn_()?;
736 self.result()?.log_output_display();
737 Ok(())
738 }
739}