poulpy/base2k/src/encoding.rs
base2k/src/encoding.rsRaw
1use crate::ffi::znx::znx_zero_i64_ref;
2use crate::{Infos, VecZnx};
3use itertools::izip;
4use rug::{Assign, Float};
5use std::cmp::min;
6
7pub trait Encoding {
8 /// encode a vector of i64 on the receiver.
9 ///
10 /// # Arguments
11 ///
12 /// * `poly_idx`: the index of the poly where to encode the data.
13 /// * `log_base2k`: base two negative logarithm decomposition of the receiver.
14 /// * `log_k`: base two negative logarithm of the scaling of the data.
15 /// * `data`: data to encode on the receiver.
16 /// * `log_max`: base two logarithm of the infinity norm of the input data.
17 fn encode_vec_i64(&mut self, poly_idx: usize, log_base2k: usize, log_k: usize, data: &[i64], log_max: usize);
18
19 /// decode a vector of i64 from the receiver.
20 ///
21 /// # Arguments
22 ///
23 /// * `poly_idx`: the index of the poly where to encode the data.
24 /// * `log_base2k`: base two negative logarithm decomposition of the receiver.
25 /// * `log_k`: base two logarithm of the scaling of the data.
26 /// * `data`: data to decode from the receiver.
27 fn decode_vec_i64(&self, poly_idx: usize, log_base2k: usize, log_k: usize, data: &mut [i64]);
28
29 /// decode a vector of Float from the receiver.
30 ///
31 /// # Arguments
32 /// * `poly_idx`: the index of the poly where to encode the data.
33 /// * `log_base2k`: base two negative logarithm decomposition of the receiver.
34 /// * `data`: data to decode from the receiver.
35 fn decode_vec_float(&self, poly_idx: usize, log_base2k: usize, data: &mut [Float]);
36
37 /// encodes a single i64 on the receiver at the given index.
38 ///
39 /// # Arguments
40 ///
41 /// * `poly_idx`: the index of the poly where to encode the data.
42 /// * `log_base2k`: base two negative logarithm decomposition of the receiver.
43 /// * `log_k`: base two negative logarithm of the scaling of the data.
44 /// * `i`: index of the coefficient on which to encode the data.
45 /// * `data`: data to encode on the receiver.
46 /// * `log_max`: base two logarithm of the infinity norm of the input data.
47 fn encode_coeff_i64(&mut self, poly_idx: usize, log_base2k: usize, log_k: usize, i: usize, data: i64, log_max: usize);
48
49 /// decode a single of i64 from the receiver at the given index.
50 ///
51 /// # Arguments
52 ///
53 /// * `poly_idx`: the index of the poly where to encode the data.
54 /// * `log_base2k`: base two negative logarithm decomposition of the receiver.
55 /// * `log_k`: base two negative logarithm of the scaling of the data.
56 /// * `i`: index of the coefficient to decode.
57 /// * `data`: data to decode from the receiver.
58 fn decode_coeff_i64(&self, poly_idx: usize, log_base2k: usize, log_k: usize, i: usize) -> i64;
59}
60
61impl Encoding for VecZnx {
62 fn encode_vec_i64(&mut self, poly_idx: usize, log_base2k: usize, log_k: usize, data: &[i64], log_max: usize) {
63 encode_vec_i64(self, poly_idx, log_base2k, log_k, data, log_max)
64 }
65
66 fn decode_vec_i64(&self, poly_idx: usize, log_base2k: usize, log_k: usize, data: &mut [i64]) {
67 decode_vec_i64(self, poly_idx, log_base2k, log_k, data)
68 }
69
70 fn decode_vec_float(&self, poly_idx: usize, log_base2k: usize, data: &mut [Float]) {
71 decode_vec_float(self, poly_idx, log_base2k, data)
72 }
73
74 fn encode_coeff_i64(&mut self, poly_idx: usize, log_base2k: usize, log_k: usize, i: usize, value: i64, log_max: usize) {
75 encode_coeff_i64(self, poly_idx, log_base2k, log_k, i, value, log_max)
76 }
77
78 fn decode_coeff_i64(&self, poly_idx: usize, log_base2k: usize, log_k: usize, i: usize) -> i64 {
79 decode_coeff_i64(self, poly_idx, log_base2k, log_k, i)
80 }
81}
82
83fn encode_vec_i64(a: &mut VecZnx, poly_idx: usize, log_base2k: usize, log_k: usize, data: &[i64], log_max: usize) {
84 let cols: usize = (log_k + log_base2k - 1) / log_base2k;
85
86 #[cfg(debug_assertions)]
87 {
88 assert!(
89 cols <= a.cols(),
90 "invalid argument log_k: (log_k + a.log_base2k - 1)/a.log_base2k={} > a.cols()={}",
91 cols,
92 a.cols()
93 );
94 assert!(poly_idx < a.size);
95 assert!(data.len() <= a.n())
96 }
97
98 let data_len: usize = data.len();
99 let log_k_rem: usize = log_base2k - (log_k % log_base2k);
100
101 (0..a.cols()).for_each(|i| unsafe {
102 znx_zero_i64_ref(a.n() as u64, a.at_poly_mut_ptr(poly_idx, i));
103 });
104
105 // If 2^{log_base2k} * 2^{k_rem} < 2^{63}-1, then we can simply copy
106 // values on the last limb.
107 // Else we decompose values base2k.
108 if log_max + log_k_rem < 63 || log_k_rem == log_base2k {
109 a.at_poly_mut(poly_idx, cols - 1)[..data_len].copy_from_slice(&data[..data_len]);
110 } else {
111 let mask: i64 = (1 << log_base2k) - 1;
112 let steps: usize = min(cols, (log_max + log_base2k - 1) / log_base2k);
113 (cols - steps..cols)
114 .rev()
115 .enumerate()
116 .for_each(|(i, i_rev)| {
117 let shift: usize = i * log_base2k;
118 izip!(a.at_poly_mut(poly_idx, i_rev).iter_mut(), data.iter()).for_each(|(y, x)| *y = (x >> shift) & mask);
119 })
120 }
121
122 // Case where self.prec % self.k != 0.
123 if log_k_rem != log_base2k {
124 let steps: usize = min(cols, (log_max + log_base2k - 1) / log_base2k);
125 (cols - steps..cols).rev().for_each(|i| {
126 a.at_poly_mut(poly_idx, i)[..data_len]
127 .iter_mut()
128 .for_each(|x| *x <<= log_k_rem);
129 })
130 }
131}
132
133fn decode_vec_i64(a: &VecZnx, poly_idx: usize, log_base2k: usize, log_k: usize, data: &mut [i64]) {
134 let cols: usize = (log_k + log_base2k - 1) / log_base2k;
135 #[cfg(debug_assertions)]
136 {
137 assert!(
138 data.len() >= a.n(),
139 "invalid data: data.len()={} < a.n()={}",
140 data.len(),
141 a.n()
142 );
143 assert!(poly_idx < a.size());
144 }
145 data.copy_from_slice(a.at_poly(poly_idx, 0));
146 let rem: usize = log_base2k - (log_k % log_base2k);
147 (1..cols).for_each(|i| {
148 if i == cols - 1 && rem != log_base2k {
149 let k_rem: usize = log_base2k - rem;
150 izip!(a.at_poly(poly_idx, i).iter(), data.iter_mut()).for_each(|(x, y)| {
151 *y = (*y << k_rem) + (x >> rem);
152 });
153 } else {
154 izip!(a.at_poly(poly_idx, i).iter(), data.iter_mut()).for_each(|(x, y)| {
155 *y = (*y << log_base2k) + x;
156 });
157 }
158 })
159}
160
161fn decode_vec_float(a: &VecZnx, poly_idx: usize, log_base2k: usize, data: &mut [Float]) {
162 let cols: usize = a.cols();
163 #[cfg(debug_assertions)]
164 {
165 assert!(
166 data.len() >= a.n(),
167 "invalid data: data.len()={} < a.n()={}",
168 data.len(),
169 a.n()
170 );
171 assert!(poly_idx < a.size());
172 }
173
174 let prec: u32 = (log_base2k * cols) as u32;
175
176 // 2^{log_base2k}
177 let base = Float::with_val(prec, (1 << log_base2k) as f64);
178
179 // y[i] = sum x[j][i] * 2^{-log_base2k*j}
180 (0..cols).for_each(|i| {
181 if i == 0 {
182 izip!(a.at_poly(poly_idx, cols - i - 1).iter(), data.iter_mut()).for_each(|(x, y)| {
183 y.assign(*x);
184 *y /= &base;
185 });
186 } else {
187 izip!(a.at_poly(poly_idx, cols - i - 1).iter(), data.iter_mut()).for_each(|(x, y)| {
188 *y += Float::with_val(prec, *x);
189 *y /= &base;
190 });
191 }
192 });
193}
194
195fn encode_coeff_i64(a: &mut VecZnx, poly_idx: usize, log_base2k: usize, log_k: usize, i: usize, value: i64, log_max: usize) {
196 let cols: usize = (log_k + log_base2k - 1) / log_base2k;
197
198 #[cfg(debug_assertions)]
199 {
200 assert!(i < a.n());
201 assert!(
202 cols <= a.cols(),
203 "invalid argument log_k: (log_k + a.log_base2k - 1)/a.log_base2k={} > a.cols()={}",
204 cols,
205 a.cols()
206 );
207 assert!(poly_idx < a.size());
208 }
209
210 let log_k_rem: usize = log_base2k - (log_k % log_base2k);
211 (0..a.cols()).for_each(|j| a.at_poly_mut(poly_idx, j)[i] = 0);
212
213 // If 2^{log_base2k} * 2^{log_k_rem} < 2^{63}-1, then we can simply copy
214 // values on the last limb.
215 // Else we decompose values base2k.
216 if log_max + log_k_rem < 63 || log_k_rem == log_base2k {
217 a.at_poly_mut(poly_idx, cols - 1)[i] = value;
218 } else {
219 let mask: i64 = (1 << log_base2k) - 1;
220 let steps: usize = min(cols, (log_max + log_base2k - 1) / log_base2k);
221 (cols - steps..cols)
222 .rev()
223 .enumerate()
224 .for_each(|(j, j_rev)| {
225 a.at_poly_mut(poly_idx, j_rev)[i] = (value >> (j * log_base2k)) & mask;
226 })
227 }
228
229 // Case where prec % k != 0.
230 if log_k_rem != log_base2k {
231 let steps: usize = min(cols, (log_max + log_base2k - 1) / log_base2k);
232 (cols - steps..cols).rev().for_each(|j| {
233 a.at_poly_mut(poly_idx, j)[i] <<= log_k_rem;
234 })
235 }
236}
237
238fn decode_coeff_i64(a: &VecZnx, poly_idx: usize, log_base2k: usize, log_k: usize, i: usize) -> i64 {
239 #[cfg(debug_assertions)]
240 {
241 assert!(i < a.n());
242 assert!(poly_idx < a.size())
243 }
244
245 let cols: usize = (log_k + log_base2k - 1) / log_base2k;
246 let data: &[i64] = a.raw();
247 let mut res: i64 = data[i];
248 let rem: usize = log_base2k - (log_k % log_base2k);
249 let slice_size: usize = a.n() * a.size();
250 (1..cols).for_each(|i| {
251 let x = data[i * slice_size];
252 if i == cols - 1 && rem != log_base2k {
253 let k_rem: usize = log_base2k - rem;
254 res = (res << k_rem) + (x >> rem);
255 } else {
256 res = (res << log_base2k) + x;
257 }
258 });
259 res
260}
261
262#[cfg(test)]
263mod tests {
264 use crate::{Encoding, VecZnx};
265 use itertools::izip;
266 use sampling::source::Source;
267
268 #[test]
269 fn test_set_get_i64_lo_norm() {
270 let n: usize = 8;
271 let log_base2k: usize = 17;
272 let cols: usize = 5;
273 let log_k: usize = cols * log_base2k - 5;
274 let mut a: VecZnx = VecZnx::new(n, 2, cols);
275 let mut source: Source = Source::new([0u8; 32]);
276 let raw: &mut [i64] = a.raw_mut();
277 raw.iter_mut().enumerate().for_each(|(i, x)| *x = i as i64);
278 (0..a.size()).for_each(|poly_idx| {
279 let mut have: Vec<i64> = vec![i64::default(); n];
280 have.iter_mut()
281 .for_each(|x| *x = (source.next_i64() << 56) >> 56);
282 a.encode_vec_i64(poly_idx, log_base2k, log_k, &have, 10);
283 let mut want: Vec<i64> = vec![i64::default(); n];
284 a.decode_vec_i64(poly_idx, log_base2k, log_k, &mut want);
285 izip!(want, have).for_each(|(a, b)| assert_eq!(a, b, "{} != {}", a, b));
286 });
287 }
288
289 #[test]
290 fn test_set_get_i64_hi_norm() {
291 let n: usize = 8;
292 let log_base2k: usize = 17;
293 let cols: usize = 5;
294 let log_k: usize = cols * log_base2k - 5;
295 let mut a: VecZnx = VecZnx::new(n, 2, cols);
296 let mut source = Source::new([0u8; 32]);
297 let raw: &mut [i64] = a.raw_mut();
298 raw.iter_mut().enumerate().for_each(|(i, x)| *x = i as i64);
299 (0..a.size()).for_each(|poly_idx| {
300 let mut have: Vec<i64> = vec![i64::default(); n];
301 have.iter_mut().for_each(|x| *x = source.next_i64());
302 a.encode_vec_i64(poly_idx, log_base2k, log_k, &have, 64);
303 let mut want = vec![i64::default(); n];
304 a.decode_vec_i64(poly_idx, log_base2k, log_k, &mut want);
305 izip!(want, have).for_each(|(a, b)| assert_eq!(a, b, "{} != {}", a, b));
306 })
307 }
308}