poulpy/math/src/ring/impl_u64/sampling.rs
math/src/ring/impl_u64/sampling.rsRaw
1use crate::modulus::WordOps;
2use crate::poly::{Poly, PolyRNS};
3use crate::ring::{Ring, RingRNS};
4use num::ToPrimitive;
5use rand_distr::{Distribution, Normal};
6use sampling::source::Source;
7
8impl Ring<u64> {
9 pub fn fill_uniform(&self, source: &mut Source, a: &mut Poly<u64>) {
10 let max: u64 = self.modulus.q;
11 let mask: u64 = max.mask();
12 a.0.iter_mut()
13 .for_each(|a| *a = source.next_u64n(max, mask));
14 }
15
16 pub fn fill_dist_f64<T: Distribution<f64>>(
17 &self,
18 source: &mut Source,
19 dist: T,
20 bound: f64,
21 a: &mut Poly<u64>,
22 ) {
23 let max: u64 = self.modulus.q;
24 a.0.iter_mut().for_each(|a| {
25 let mut dist_f64: f64 = dist.sample(source);
26
27 while dist_f64.abs() > bound {
28 dist_f64 = dist.sample(source)
29 }
30
31 let dist_u64: u64 = (dist_f64 + 0.5).abs().to_u64().unwrap();
32 let sign: u64 = dist_f64.to_bits() >> 63;
33
34 *a = (dist_u64 * sign) | (max - dist_u64) * (sign ^ 1)
35 });
36 }
37
38 pub fn fill_normal(&self, source: &mut Source, sigma: f64, bound: f64, a: &mut Poly<u64>){
39 self.fill_dist_f64(source, Normal::new(0.0, sigma).unwrap(), bound, a);
40 }
41}
42
43impl RingRNS<u64> {
44 pub fn fill_uniform(&self, source: &mut Source, a: &mut PolyRNS<u64>) {
45 self.0
46 .iter()
47 .enumerate()
48 .for_each(|(i, r)| r.fill_uniform(source, a.at_mut(i)));
49 }
50
51 pub fn fill_dist_f64<T: Distribution<f64>>(
52 &self,
53 source: &mut Source,
54 dist: T,
55 bound: f64,
56 a: &mut PolyRNS<u64>,
57 ) {
58 (0..a.n()).for_each(|j| {
59 let mut dist_f64: f64 = dist.sample(source);
60
61 while dist_f64.abs() > bound {
62 dist_f64 = dist.sample(source)
63 }
64
65 let dist_u64: u64 = (dist_f64 + 0.5).abs().to_u64().unwrap();
66 let sign: u64 = dist_f64.to_bits() >> 63;
67
68 self.0.iter().enumerate().for_each(|(i, r)| {
69 a.at_mut(i).0[j] = (dist_u64 * sign) | (r.modulus.q - dist_u64) * (sign ^ 1);
70 })
71 })
72 }
73}