mirror of
https://github.com/arnaucube/poulpy.git
synced 2026-02-10 21:26:41 +01:00
Remove Zn (replaced by VecZnx), add more cross-base2k ops & tests
This commit is contained in:
@@ -2,7 +2,7 @@ use itertools::izip;
|
||||
use rug::{Assign, Float};
|
||||
|
||||
use crate::{
|
||||
layouts::{DataMut, DataRef, VecZnx, VecZnxToMut, VecZnxToRef, Zn, ZnToMut, ZnToRef, ZnxInfos, ZnxView, ZnxViewMut},
|
||||
layouts::{DataMut, DataRef, VecZnx, VecZnxToMut, VecZnxToRef, ZnxInfos, ZnxView, ZnxViewMut},
|
||||
reference::znx::{
|
||||
ZnxNormalizeFinalStepInplace, ZnxNormalizeFirstStepInplace, ZnxNormalizeMiddleStepInplace, ZnxRef, ZnxZero,
|
||||
get_carry_i128, get_digit_i128, znx_zero_ref,
|
||||
@@ -245,90 +245,6 @@ impl<D: DataRef> VecZnx<D> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<D: DataMut> Zn<D> {
|
||||
pub fn encode_i64(&mut self, base2k: usize, k: usize, data: i64) {
|
||||
let size: usize = k.div_ceil(base2k);
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
{
|
||||
let a: Zn<&mut [u8]> = self.to_mut();
|
||||
assert!(
|
||||
size <= a.size(),
|
||||
"invalid argument k.div_ceil(base2k)={} > a.size()={}",
|
||||
size,
|
||||
a.size()
|
||||
);
|
||||
}
|
||||
|
||||
let mut a: Zn<&mut [u8]> = self.to_mut();
|
||||
let a_size = a.size();
|
||||
|
||||
for j in 0..a_size {
|
||||
a.at_mut(0, j)[0] = 0
|
||||
}
|
||||
|
||||
a.at_mut(0, size - 1)[0] = data;
|
||||
|
||||
let mut carry: Vec<i64> = vec![0i64; 1];
|
||||
let k_rem: usize = (base2k - (k % base2k)) % base2k;
|
||||
|
||||
for j in (0..size).rev() {
|
||||
let slice = &mut a.at_mut(0, j)[..1];
|
||||
|
||||
if j == size - 1 {
|
||||
ZnxRef::znx_normalize_first_step_inplace(base2k, k_rem, slice, &mut carry);
|
||||
} else if j == 0 {
|
||||
ZnxRef::znx_normalize_final_step_inplace(base2k, k_rem, slice, &mut carry);
|
||||
} else {
|
||||
ZnxRef::znx_normalize_middle_step_inplace(base2k, k_rem, slice, &mut carry);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<D: DataRef> Zn<D> {
|
||||
pub fn decode_i64(&self, base2k: usize, k: usize) -> i64 {
|
||||
let a: Zn<&[u8]> = self.to_ref();
|
||||
let size: usize = k.div_ceil(base2k);
|
||||
let mut res: i64 = 0;
|
||||
let rem: usize = base2k - (k % base2k);
|
||||
(0..size).for_each(|j| {
|
||||
let x: i64 = a.at(0, j)[0];
|
||||
if j == size - 1 && rem != base2k {
|
||||
let k_rem: usize = (base2k - rem) % base2k;
|
||||
let scale: i64 = 1 << rem as i64;
|
||||
res = (res << k_rem) + div_round(x, scale);
|
||||
} else {
|
||||
res = (res << base2k) + x;
|
||||
}
|
||||
});
|
||||
res
|
||||
}
|
||||
|
||||
pub fn decode_float(&self, base2k: usize) -> Float {
|
||||
let a: Zn<&[u8]> = self.to_ref();
|
||||
let size: usize = a.size();
|
||||
let prec: u32 = (base2k * size) as u32;
|
||||
|
||||
// 2^{base2k}
|
||||
let base: Float = Float::with_val(prec, (1 << base2k) as f64);
|
||||
let mut res: Float = Float::with_val(prec, (1 << base2k) as f64);
|
||||
|
||||
// y[i] = sum x[j][i] * 2^{-base2k*j}
|
||||
(0..size).for_each(|i| {
|
||||
if i == 0 {
|
||||
res.assign(a.at(0, size - i - 1)[0]);
|
||||
res /= &base;
|
||||
} else {
|
||||
res += Float::with_val(prec, a.at(0, size - i - 1)[0]);
|
||||
res /= &base;
|
||||
}
|
||||
});
|
||||
|
||||
res
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn div_round(a: i64, b: i64) -> i64 {
|
||||
assert!(b != 0, "division by zero");
|
||||
|
||||
@@ -10,7 +10,6 @@ mod vec_znx;
|
||||
mod vec_znx_big;
|
||||
mod vec_znx_dft;
|
||||
mod vmp_pmat;
|
||||
mod zn;
|
||||
mod znx_base;
|
||||
|
||||
pub use mat_znx::*;
|
||||
@@ -24,7 +23,6 @@ pub use vec_znx::*;
|
||||
pub use vec_znx_big::*;
|
||||
pub use vec_znx_dft::*;
|
||||
pub use vmp_pmat::*;
|
||||
pub use zn::*;
|
||||
pub use znx_base::*;
|
||||
|
||||
pub trait Data = PartialEq + Eq + Sized + Default;
|
||||
|
||||
@@ -1,273 +0,0 @@
|
||||
use std::{
|
||||
fmt,
|
||||
hash::{DefaultHasher, Hasher},
|
||||
};
|
||||
|
||||
use crate::{
|
||||
alloc_aligned,
|
||||
layouts::{
|
||||
Data, DataMut, DataRef, DataView, DataViewMut, DigestU64, FillUniform, ReaderFrom, ToOwnedDeep, WriterTo, ZnxInfos,
|
||||
ZnxSliceSize, ZnxView, ZnxViewMut, ZnxZero,
|
||||
},
|
||||
source::Source,
|
||||
};
|
||||
|
||||
use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
|
||||
use rand::RngCore;
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(PartialEq, Eq, Clone, Copy, Hash)]
|
||||
pub struct Zn<D: Data> {
|
||||
pub data: D,
|
||||
pub n: usize,
|
||||
pub cols: usize,
|
||||
pub size: usize,
|
||||
pub max_size: usize,
|
||||
}
|
||||
|
||||
impl<D: DataRef> DigestU64 for Zn<D> {
|
||||
fn digest_u64(&self) -> u64 {
|
||||
let mut h: DefaultHasher = DefaultHasher::new();
|
||||
h.write(self.data.as_ref());
|
||||
h.write_usize(self.n);
|
||||
h.write_usize(self.cols);
|
||||
h.write_usize(self.size);
|
||||
h.write_usize(self.max_size);
|
||||
h.finish()
|
||||
}
|
||||
}
|
||||
|
||||
impl<D: DataRef> ToOwnedDeep for Zn<D> {
|
||||
type Owned = Zn<Vec<u8>>;
|
||||
fn to_owned_deep(&self) -> Self::Owned {
|
||||
Zn {
|
||||
data: self.data.as_ref().to_vec(),
|
||||
n: self.n,
|
||||
cols: self.cols,
|
||||
size: self.size,
|
||||
max_size: self.max_size,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<D: DataRef> fmt::Debug for Zn<D> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "{self}")
|
||||
}
|
||||
}
|
||||
|
||||
impl<D: Data> ZnxInfos for Zn<D> {
|
||||
fn cols(&self) -> usize {
|
||||
self.cols
|
||||
}
|
||||
|
||||
fn rows(&self) -> usize {
|
||||
1
|
||||
}
|
||||
|
||||
fn n(&self) -> usize {
|
||||
self.n
|
||||
}
|
||||
|
||||
fn size(&self) -> usize {
|
||||
self.size
|
||||
}
|
||||
}
|
||||
|
||||
impl<D: Data> ZnxSliceSize for Zn<D> {
|
||||
fn sl(&self) -> usize {
|
||||
self.n() * self.cols()
|
||||
}
|
||||
}
|
||||
|
||||
impl<D: Data> DataView for Zn<D> {
|
||||
type D = D;
|
||||
fn data(&self) -> &Self::D {
|
||||
&self.data
|
||||
}
|
||||
}
|
||||
|
||||
impl<D: Data> DataViewMut for Zn<D> {
|
||||
fn data_mut(&mut self) -> &mut Self::D {
|
||||
&mut self.data
|
||||
}
|
||||
}
|
||||
|
||||
impl<D: DataRef> ZnxView for Zn<D> {
|
||||
type Scalar = i64;
|
||||
}
|
||||
|
||||
impl Zn<Vec<u8>> {
|
||||
pub fn rsh_tmp_bytes(n: usize) -> usize {
|
||||
n * std::mem::size_of::<i64>()
|
||||
}
|
||||
}
|
||||
|
||||
impl<D: DataMut> ZnxZero for Zn<D> {
|
||||
fn zero(&mut self) {
|
||||
self.raw_mut().fill(0)
|
||||
}
|
||||
fn zero_at(&mut self, i: usize, j: usize) {
|
||||
self.at_mut(i, j).fill(0);
|
||||
}
|
||||
}
|
||||
|
||||
impl Zn<Vec<u8>> {
|
||||
pub fn bytes_of(n: usize, cols: usize, size: usize) -> usize {
|
||||
n * cols * size * size_of::<i64>()
|
||||
}
|
||||
|
||||
pub fn alloc(n: usize, cols: usize, size: usize) -> Self {
|
||||
let data: Vec<u8> = alloc_aligned::<u8>(Self::bytes_of(n, cols, size));
|
||||
Self {
|
||||
data,
|
||||
n,
|
||||
cols,
|
||||
size,
|
||||
max_size: size,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_bytes<Scalar: Sized>(n: usize, cols: usize, size: usize, bytes: impl Into<Vec<u8>>) -> Self {
|
||||
let data: Vec<u8> = bytes.into();
|
||||
assert!(data.len() == Self::bytes_of(n, cols, size));
|
||||
Self {
|
||||
data,
|
||||
n,
|
||||
cols,
|
||||
size,
|
||||
max_size: size,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<D: Data> Zn<D> {
|
||||
pub fn from_data(data: D, n: usize, cols: usize, size: usize) -> Self {
|
||||
Self {
|
||||
data,
|
||||
n,
|
||||
cols,
|
||||
size,
|
||||
max_size: size,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<D: DataRef> fmt::Display for Zn<D> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
writeln!(
|
||||
f,
|
||||
"Zn(n={}, cols={}, size={})",
|
||||
self.n, self.cols, self.size
|
||||
)?;
|
||||
|
||||
for col in 0..self.cols {
|
||||
writeln!(f, "Column {col}:")?;
|
||||
for size in 0..self.size {
|
||||
let coeffs = self.at(col, size);
|
||||
write!(f, " Size {size}: [")?;
|
||||
|
||||
let max_show = 100;
|
||||
let show_count = coeffs.len().min(max_show);
|
||||
|
||||
for (i, &coeff) in coeffs.iter().take(show_count).enumerate() {
|
||||
if i > 0 {
|
||||
write!(f, ", ")?;
|
||||
}
|
||||
write!(f, "{coeff}")?;
|
||||
}
|
||||
|
||||
if coeffs.len() > max_show {
|
||||
write!(f, ", ... ({} more)", coeffs.len() - max_show)?;
|
||||
}
|
||||
|
||||
writeln!(f, "]")?;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl<D: DataMut> FillUniform for Zn<D> {
|
||||
fn fill_uniform(&mut self, log_bound: usize, source: &mut Source) {
|
||||
match log_bound {
|
||||
64 => source.fill_bytes(self.data.as_mut()),
|
||||
0 => panic!("invalid log_bound, cannot be zero"),
|
||||
_ => {
|
||||
let mask: u64 = (1u64 << log_bound) - 1;
|
||||
for x in self.raw_mut().iter_mut() {
|
||||
let r = source.next_u64() & mask;
|
||||
*x = ((r << (64 - log_bound)) as i64) >> (64 - log_bound);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub type ZnOwned = Zn<Vec<u8>>;
|
||||
pub type ZnMut<'a> = Zn<&'a mut [u8]>;
|
||||
pub type ZnRef<'a> = Zn<&'a [u8]>;
|
||||
|
||||
pub trait ZnToRef {
|
||||
fn to_ref(&self) -> Zn<&[u8]>;
|
||||
}
|
||||
|
||||
impl<D: DataRef> ZnToRef for Zn<D> {
|
||||
fn to_ref(&self) -> Zn<&[u8]> {
|
||||
Zn {
|
||||
data: self.data.as_ref(),
|
||||
n: self.n,
|
||||
cols: self.cols,
|
||||
size: self.size,
|
||||
max_size: self.max_size,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub trait ZnToMut {
|
||||
fn to_mut(&mut self) -> Zn<&mut [u8]>;
|
||||
}
|
||||
|
||||
impl<D: DataMut> ZnToMut for Zn<D> {
|
||||
fn to_mut(&mut self) -> Zn<&mut [u8]> {
|
||||
Zn {
|
||||
data: self.data.as_mut(),
|
||||
n: self.n,
|
||||
cols: self.cols,
|
||||
size: self.size,
|
||||
max_size: self.max_size,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<D: DataMut> ReaderFrom for Zn<D> {
|
||||
fn read_from<R: std::io::Read>(&mut self, reader: &mut R) -> std::io::Result<()> {
|
||||
self.n = reader.read_u64::<LittleEndian>()? as usize;
|
||||
self.cols = reader.read_u64::<LittleEndian>()? as usize;
|
||||
self.size = reader.read_u64::<LittleEndian>()? as usize;
|
||||
self.max_size = reader.read_u64::<LittleEndian>()? as usize;
|
||||
let len: usize = reader.read_u64::<LittleEndian>()? as usize;
|
||||
let buf: &mut [u8] = self.data.as_mut();
|
||||
if buf.len() != len {
|
||||
return Err(std::io::Error::new(
|
||||
std::io::ErrorKind::UnexpectedEof,
|
||||
format!("self.data.len()={} != read len={}", buf.len(), len),
|
||||
));
|
||||
}
|
||||
reader.read_exact(&mut buf[..len])?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl<D: DataRef> WriterTo for Zn<D> {
|
||||
fn write_to<W: std::io::Write>(&self, writer: &mut W) -> std::io::Result<()> {
|
||||
writer.write_u64::<LittleEndian>(self.n as u64)?;
|
||||
writer.write_u64::<LittleEndian>(self.cols as u64)?;
|
||||
writer.write_u64::<LittleEndian>(self.size as u64)?;
|
||||
writer.write_u64::<LittleEndian>(self.max_size as u64)?;
|
||||
let buf: &[u8] = self.data.as_ref();
|
||||
writer.write_u64::<LittleEndian>(buf.len() as u64)?;
|
||||
writer.write_all(buf)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user