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 {
141 OrbitBasisIterator::new(
142 self.prefactors.clone(),
143 self.group,
144 self.origins.clone(),
145 self.action,
146 )
147 }
148
149 fn first(&self) -> Option<I> {
150 if let Some(prefactors) = self.prefactors.as_ref() {
151 prefactors
152 .iter()
153 .rev()
154 .try_fold(self.origins.first()?.clone(), |acc, (symop, action)| {
155 (action)(symop, &acc).ok()
156 })
157 } else {
158 self.origins.first().cloned()
159 }
160 }
161}
162
163pub struct OrbitBasisIterator<G, I>
166where
167 G: GroupProperties,
168{
169 #[allow(clippy::type_complexity)]
170 prefactors: Option<
171 VecDeque<(
172 G::GroupElement,
173 fn(&G::GroupElement, &I) -> Result<I, anyhow::Error>,
174 )>,
175 >,
176
177 group_origin_iter: Product<
179 <<G as GroupProperties>::ElementCollection as IntoIterator>::IntoIter,
180 std::vec::IntoIter<I>,
181 >,
182
183 action: fn(&G::GroupElement, &I) -> Result<I, anyhow::Error>,
185}
186
187impl<G, I> OrbitBasisIterator<G, I>
188where
189 G: GroupProperties,
190 I: Clone,
191{
192 #[allow(clippy::type_complexity)]
204 fn new(
205 prefactors: Option<
206 VecDeque<(
207 G::GroupElement,
208 fn(&G::GroupElement, &I) -> Result<I, anyhow::Error>,
209 )>,
210 >,
211 group: &G,
212 origins: Vec<I>,
213 action: fn(&G::GroupElement, &I) -> Result<I, anyhow::Error>,
214 ) -> Self {
215 Self {
216 prefactors,
217 group_origin_iter: group
218 .elements()
219 .clone()
220 .into_iter()
221 .cartesian_product(origins),
222 action,
223 }
224 }
225}
226
227impl<G, I> Iterator for OrbitBasisIterator<G, I>
228where
229 G: GroupProperties,
230 I: Clone,
231{
232 type Item = Result<I, anyhow::Error>;
233
234 fn next(&mut self) -> Option<Self::Item> {
235 if let Some(prefactors) = self.prefactors.as_ref() {
236 self.group_origin_iter.next().and_then(|(op, origin)| {
242 prefactors
243 .iter()
244 .rev()
245 .try_fold((self.action)(&op, &origin), |acc_res, (symop, action)| {
246 acc_res.map(|acc| (action)(symop, &acc))
247 })
248 .ok()
249 })
250 } else {
251 self.group_origin_iter
252 .next()
253 .map(|(op, origin)| (self.action)(&op, &origin))
254 }
255 }
256}
257
258#[derive(Builder, Clone)]
263pub struct EagerBasis<I: Clone> {
264 elements: Vec<I>,
266}
267
268impl<I: Clone> EagerBasis<I> {
269 pub fn builder() -> EagerBasisBuilder<I> {
270 EagerBasisBuilder::default()
271 }
272}
273
274impl<I: Clone> Basis<I> for EagerBasis<I> {
275 type BasisIter = std::vec::IntoIter<Result<I, anyhow::Error>>;
276
277 fn n_items(&self) -> usize {
278 self.elements.len()
279 }
280
281 fn iter(&self) -> Self::BasisIter {
282 self.elements
283 .iter()
284 .cloned()
285 .map(Ok)
286 .collect_vec()
287 .into_iter()
288 }
289
290 fn first(&self) -> Option<I> {
291 self.elements.first().cloned()
292 }
293}