1use 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
19pub trait Basis<I> {
29 type BasisIter: Iterator<Item = Result<I, anyhow::Error>>;
31
32 fn n_items(&self) -> usize;
34
35 fn iter(&self) -> Self::BasisIter;
37
38 fn first(&self) -> Option<I>;
40}
41
42#[derive(Builder, Clone)]
51pub(crate) struct OrbitBasis<'g, G, I>
52where
53 G: GroupProperties,
54{
55 origins: Vec<I>,
57
58 group: &'g G,
61
62 #[builder(default = "None")]
66 prefactors: Option<
67 VecDeque<(
68 G::GroupElement,
69 fn(&G::GroupElement, &I) -> Result<I, anyhow::Error>,
70 )>,
71 >,
72
73 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 pub fn origins(&self) -> &Vec<I> {
88 &self.origins
89 }
90
91 pub fn group(&self) -> &G {
94 self.group
95 }
96
97 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
146pub 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 group_origin_iter: Product<
161 <<G as GroupProperties>::ElementCollection as IntoIterator>::IntoIter,
162 std::vec::IntoIter<I>,
163 >,
164
165 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 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 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#[derive(Builder, Clone)]
244pub(crate) struct EagerBasis<I: Clone> {
245 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}