use std::fmt::Debug;
use std::ops::Range;
use feanor_math::seq::VectorFn;
use crate::ciphertext_ring::indices::RNSFactorIndexList;
#[repr(transparent)]
#[derive(Debug, PartialEq, Eq, Hash)]
pub struct RNSGadgetVectorDigitIndices {
digit_boundaries: [usize]
}
impl RNSGadgetVectorDigitIndices {
fn from_unchecked(digit_boundaries: Box<[usize]>) -> Box<Self> {
unsafe { std::mem::transmute(digit_boundaries) }
}
pub fn from<V>(digits: V) -> Box<Self>
where V: VectorFn<Range<usize>>
{
let mut result: Vec<usize> = Vec::with_capacity(digits.len());
for _ in 0..digits.len() {
let mut it = digits.iter().filter(|digit| digit.start == *result.last().unwrap_or(&0));
if let Some(next) = it.next() {
if it.next().is_some() {
panic!("multiple digits start at {}", result.last().unwrap_or(&0));
}
result.push(next.end);
} else {
panic!("no digit contains {}", result.last().unwrap_or(&0));
}
}
return Self::from_unchecked(result.into_boxed_slice());
}
pub fn rns_base_len(&self) -> usize {
*self.digit_boundaries.last().unwrap_or(&0)
}
pub fn select_digits(digits: usize, rns_base_len: usize) -> Box<Self> {
assert!(digits <= rns_base_len, "the number of gadget product digits may not exceed the number of RNS factors");
let moduli_per_small_digit = rns_base_len / digits;
let large_digits = rns_base_len % digits;
let small_digits = digits - large_digits;
let mut result = Vec::with_capacity(digits);
let mut current = 0;
for _ in 0..large_digits {
current += moduli_per_small_digit + 1;
result.push(current);
}
for _ in 0..small_digits {
current += moduli_per_small_digit;
result.push(current);
}
return Self::from_unchecked(result.into_boxed_slice());
}
pub fn remove_indices(&self, drop_rns_factors: &RNSFactorIndexList) -> Box<Self> {
for i in drop_rns_factors.iter() {
assert!(*i < self.rns_base_len());
}
let mut result = Vec::new();
let mut current_len = 0;
for range in self.iter() {
let dropped_els = drop_rns_factors.num_within(&range);
if dropped_els != range.end - range.start {
current_len += range.end - range.start - dropped_els;
result.push(current_len);
}
}
debug_assert!(*result.last().unwrap_or(&0) == self.rns_base_len() - drop_rns_factors.len());
return Self::from_unchecked(result.into_boxed_slice());
}
}
impl VectorFn<Range<usize>> for RNSGadgetVectorDigitIndices {
fn len(&self) -> usize {
self.digit_boundaries.len()
}
fn at(&self, i: usize) -> Range<usize> {
if i == 0 {
0..self.digit_boundaries[0]
} else {
self.digit_boundaries[i - 1]..self.digit_boundaries[i]
}
}
}
impl Clone for Box<RNSGadgetVectorDigitIndices> {
fn clone(&self) -> Self {
RNSGadgetVectorDigitIndices::from_unchecked(self.digit_boundaries.to_owned().into_boxed_slice())
}
}
impl ToOwned for RNSGadgetVectorDigitIndices {
type Owned = Box<Self>;
fn to_owned(&self) -> Self::Owned {
RNSGadgetVectorDigitIndices::from_unchecked(self.digit_boundaries.to_owned().into_boxed_slice())
}
}