use crate::markoff::*;
use crate::numbers::*;
use crate::streams::*;
use rayon::iter::plumbing::*;
use rayon::iter::*;
#[derive(Clone)]
pub struct CoordStream<'a, S, const L_HYPER: usize, const L_ELLIP: usize, const P: u128>
where
FpNum<P>: SylowDecomposable<S>,
QuadNum<P>: SylowDecomposable<S>,
{
hyper_stream: Option<SylowStream<S, L_HYPER, FpNum<P>, ()>>,
ellip_stream: Option<SylowStream<S, L_ELLIP, QuadNum<P>, ()>>,
hyper_decomp: &'a SylowDecomp<S, L_HYPER, FpNum<P>>,
ellip_decomp: &'a SylowDecomp<S, L_ELLIP, QuadNum<P>>,
}
impl<'a, S, const L_HYPER: usize, const L_ELLIP: usize, const P: u128>
CoordStream<'a, S, L_HYPER, L_ELLIP, P>
where
FpNum<P>: SylowDecomposable<S>,
QuadNum<P>: SylowDecomposable<S>,
{
pub fn new(
hyper_decomp: &'a SylowDecomp<S, L_HYPER, FpNum<P>>,
ellip_decomp: &'a SylowDecomp<S, L_ELLIP, QuadNum<P>>,
hyper_lim: u128,
ellip_lim: u128,
) -> CoordStream<'a, S, L_HYPER, L_ELLIP, P> {
let hyper_stream = DivisorStream::new(FpNum::FACTORS.factors(), hyper_lim, true)
.map(|v| v.try_into().unwrap())
.fold(
SylowStreamBuilder::<S, L_HYPER, FpNum<P>, ()>::new()
.add_flag(flags::NO_PARABOLIC)
.add_flag(flags::NO_UPPER_HALF)
.add_flag(flags::LEQ),
|b, x| b.add_target(&x),
)
.into_iter();
let ellip_stream = DivisorStream::new(QuadNum::FACTORS.factors(), ellip_lim, true)
.map(|v| v.try_into().unwrap())
.fold(
SylowStreamBuilder::<S, L_ELLIP, QuadNum<P>, ()>::new()
.add_flag(flags::NO_PARABOLIC)
.add_flag(flags::NO_UPPER_HALF)
.add_flag(flags::LEQ),
|b, x| b.add_target(&x),
)
.into_iter();
CoordStream {
hyper_stream: Some(hyper_stream),
ellip_stream: Some(ellip_stream),
hyper_decomp,
ellip_decomp,
}
}
pub fn upper_triangle(self) -> impl ParallelIterator<Item = (Coord<P>, Coord<P>)> + 'a
where
S: Clone + Send + Sync,
{
#[derive(Clone)]
struct Helper<I>(I);
impl<I: Iterator + Clone> Iterator for Helper<I> {
type Item = (I, I::Item);
fn next(&mut self) -> Option<Self::Item> {
let iter = self.0.clone();
let Some(a) = self.0.next() else {
return None;
};
Some((iter, a))
}
}
Helper(self)
.par_bridge()
.flat_map(|(iter, a)| ParallelIterator::map(iter, move |b| (a, b)))
}
}
impl<'a, S, const L_HYPER: usize, const L_ELLIP: usize, const P: u128> Iterator
for CoordStream<'a, S, L_HYPER, L_ELLIP, P>
where
FpNum<P>: SylowDecomposable<S>,
QuadNum<P>: SylowDecomposable<S>,
{
type Item = Coord<P>;
fn next(&mut self) -> Option<Self::Item> {
if let Some(stream) = self.hyper_stream.as_mut() {
if let Some((a, _)) = stream.next() {
return Some(Coord(FpNum::from_chi(&a, self.hyper_decomp)));
}
self.hyper_stream = None;
}
if let Some(stream) = self.ellip_stream.as_mut() {
if let Some((a, _)) = stream.next() {
return Some(Coord(QuadNum::from_chi(&a, self.ellip_decomp)));
}
self.ellip_stream = None;
}
None
}
}
impl<'a, S, const L_HYPER: usize, const L_ELLIP: usize, const P: u128> ParallelIterator
for CoordStream<'a, S, L_HYPER, L_ELLIP, P>
where
S: Send + Sync,
FpNum<P>: SylowDecomposable<S>,
QuadNum<P>: SylowDecomposable<S>,
{
type Item = Coord<P>;
fn drive_unindexed<C>(self, consumer: C) -> C::Result
where
C: UnindexedConsumer<Self::Item>,
{
let left = self.hyper_stream.map(|stream| {
stream
.parallelize()
.map(|(x, _)| Coord(FpNum::from_chi(&x, self.hyper_decomp)))
.drive_unindexed(consumer.split_off_left())
});
let right = self.ellip_stream.map(|stream| {
stream
.parallelize()
.map(|(x, _)| Coord(QuadNum::from_chi(&x, self.ellip_decomp)))
.drive_unindexed(consumer.split_off_left())
});
match (left, right) {
(Some(l), Some(r)) => consumer.to_reducer().reduce(l, r),
(None, Some(r)) => r,
(None, None) => consumer.into_folder().complete(),
(Some(l), None) => l,
}
}
}