arnaucube
arnaucube/poulpyPublic Self-hosted repository
poulpy/backend/src/vec_znx_dft_ops.rs
backend/src/vec_znx_dft_ops.rsRaw
  1use crate::ffi::{vec_znx_big, vec_znx_dft};
  2use crate::vec_znx_dft::bytes_of_vec_znx_dft;
  3use crate::znx_base::ZnxInfos;
  4use crate::{
  5    Backend, Scratch, VecZnxBig, VecZnxBigToMut, VecZnxDft, VecZnxDftOwned, VecZnxDftToMut, VecZnxDftToRef, VecZnxToRef,
  6    ZnxSliceSize,
  7};
  8use crate::{FFT64, Module, ZnxView, ZnxViewMut, ZnxZero};
  9use std::cmp::min;
 10
 11pub trait VecZnxDftAlloc<B: Backend> {
 12    /// Allocates a vector Z[X]/(X^N+1) that stores normalized in the DFT space.
 13    fn new_vec_znx_dft(&self, cols: usize, size: usize) -> VecZnxDftOwned<B>;
 14
 15    /// Returns a new [VecZnxDft] with the provided bytes array as backing array.
 16    ///
 17    /// Behavior: takes ownership of the backing array.
 18    ///
 19    /// # Arguments
 20    ///
 21    /// * `cols`: the number of cols of the [VecZnxDft].
 22    /// * `bytes`: a byte array of size at least [Module::bytes_of_vec_znx_dft].
 23    ///
 24    /// # Panics
 25    /// If `bytes.len()` < [Module::bytes_of_vec_znx_dft].
 26    fn new_vec_znx_dft_from_bytes(&self, cols: usize, size: usize, bytes: Vec<u8>) -> VecZnxDftOwned<B>;
 27
 28    /// Returns a new [VecZnxDft] with the provided bytes array as backing array.
 29    ///
 30    /// # Arguments
 31    ///
 32    /// * `cols`: the number of cols of the [VecZnxDft].
 33    /// * `bytes`: a byte array of size at least [Module::bytes_of_vec_znx_dft].
 34    ///
 35    /// # Panics
 36    /// If `bytes.len()` < [Module::bytes_of_vec_znx_dft].
 37    fn bytes_of_vec_znx_dft(&self, cols: usize, size: usize) -> usize;
 38}
 39
 40pub trait VecZnxDftOps<B: Backend> {
 41    /// Returns the minimum number of bytes necessary to allocate
 42    /// a new [VecZnxDft] through [VecZnxDft::from_bytes].
 43    fn vec_znx_idft_tmp_bytes(&self) -> usize;
 44
 45    fn vec_znx_dft_add<R, A, D>(&self, res: &mut R, res_col: usize, a: &A, a_col: usize, b: &D, b_col: usize)
 46    where
 47        R: VecZnxDftToMut<B>,
 48        A: VecZnxDftToRef<B>,
 49        D: VecZnxDftToRef<B>;
 50
 51    fn vec_znx_dft_add_inplace<R, A>(&self, res: &mut R, res_col: usize, a: &A, a_col: usize)
 52    where
 53        R: VecZnxDftToMut<B>,
 54        A: VecZnxDftToRef<B>;
 55
 56    fn vec_znx_dft_copy<R, A>(&self, res: &mut R, res_col: usize, a: &A, a_col: usize)
 57    where
 58        R: VecZnxDftToMut<B>,
 59        A: VecZnxDftToRef<B>;
 60
 61    /// b <- IDFT(a), uses a as scratch space.
 62    fn vec_znx_idft_tmp_a<R, A>(&self, res: &mut R, res_col: usize, a: &mut A, a_col: usize)
 63    where
 64        R: VecZnxBigToMut<B>,
 65        A: VecZnxDftToMut<B>;
 66
 67    /// Consumes a to return IDFT(a) in big coeff space.
 68    fn vec_znx_idft_consume<D>(&self, a: VecZnxDft<D, B>) -> VecZnxBig<D, FFT64>
 69    where
 70        VecZnxDft<D, FFT64>: VecZnxDftToMut<FFT64>;
 71
 72    fn vec_znx_idft<R, A>(&self, res: &mut R, res_col: usize, a: &A, a_col: usize, scratch: &mut Scratch)
 73    where
 74        R: VecZnxBigToMut<B>,
 75        A: VecZnxDftToRef<B>;
 76
 77    fn vec_znx_dft<R, A>(&self, res: &mut R, res_col: usize, a: &A, a_col: usize)
 78    where
 79        R: VecZnxDftToMut<B>,
 80        A: VecZnxToRef;
 81}
 82
 83impl<B: Backend> VecZnxDftAlloc<B> for Module<B> {
 84    fn new_vec_znx_dft(&self, cols: usize, size: usize) -> VecZnxDftOwned<B> {
 85        VecZnxDftOwned::new(&self, cols, size)
 86    }
 87
 88    fn new_vec_znx_dft_from_bytes(&self, cols: usize, size: usize, bytes: Vec<u8>) -> VecZnxDftOwned<B> {
 89        VecZnxDftOwned::new_from_bytes(self, cols, size, bytes)
 90    }
 91
 92    fn bytes_of_vec_znx_dft(&self, cols: usize, size: usize) -> usize {
 93        bytes_of_vec_znx_dft(self, cols, size)
 94    }
 95}
 96
 97impl VecZnxDftOps<FFT64> for Module<FFT64> {
 98    fn vec_znx_dft_add<R, A, D>(&self, res: &mut R, res_col: usize, a: &A, a_col: usize, b: &D, b_col: usize)
 99    where
100        R: VecZnxDftToMut<FFT64>,
101        A: VecZnxDftToRef<FFT64>,
102        D: VecZnxDftToRef<FFT64>,
103    {
104        let mut res_mut: VecZnxDft<&mut [u8], FFT64> = res.to_mut();
105        let a_ref: VecZnxDft<&[u8], FFT64> = a.to_ref();
106        let b_ref: VecZnxDft<&[u8], FFT64> = b.to_ref();
107
108        let min_size: usize = res_mut.size().min(a_ref.size()).min(b_ref.size());
109
110        unsafe {
111            (0..min_size).for_each(|j| {
112                vec_znx_dft::vec_dft_add(
113                    self.ptr,
114                    res_mut.at_mut_ptr(res_col, j) as *mut vec_znx_dft::vec_znx_dft_t,
115                    1,
116                    a_ref.at_ptr(a_col, j) as *const vec_znx_dft::vec_znx_dft_t,
117                    1,
118                    b_ref.at_ptr(b_col, j) as *const vec_znx_dft::vec_znx_dft_t,
119                    1,
120                );
121            });
122        }
123        (min_size..res_mut.size()).for_each(|j| {
124            res_mut.zero_at(res_col, j);
125        })
126    }
127
128    fn vec_znx_dft_add_inplace<R, A>(&self, res: &mut R, res_col: usize, a: &A, a_col: usize)
129    where
130        R: VecZnxDftToMut<FFT64>,
131        A: VecZnxDftToRef<FFT64>,
132    {
133        let mut res_mut: VecZnxDft<&mut [u8], FFT64> = res.to_mut();
134        let a_ref: VecZnxDft<&[u8], FFT64> = a.to_ref();
135
136        let min_size: usize = res_mut.size().min(a_ref.size());
137
138        unsafe {
139            (0..min_size).for_each(|j| {
140                vec_znx_dft::vec_dft_add(
141                    self.ptr,
142                    res_mut.at_mut_ptr(res_col, j) as *mut vec_znx_dft::vec_znx_dft_t,
143                    1,
144                    res_mut.at_ptr(res_col, j) as *const vec_znx_dft::vec_znx_dft_t,
145                    1,
146                    a_ref.at_ptr(a_col, j) as *const vec_znx_dft::vec_znx_dft_t,
147                    1,
148                );
149            });
150        }
151    }
152
153    fn vec_znx_dft_copy<R, A>(&self, res: &mut R, res_col: usize, a: &A, a_col: usize)
154    where
155        R: VecZnxDftToMut<FFT64>,
156        A: VecZnxDftToRef<FFT64>,
157    {
158        let mut res_mut: VecZnxDft<&mut [u8], FFT64> = res.to_mut();
159        let a_ref: VecZnxDft<&[u8], FFT64> = a.to_ref();
160
161        let min_size: usize = min(res_mut.size(), a_ref.size());
162
163        (0..min_size).for_each(|j| {
164            res_mut
165                .at_mut(res_col, j)
166                .copy_from_slice(a_ref.at(a_col, j));
167        });
168        (min_size..res_mut.size()).for_each(|j| {
169            res_mut.zero_at(res_col, j);
170        })
171    }
172
173    fn vec_znx_idft_tmp_a<R, A>(&self, res: &mut R, res_col: usize, a: &mut A, a_col: usize)
174    where
175        R: VecZnxBigToMut<FFT64>,
176        A: VecZnxDftToMut<FFT64>,
177    {
178        let mut res_mut: VecZnxBig<&mut [u8], FFT64> = res.to_mut();
179        let mut a_mut: VecZnxDft<&mut [u8], FFT64> = a.to_mut();
180
181        let min_size: usize = min(res_mut.size(), a_mut.size());
182
183        unsafe {
184            (0..min_size).for_each(|j| {
185                vec_znx_dft::vec_znx_idft_tmp_a(
186                    self.ptr,
187                    res_mut.at_mut_ptr(res_col, j) as *mut vec_znx_big::vec_znx_big_t,
188                    1 as u64,
189                    a_mut.at_mut_ptr(a_col, j) as *mut vec_znx_dft::vec_znx_dft_t,
190                    1 as u64,
191                )
192            });
193            (min_size..res_mut.size()).for_each(|j| {
194                res_mut.zero_at(res_col, j);
195            })
196        }
197    }
198
199    fn vec_znx_idft_consume<D>(&self, mut a: VecZnxDft<D, FFT64>) -> VecZnxBig<D, FFT64>
200    where
201        VecZnxDft<D, FFT64>: VecZnxDftToMut<FFT64>,
202    {
203        let mut a_mut: VecZnxDft<&mut [u8], FFT64> = a.to_mut();
204
205        unsafe {
206            // Rev col and rows because ZnxDft.sl() >= ZnxBig.sl()
207            (0..a_mut.size()).for_each(|j| {
208                (0..a_mut.cols()).for_each(|i| {
209                    vec_znx_dft::vec_znx_idft_tmp_a(
210                        self.ptr,
211                        a_mut.at_mut_ptr(i, j) as *mut vec_znx_big::vec_znx_big_t,
212                        1 as u64,
213                        a_mut.at_mut_ptr(i, j) as *mut vec_znx_dft::vec_znx_dft_t,
214                        1 as u64,
215                    )
216                });
217            });
218        }
219
220        a.into_big()
221    }
222
223    fn vec_znx_idft_tmp_bytes(&self) -> usize {
224        unsafe { vec_znx_dft::vec_znx_idft_tmp_bytes(self.ptr) as usize }
225    }
226
227    /// b <- DFT(a)
228    ///
229    /// # Panics
230    /// If b.cols < a_col
231    fn vec_znx_dft<R, A>(&self, res: &mut R, res_col: usize, a: &A, a_col: usize)
232    where
233        R: VecZnxDftToMut<FFT64>,
234        A: VecZnxToRef,
235    {
236        let mut res_mut: VecZnxDft<&mut [u8], FFT64> = res.to_mut();
237        let a_ref: crate::VecZnx<&[u8]> = a.to_ref();
238
239        let min_size: usize = min(res_mut.size(), a_ref.size());
240
241        unsafe {
242            (0..min_size).for_each(|j| {
243                vec_znx_dft::vec_znx_dft(
244                    self.ptr,
245                    res_mut.at_mut_ptr(res_col, j) as *mut vec_znx_dft::vec_znx_dft_t,
246                    1 as u64,
247                    a_ref.at_ptr(a_col, j),
248                    1 as u64,
249                    a_ref.sl() as u64,
250                )
251            });
252            (min_size..res_mut.size()).for_each(|j| {
253                res_mut.zero_at(res_col, j);
254            });
255        }
256    }
257
258    // b <- IDFT(a), scratch space size obtained with [vec_znx_idft_tmp_bytes].
259    fn vec_znx_idft<R, A>(&self, res: &mut R, res_col: usize, a: &A, a_col: usize, scratch: &mut Scratch)
260    where
261        R: VecZnxBigToMut<FFT64>,
262        A: VecZnxDftToRef<FFT64>,
263    {
264        let mut res_mut: VecZnxBig<&mut [u8], FFT64> = res.to_mut();
265        let a_ref: VecZnxDft<&[u8], FFT64> = a.to_ref();
266
267        let (tmp_bytes, _) = scratch.tmp_slice(self.vec_znx_idft_tmp_bytes());
268
269        let min_size: usize = min(res_mut.size(), a_ref.size());
270
271        unsafe {
272            (0..min_size).for_each(|j| {
273                vec_znx_dft::vec_znx_idft(
274                    self.ptr,
275                    res_mut.at_mut_ptr(res_col, j) as *mut vec_znx_big::vec_znx_big_t,
276                    1 as u64,
277                    a_ref.at_ptr(a_col, j) as *const vec_znx_dft::vec_znx_dft_t,
278                    1 as u64,
279                    tmp_bytes.as_mut_ptr(),
280                )
281            });
282            (min_size..res_mut.size()).for_each(|j| {
283                res_mut.zero_at(res_col, j);
284            });
285        }
286    }
287}