use bitvec::prelude::*;
use rayon::prelude::*;
use rayon::slice::ParallelSliceMut;
use crate::common::{ConfigMode, PRIME_ROOTS, align_to_cycle};
use crate::sieve::{SieveMode, get_raw_composites};
pub trait PrimeRootFilters {
fn filter_twins(&self) -> Vec<u8>;
fn filter_triplets(&self) -> Vec<u8>;
fn filter_quadruplets(&self) -> Vec<u8>;
fn filter_quintuplets(&self) -> Vec<u8>;
fn filter_sextuplets(&self) -> Vec<u8>;
}
impl PrimeRootFilters for [u8; 48] {
fn filter_twins(&self) -> Vec<u8> {
self.windows(2)
.enumerate()
.filter_map(|(i, pair)| (pair[1] == pair[0] + 2).then_some(i as u8))
.collect()
}
fn filter_triplets(&self) -> Vec<u8> {
self.windows(3)
.enumerate()
.filter_map(|(i, triple)| {
let (a, b, c) = (triple[0], triple[1], triple[2]);
let valid = a + 6 == c && (a + 2 == b || a + 4 == b);
valid.then_some(i as u8) })
.collect()
}
fn filter_quadruplets(&self) -> Vec<u8> {
self.windows(4)
.enumerate()
.filter_map(|(i, quad)| {
let (a, b, c, d) = (quad[0], quad[1], quad[2], quad[3]);
let valid = a + 8 == d && a + 6 == c && a + 2 == b;
valid.then_some(i as u8) })
.collect()
}
fn filter_quintuplets(&self) -> Vec<u8> {
self.windows(5)
.enumerate()
.filter_map(|(i, quint)| {
let (a, b, c, d, e) = (quint[0], quint[1], quint[2], quint[3], quint[4]);
let valid = a + 12 == e
&& a + 6 == c
&& ((a + 10 == d && a + 4 == b) || (a + 8 == d && a + 2 == b));
valid.then_some(i as u8) })
.collect()
}
fn filter_sextuplets(&self) -> Vec<u8> {
self.windows(6)
.enumerate()
.filter_map(|(i, hex)| {
let (a, b, c, d, e, f) = (hex[0], hex[1], hex[2], hex[3], hex[4], hex[5]);
let valid = a + 16 == f && a + 12 == e && a + 10 == d && a + 6 == c && a + 4 == b;
valid.then_some(i as u8) })
.collect()
}
}
fn expand_indices(indices: &[u8], count: u8) -> Vec<u8> {
let mut unique_roots: Vec<u8> = indices
.iter()
.flat_map(|&i| (0..count).map(move |offset| i + offset))
.collect();
unique_roots.sort_unstable();
unique_roots.dedup();
unique_roots
}
fn find_constellation<T, F, G>(
start: u128,
end: u128,
mode: &ConfigMode,
filter_method: fn(&[u8; 48]) -> Vec<u8>,
group_size: usize,
initial_primes: &[T],
create_tuple: F,
include_initial: G,
) -> Vec<T>
where
T: Ord + Send + Clone,
F: Fn(u128, &[u128]) -> T + Sync + Send + Clone,
G: Fn(&T) -> bool + Sync,
{
let indices = filter_method(&PRIME_ROOTS);
let mut unique_roots = expand_indices(&indices, group_size as u8);
unique_roots.sort_unstable();
unique_roots.dedup();
let (b_start, b_end) = align_to_cycle(start, end);
let composites = get_raw_composites(unique_roots, start, end, &SieveMode::Sieve);
let mut primes: Vec<T> = indices
.into_par_iter()
.filter(|&i| (i as usize + group_size) <= PRIME_ROOTS.len())
.flat_map(|i| {
let roots: Vec<u128> = (0..group_size)
.map(|offset| PRIME_ROOTS[i as usize + offset] as u128)
.collect();
let tuple_creator = create_tuple.clone();
let combined = (0..group_size)
.map(|offset| composites[&(i + offset as u8)].as_bitslice())
.fold(bitvec![0; (b_end - b_start) as usize], |acc, slice| {
acc | slice
});
combined
.iter_zeros()
.map(move |pos| {
let base = (b_start + pos as u128) * 210;
tuple_creator(base, &roots)
})
.collect::<Vec<_>>()
})
.collect();
primes.extend(
initial_primes
.iter()
.filter(|t| include_initial(t))
.cloned(),
);
primes.par_sort_unstable();
primes
}
fn count_constellation(
start: u128,
end: u128,
mode: &ConfigMode,
filter_method: fn(&[u8; 48]) -> Vec<u8>,
group_size: usize,
) -> usize {
let indices = filter_method(&PRIME_ROOTS);
let mut unique_roots = expand_indices(&indices, group_size as u8);
unique_roots.sort_unstable();
unique_roots.dedup();
let (b_start, b_end) = align_to_cycle(start, end);
let composites = get_raw_composites(unique_roots, start, end, &SieveMode::Sieve);
let sieve_count: usize = indices
.into_par_iter()
.filter(|&i| (i as usize + group_size) <= PRIME_ROOTS.len())
.map(|i| {
(0..group_size)
.map(|offset| composites[&(i + offset as u8)].as_bitslice())
.fold(bitvec![0; (b_end - b_start) as usize], |acc, slice| {
acc | slice
})
.count_zeros()
})
.sum();
sieve_count
}
pub fn get_twins(start: u128, end: u128, mode: &ConfigMode) -> Vec<(u128, u128)> {
find_constellation(
start,
end,
mode,
PrimeRootFilters::filter_twins,
2,
&[(3, 5), (5, 7)],
|base, roots| (base + roots[0], base + roots[1]),
|&(p1, p2)| p1 >= start && p2 <= end,
)
}
pub fn get_triplets(start: u128, end: u128, mode: &ConfigMode) -> Vec<(u128, u128, u128)> {
find_constellation(
start,
end,
mode,
PrimeRootFilters::filter_triplets,
3,
&[(5, 7, 11), (7, 11, 13)],
|base, roots| (base + roots[0], base + roots[1], base + roots[2]),
|&(p1, _, p3)| p1 >= start && p3 <= end,
)
}
pub fn get_quadruplets(start: u128, end: u128, mode: &ConfigMode) -> Vec<(u128, u128, u128, u128)> {
find_constellation(
start,
end,
mode,
PrimeRootFilters::filter_quadruplets,
4,
&[(5, 7, 11, 13)],
|base, roots| {
(
base + roots[0],
base + roots[1],
base + roots[2],
base + roots[3],
)
},
|&(p1, _, _, p4)| p1 >= start && p4 <= end,
)
}
pub fn get_quintuplets(
start: u128,
end: u128,
mode: &ConfigMode,
) -> Vec<(u128, u128, u128, u128, u128)> {
find_constellation(
start,
end,
mode,
PrimeRootFilters::filter_quintuplets,
5,
&[(5, 7, 11, 13, 17), (7, 11, 13, 17, 19)],
|base, roots| {
(
base + roots[0],
base + roots[1],
base + roots[2],
base + roots[3],
base + roots[4],
)
},
|&(p1, _, _, _, p5)| p1 >= start && p5 <= end,
)
}
pub fn get_sextuplets(
start: u128,
end: u128,
mode: &ConfigMode,
) -> Vec<(u128, u128, u128, u128, u128, u128)> {
find_constellation(
start,
end,
mode,
PrimeRootFilters::filter_sextuplets,
6,
&[(7, 11, 13, 17, 19, 23)],
|base, roots| {
(
base + roots[0],
base + roots[1],
base + roots[2],
base + roots[3],
base + roots[4],
base + roots[5],
)
},
|&(p1, _, _, _, _, p6)| p1 >= start && p6 <= end,
)
}
pub fn count_twins(start: u128, end: u128, mode: &ConfigMode) -> usize {
let mut count = count_constellation(start, end, mode, PrimeRootFilters::filter_twins, 2);
count += [(3, 5), (5, 7)]
.iter()
.filter(|&&(p1, p2)| p1 >= start && p2 <= end)
.count();
count
}
pub fn count_triplets(start: u128, end: u128, mode: &ConfigMode) -> usize {
let mut count = count_constellation(start, end, mode, PrimeRootFilters::filter_triplets, 3);
count += [(5, 7, 11), (7, 11, 13)]
.iter()
.filter(|&&(p1, _, p3)| p1 >= start && p3 <= end)
.count();
count
}
pub fn count_quadruplets(start: u128, end: u128, mode: &ConfigMode) -> usize {
let mut count = count_constellation(start, end, mode, PrimeRootFilters::filter_quadruplets, 4);
count += [(5, 7, 11, 13)]
.iter()
.filter(|&&(p1, _, _, p4)| p1 >= start && p4 <= end)
.count();
count
}
pub fn count_quintuplets(start: u128, end: u128, mode: &ConfigMode) -> usize {
let mut count = count_constellation(start, end, mode, PrimeRootFilters::filter_quintuplets, 5);
count += [(5, 7, 11, 13, 17), (7, 11, 13, 17, 19)]
.iter()
.filter(|&&(p1, _, _, _, p5)| p1 >= start && p5 <= end)
.count();
count
}
pub fn count_sextuplets(start: u128, end: u128, mode: &ConfigMode) -> usize {
let mut count = count_constellation(start, end, mode, PrimeRootFilters::filter_sextuplets, 6);
count += [(7, 11, 13, 17, 19, 23)]
.iter()
.filter(|&&(p1, _, _, _, _, p6)| p1 >= start && p6 <= end)
.count();
count
}