qsym2/target/noci/
basis.rs

1//! Basis for non-orthogonal configuration interaction of Slater determinants.
2
3use std::collections::VecDeque;
4
5use anyhow;
6use derive_builder::Builder;
7use itertools::structs::Product;
8use itertools::Itertools;
9
10use crate::group::GroupProperties;
11
12#[path = "basis_transformation.rs"]
13mod basis_transformation;
14
15#[cfg(test)]
16#[path = "basis_tests.rs"]
17mod basis_tests;
18
19// =====
20// Basis
21// =====
22
23// -----------------
24// Trait definitions
25// -----------------
26
27/// Trait defining behaviours of a basis consisting of linear-space items.
28pub trait Basis<I> {
29    /// Type of the iterator over items in the basis.
30    type BasisIter: Iterator<Item = Result<I, anyhow::Error>>;
31
32    /// Returns the number of items in the basis.
33    fn n_items(&self) -> usize;
34
35    /// An iterator over items in the basis.
36    fn iter(&self) -> Self::BasisIter;
37
38    /// Shared reference to the first item in the basis.
39    fn first(&self) -> Option<I>;
40}
41
42// --------------------------------------
43// Struct definitions and implementations
44// --------------------------------------
45
46// ~~~~~~~~~~~~~~~~~~~~~~
47// Lazy basis from orbits
48// ~~~~~~~~~~~~~~~~~~~~~~
49
50#[derive(Builder, Clone)]
51pub(crate) struct OrbitBasis<'g, G, I>
52where
53    G: GroupProperties,
54{
55    /// The origins from which orbits are generated.
56    origins: Vec<I>,
57
58    /// The group acting on the origins to generate orbits, the concatenation of which forms the
59    /// basis.
60    group: &'g G,
61
62    /// Additional operators acting on the entire orbit basis (right-most operator acts first). Each
63    /// operator has an associated action that defines how it operatres on the elements in the
64    /// orbit basis.
65    #[builder(default = "None")]
66    prefactors: Option<
67        VecDeque<(
68            G::GroupElement,
69            fn(&G::GroupElement, &I) -> Result<I, anyhow::Error>,
70        )>,
71    >,
72
73    /// A function defining the action of each group element on the origin.
74    action: fn(&G::GroupElement, &I) -> Result<I, anyhow::Error>,
75}
76
77impl<'g, G, I> OrbitBasis<'g, G, I>
78where
79    G: GroupProperties + Clone,
80    I: Clone,
81{
82    pub(crate) fn builder() -> OrbitBasisBuilder<'g, G, I> {
83        OrbitBasisBuilder::<G, I>::default()
84    }
85
86    /// The origins from which orbits are generated.
87    pub fn origins(&self) -> &Vec<I> {
88        &self.origins
89    }
90
91    /// The group acting on the origins to generate orbits, the concatenation of which forms the
92    /// basis.
93    pub fn group(&self) -> &G {
94        self.group
95    }
96
97    /// Additional operators acting on the entire orbit basis (right-most operator acts first). Each
98    /// operator has an associated action that defines how it operatres on the elements in the
99    /// orbit basis.
100    pub fn prefactors(
101        &self,
102    ) -> Option<
103        &VecDeque<(
104            G::GroupElement,
105            fn(&G::GroupElement, &I) -> Result<I, anyhow::Error>,
106        )>,
107    > {
108        self.prefactors.as_ref()
109    }
110}
111
112impl<'g, G, I> Basis<I> for OrbitBasis<'g, G, I>
113where
114    G: GroupProperties,
115    I: Clone,
116{
117    type BasisIter = OrbitBasisIterator<G, I>;
118
119    fn n_items(&self) -> usize {
120        self.origins.len() * self.group.order()
121    }
122
123    fn iter(&self) -> Self::BasisIter {
124        OrbitBasisIterator::new(
125            self.prefactors.clone(),
126            self.group,
127            self.origins.clone(),
128            self.action,
129        )
130    }
131
132    fn first(&self) -> Option<I> {
133        if let Some(prefactors) = self.prefactors.as_ref() {
134            prefactors
135                .iter()
136                .rev()
137                .try_fold(self.origins.get(0)?.clone(), |acc, (symop, action)| {
138                    (action)(symop, &acc).ok()
139                })
140        } else {
141            self.origins.get(0).cloned()
142        }
143    }
144}
145
146/// Lazy iterator for basis constructed from the concatenation of orbits generated from multiple
147/// origins.
148pub struct OrbitBasisIterator<G, I>
149where
150    G: GroupProperties,
151{
152    prefactors: Option<
153        VecDeque<(
154            G::GroupElement,
155            fn(&G::GroupElement, &I) -> Result<I, anyhow::Error>,
156        )>,
157    >,
158
159    /// A mutable iterator over the Cartesian product between the group elements and the origins.
160    group_origin_iter: Product<
161        <<G as GroupProperties>::ElementCollection as IntoIterator>::IntoIter,
162        std::vec::IntoIter<I>,
163    >,
164
165    /// A function defining the action of each group element on the origin.
166    action: fn(&G::GroupElement, &I) -> Result<I, anyhow::Error>,
167}
168
169impl<G, I> OrbitBasisIterator<G, I>
170where
171    G: GroupProperties,
172    I: Clone,
173{
174    /// Creates and returns a new orbit basis iterator.
175    ///
176    /// # Arguments
177    ///
178    /// * `group` - A group.
179    /// * `origins` - A slice of origins.
180    /// * `action` - A function or closure defining the action of each group element on the origins.
181    ///
182    /// # Returns
183    ///
184    /// An orbit basis iterator.
185    fn new(
186        prefactors: Option<
187            VecDeque<(
188                G::GroupElement,
189                fn(&G::GroupElement, &I) -> Result<I, anyhow::Error>,
190            )>,
191        >,
192        group: &G,
193        origins: Vec<I>,
194        action: fn(&G::GroupElement, &I) -> Result<I, anyhow::Error>,
195    ) -> Self {
196        Self {
197            prefactors,
198            group_origin_iter: group
199                .elements()
200                .clone()
201                .into_iter()
202                .cartesian_product(origins.into_iter()),
203            action,
204        }
205    }
206}
207
208impl<G, I> Iterator for OrbitBasisIterator<G, I>
209where
210    G: GroupProperties,
211    I: Clone,
212{
213    type Item = Result<I, anyhow::Error>;
214
215    fn next(&mut self) -> Option<Self::Item> {
216        if let Some(prefactors) = self.prefactors.as_ref() {
217            // let group_action_result = self
218            //     .group_origin_iter
219            //     .next()
220            //     .map(|(op, origin)| (self.action)(&op, &origin))?;
221            // Some((self.action)(prefactor, group_action_result.as_ref().ok()?))
222            self.group_origin_iter.next().and_then(|(op, origin)| {
223                prefactors
224                    .iter()
225                    .rev()
226                    .try_fold((self.action)(&op, &origin), |acc_res, (symop, action)| {
227                        acc_res.map(|acc| (action)(symop, &acc))
228                    })
229                    .ok()
230            })
231        } else {
232            self.group_origin_iter
233                .next()
234                .map(|(op, origin)| (self.action)(&op, &origin))
235        }
236    }
237}
238
239// ~~~~~~~~~~~
240// Eager basis
241// ~~~~~~~~~~~
242
243#[derive(Builder, Clone)]
244pub(crate) struct EagerBasis<I: Clone> {
245    /// The elements in the basis.
246    elements: Vec<I>,
247}
248
249impl<I: Clone> EagerBasis<I> {
250    pub(crate) fn builder() -> EagerBasisBuilder<I> {
251        EagerBasisBuilder::default()
252    }
253}
254
255impl<I: Clone> Basis<I> for EagerBasis<I> {
256    type BasisIter = std::vec::IntoIter<Result<I, anyhow::Error>>;
257
258    fn n_items(&self) -> usize {
259        self.elements.len()
260    }
261
262    fn iter(&self) -> Self::BasisIter {
263        self.elements
264            .iter()
265            .cloned()
266            .map(Ok)
267            .collect_vec()
268            .into_iter()
269    }
270
271    fn first(&self) -> Option<I> {
272        self.elements.get(0).cloned()
273    }
274}