1use std::collections::VecDeque;
4
5use anyhow::{self, format_err};
6use derive_builder::Builder;
7use itertools::Itertools;
8use itertools::structs::Product;
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 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 #[allow(clippy::type_complexity)]
67 prefactors: Option<
68 VecDeque<(
69 G::GroupElement,
70 fn(&G::GroupElement, &I) -> Result<I, anyhow::Error>,
71 )>,
72 >,
73
74 action: fn(&G::GroupElement, &I) -> Result<I, anyhow::Error>,
76}
77
78impl<'g, G, I> OrbitBasis<'g, G, I>
79where
80 G: GroupProperties + Clone,
81 I: Clone,
82{
83 pub fn builder() -> OrbitBasisBuilder<'g, G, I> {
84 OrbitBasisBuilder::<'g, G, I>::default()
85 }
86
87 pub fn origins(&self) -> &Vec<I> {
89 &self.origins
90 }
91
92 pub fn group(&self) -> &G {
95 self.group
96 }
97
98 #[allow(clippy::type_complexity)]
102 pub fn prefactors(
103 &self,
104 ) -> Option<
105 &VecDeque<(
106 G::GroupElement,
107 fn(&G::GroupElement, &I) -> Result<I, anyhow::Error>,
108 )>,
109 > {
110 self.prefactors.as_ref()
111 }
112}
113
114impl<'g, G, I> OrbitBasis<'g, G, I>
115where
116 G: GroupProperties,
117 I: Clone,
118{
119 pub fn to_eager(&self) -> Result<EagerBasis<I>, anyhow::Error> {
121 let elements = self.iter().collect::<Result<Vec<_>, _>>()?;
122 EagerBasis::builder()
123 .elements(elements)
124 .build()
125 .map_err(|err| format_err!(err))
126 }
127}
128
129impl<'g, G, I> Basis<I> for OrbitBasis<'g, G, I>
130where
131 G: GroupProperties,
132 I: Clone,
133{
134 type BasisIter = OrbitBasisIterator<G, I>;
135
136 fn n_items(&self) -> usize {
137 self.origins.len() * self.group.order()
138 }
139
140 fn iter(&self) -> Self::BasisIter {
144 OrbitBasisIterator::new(
145 self.prefactors.clone(),
146 self.group,
147 self.origins.clone(),
148 self.action,
149 )
150 }
151
152 fn first(&self) -> Option<I> {
153 if let Some(prefactors) = self.prefactors.as_ref() {
154 prefactors
155 .iter()
156 .rev()
157 .try_fold(self.origins.first()?.clone(), |acc, (symop, action)| {
158 (action)(symop, &acc).ok()
159 })
160 } else {
161 self.origins.first().cloned()
162 }
163 }
164}
165
166pub struct OrbitBasisIterator<G, I>
169where
170 G: GroupProperties,
171{
172 #[allow(clippy::type_complexity)]
173 prefactors: Option<
174 VecDeque<(
175 G::GroupElement,
176 fn(&G::GroupElement, &I) -> Result<I, anyhow::Error>,
177 )>,
178 >,
179
180 group_origin_iter: Product<
182 <<G as GroupProperties>::ElementCollection as IntoIterator>::IntoIter,
183 std::vec::IntoIter<I>,
184 >,
185
186 action: fn(&G::GroupElement, &I) -> Result<I, anyhow::Error>,
188}
189
190impl<G, I> OrbitBasisIterator<G, I>
191where
192 G: GroupProperties,
193 I: Clone,
194{
195 #[allow(clippy::type_complexity)]
210 fn new(
211 prefactors: Option<
212 VecDeque<(
213 G::GroupElement,
214 fn(&G::GroupElement, &I) -> Result<I, anyhow::Error>,
215 )>,
216 >,
217 group: &G,
218 origins: Vec<I>,
219 action: fn(&G::GroupElement, &I) -> Result<I, anyhow::Error>,
220 ) -> Self {
221 Self {
222 prefactors,
223 group_origin_iter: group
224 .elements()
225 .clone()
226 .into_iter()
227 .cartesian_product(origins),
228 action,
229 }
230 }
231}
232
233impl<G, I> Iterator for OrbitBasisIterator<G, I>
234where
235 G: GroupProperties,
236 I: Clone,
237{
238 type Item = Result<I, anyhow::Error>;
239
240 fn next(&mut self) -> Option<Self::Item> {
241 if let Some(prefactors) = self.prefactors.as_ref() {
242 self.group_origin_iter.next().and_then(|(op, origin)| {
248 prefactors
249 .iter()
250 .rev()
251 .try_fold((self.action)(&op, &origin), |acc_res, (symop, action)| {
252 acc_res.map(|acc| (action)(symop, &acc))
253 })
254 .ok()
255 })
256 } else {
257 self.group_origin_iter
258 .next()
259 .map(|(op, origin)| (self.action)(&op, &origin))
260 }
261 }
262}
263
264#[derive(Builder, Clone)]
269pub struct EagerBasis<I: Clone> {
270 elements: Vec<I>,
272}
273
274impl<I: Clone> EagerBasis<I> {
275 pub fn builder() -> EagerBasisBuilder<I> {
276 EagerBasisBuilder::default()
277 }
278}
279
280impl<I: Clone> Basis<I> for EagerBasis<I> {
281 type BasisIter = std::vec::IntoIter<Result<I, anyhow::Error>>;
282
283 fn n_items(&self) -> usize {
284 self.elements.len()
285 }
286
287 fn iter(&self) -> Self::BasisIter {
288 self.elements
289 .iter()
290 .cloned()
291 .map(Ok)
292 .collect_vec()
293 .into_iter()
294 }
295
296 fn first(&self) -> Option<I> {
297 self.elements.first().cloned()
298 }
299}