arnaucube
arnaucube/poulpyPublic Self-hosted repository
poulpy/poulpy-backend/src/implementation/cpu_spqlios/vec_znx_big_fft64.rs
poulpy-backend/src/implementation/cpu_spqlios/vec_znx_big_fft64.rsRaw
  1use std::fmt;
  2
  3use rand_distr::{Distribution, Normal};
  4
  5use crate::{
  6    hal::{
  7        api::{
  8            TakeSlice, VecZnxBigAddDistF64, VecZnxBigFillDistF64, VecZnxBigNormalizeTmpBytes, ZnxInfos, ZnxSliceSize, ZnxView,
  9            ZnxViewMut,
 10        },
 11        layouts::{
 12            Data, DataRef, Module, Scratch, VecZnx, VecZnxBig, VecZnxBigBytesOf, VecZnxBigOwned, VecZnxBigToMut, VecZnxBigToRef,
 13            VecZnxToMut, VecZnxToRef,
 14        },
 15        oep::{
 16            VecZnxBigAddDistF64Impl, VecZnxBigAddImpl, VecZnxBigAddInplaceImpl, VecZnxBigAddNormalImpl, VecZnxBigAddSmallImpl,
 17            VecZnxBigAddSmallInplaceImpl, VecZnxBigAllocBytesImpl, VecZnxBigAllocImpl, VecZnxBigAutomorphismImpl,
 18            VecZnxBigAutomorphismInplaceImpl, VecZnxBigFillDistF64Impl, VecZnxBigFillNormalImpl, VecZnxBigFromBytesImpl,
 19            VecZnxBigNegateInplaceImpl, VecZnxBigNormalizeImpl, VecZnxBigNormalizeTmpBytesImpl, VecZnxBigSubABInplaceImpl,
 20            VecZnxBigSubBAInplaceImpl, VecZnxBigSubImpl, VecZnxBigSubSmallAImpl, VecZnxBigSubSmallAInplaceImpl,
 21            VecZnxBigSubSmallBImpl, VecZnxBigSubSmallBInplaceImpl,
 22        },
 23        source::Source,
 24    },
 25    implementation::cpu_spqlios::{ffi::vec_znx, module_fft64::FFT64},
 26};
 27
 28const VEC_ZNX_BIG_FFT64_WORDSIZE: usize = 1;
 29
 30impl<D: DataRef> ZnxView for VecZnxBig<D, FFT64> {
 31    type Scalar = i64;
 32}
 33
 34impl<D: Data> VecZnxBigBytesOf for VecZnxBig<D, FFT64> {
 35    fn bytes_of(n: usize, cols: usize, size: usize) -> usize {
 36        VEC_ZNX_BIG_FFT64_WORDSIZE * n * cols * size * size_of::<f64>()
 37    }
 38}
 39
 40impl<D: Data> ZnxSliceSize for VecZnxBig<D, FFT64> {
 41    fn sl(&self) -> usize {
 42        VEC_ZNX_BIG_FFT64_WORDSIZE * self.n() * self.cols()
 43    }
 44}
 45
 46unsafe impl VecZnxBigAllocImpl<FFT64> for FFT64 {
 47    fn vec_znx_big_alloc_impl(n: usize, cols: usize, size: usize) -> VecZnxBigOwned<FFT64> {
 48        VecZnxBig::<Vec<u8>, FFT64>::new(n, cols, size)
 49    }
 50}
 51
 52unsafe impl VecZnxBigFromBytesImpl<FFT64> for FFT64 {
 53    fn vec_znx_big_from_bytes_impl(n: usize, cols: usize, size: usize, bytes: Vec<u8>) -> VecZnxBigOwned<FFT64> {
 54        VecZnxBig::<Vec<u8>, FFT64>::new_from_bytes(n, cols, size, bytes)
 55    }
 56}
 57
 58unsafe impl VecZnxBigAllocBytesImpl<FFT64> for FFT64 {
 59    fn vec_znx_big_alloc_bytes_impl(n: usize, cols: usize, size: usize) -> usize {
 60        VecZnxBig::<Vec<u8>, FFT64>::bytes_of(n, cols, size)
 61    }
 62}
 63
 64unsafe impl VecZnxBigAddDistF64Impl<FFT64> for FFT64 {
 65    fn add_dist_f64_impl<R: VecZnxBigToMut<FFT64>, D: Distribution<f64>>(
 66        _module: &Module<FFT64>,
 67        basek: usize,
 68        res: &mut R,
 69        res_col: usize,
 70        k: usize,
 71        source: &mut Source,
 72        dist: D,
 73        bound: f64,
 74    ) {
 75        let mut res: VecZnxBig<&mut [u8], FFT64> = res.to_mut();
 76        assert!(
 77            (bound.log2().ceil() as i64) < 64,
 78            "invalid bound: ceil(log2(bound))={} > 63",
 79            (bound.log2().ceil() as i64)
 80        );
 81
 82        let limb: usize = k.div_ceil(basek) - 1;
 83        let basek_rem: usize = (limb + 1) * basek - k;
 84
 85        if basek_rem != 0 {
 86            res.at_mut(res_col, limb).iter_mut().for_each(|x| {
 87                let mut dist_f64: f64 = dist.sample(source);
 88                while dist_f64.abs() > bound {
 89                    dist_f64 = dist.sample(source)
 90                }
 91                *x += (dist_f64.round() as i64) << basek_rem;
 92            });
 93        } else {
 94            res.at_mut(res_col, limb).iter_mut().for_each(|x| {
 95                let mut dist_f64: f64 = dist.sample(source);
 96                while dist_f64.abs() > bound {
 97                    dist_f64 = dist.sample(source)
 98                }
 99                *x += dist_f64.round() as i64
100            });
101        }
102    }
103}
104
105unsafe impl VecZnxBigAddNormalImpl<FFT64> for FFT64 {
106    fn add_normal_impl<R: VecZnxBigToMut<FFT64>>(
107        module: &Module<FFT64>,
108        basek: usize,
109        res: &mut R,
110        res_col: usize,
111        k: usize,
112        source: &mut Source,
113        sigma: f64,
114        bound: f64,
115    ) {
116        module.vec_znx_big_add_dist_f64(
117            basek,
118            res,
119            res_col,
120            k,
121            source,
122            Normal::new(0.0, sigma).unwrap(),
123            bound,
124        );
125    }
126}
127
128unsafe impl VecZnxBigFillDistF64Impl<FFT64> for FFT64 {
129    fn fill_dist_f64_impl<R: VecZnxBigToMut<FFT64>, D: Distribution<f64>>(
130        _module: &Module<FFT64>,
131        basek: usize,
132        res: &mut R,
133        res_col: usize,
134        k: usize,
135        source: &mut Source,
136        dist: D,
137        bound: f64,
138    ) {
139        let mut res: VecZnxBig<&mut [u8], FFT64> = res.to_mut();
140        assert!(
141            (bound.log2().ceil() as i64) < 64,
142            "invalid bound: ceil(log2(bound))={} > 63",
143            (bound.log2().ceil() as i64)
144        );
145
146        let limb: usize = k.div_ceil(basek) - 1;
147        let basek_rem: usize = (limb + 1) * basek - k;
148
149        if basek_rem != 0 {
150            res.at_mut(res_col, limb).iter_mut().for_each(|x| {
151                let mut dist_f64: f64 = dist.sample(source);
152                while dist_f64.abs() > bound {
153                    dist_f64 = dist.sample(source)
154                }
155                *x = (dist_f64.round() as i64) << basek_rem;
156            });
157        } else {
158            res.at_mut(res_col, limb).iter_mut().for_each(|x| {
159                let mut dist_f64: f64 = dist.sample(source);
160                while dist_f64.abs() > bound {
161                    dist_f64 = dist.sample(source)
162                }
163                *x = dist_f64.round() as i64
164            });
165        }
166    }
167}
168
169unsafe impl VecZnxBigFillNormalImpl<FFT64> for FFT64 {
170    fn fill_normal_impl<R: VecZnxBigToMut<FFT64>>(
171        module: &Module<FFT64>,
172        basek: usize,
173        res: &mut R,
174        res_col: usize,
175        k: usize,
176        source: &mut Source,
177        sigma: f64,
178        bound: f64,
179    ) {
180        module.vec_znx_big_fill_dist_f64(
181            basek,
182            res,
183            res_col,
184            k,
185            source,
186            Normal::new(0.0, sigma).unwrap(),
187            bound,
188        );
189    }
190}
191
192unsafe impl VecZnxBigAddImpl<FFT64> for FFT64 {
193    /// Adds `a` to `b` and stores the result on `c`.
194    fn vec_znx_big_add_impl<R, A, B>(
195        module: &Module<FFT64>,
196        res: &mut R,
197        res_col: usize,
198        a: &A,
199        a_col: usize,
200        b: &B,
201        b_col: usize,
202    ) where
203        R: VecZnxBigToMut<FFT64>,
204        A: VecZnxBigToRef<FFT64>,
205        B: VecZnxBigToRef<FFT64>,
206    {
207        let a: VecZnxBig<&[u8], FFT64> = a.to_ref();
208        let b: VecZnxBig<&[u8], FFT64> = b.to_ref();
209        let mut res: VecZnxBig<&mut [u8], FFT64> = res.to_mut();
210
211        #[cfg(debug_assertions)]
212        {
213            assert_eq!(a.n(), res.n());
214            assert_eq!(b.n(), res.n());
215            assert_ne!(a.as_ptr(), b.as_ptr());
216        }
217        unsafe {
218            vec_znx::vec_znx_add(
219                module.ptr(),
220                res.at_mut_ptr(res_col, 0),
221                res.size() as u64,
222                res.sl() as u64,
223                a.at_ptr(a_col, 0),
224                a.size() as u64,
225                a.sl() as u64,
226                b.at_ptr(b_col, 0),
227                b.size() as u64,
228                b.sl() as u64,
229            )
230        }
231    }
232}
233
234unsafe impl VecZnxBigAddInplaceImpl<FFT64> for FFT64 {
235    /// Adds `a` to `b` and stores the result on `b`.
236    fn vec_znx_big_add_inplace_impl<R, A>(module: &Module<FFT64>, res: &mut R, res_col: usize, a: &A, a_col: usize)
237    where
238        R: VecZnxBigToMut<FFT64>,
239        A: VecZnxBigToRef<FFT64>,
240    {
241        let a: VecZnxBig<&[u8], FFT64> = a.to_ref();
242        let mut res: VecZnxBig<&mut [u8], FFT64> = res.to_mut();
243
244        #[cfg(debug_assertions)]
245        {
246            assert_eq!(a.n(), res.n());
247        }
248        unsafe {
249            vec_znx::vec_znx_add(
250                module.ptr(),
251                res.at_mut_ptr(res_col, 0),
252                res.size() as u64,
253                res.sl() as u64,
254                a.at_ptr(a_col, 0),
255                a.size() as u64,
256                a.sl() as u64,
257                res.at_ptr(res_col, 0),
258                res.size() as u64,
259                res.sl() as u64,
260            )
261        }
262    }
263}
264
265unsafe impl VecZnxBigAddSmallImpl<FFT64> for FFT64 {
266    /// Adds `a` to `b` and stores the result on `c`.
267    fn vec_znx_big_add_small_impl<R, A, B>(
268        module: &Module<FFT64>,
269        res: &mut R,
270        res_col: usize,
271        a: &A,
272        a_col: usize,
273        b: &B,
274        b_col: usize,
275    ) where
276        R: VecZnxBigToMut<FFT64>,
277        A: VecZnxBigToRef<FFT64>,
278        B: VecZnxToRef,
279    {
280        let a: VecZnxBig<&[u8], FFT64> = a.to_ref();
281        let b: VecZnx<&[u8]> = b.to_ref();
282        let mut res: VecZnxBig<&mut [u8], FFT64> = res.to_mut();
283
284        #[cfg(debug_assertions)]
285        {
286            assert_eq!(a.n(), res.n());
287            assert_eq!(b.n(), res.n());
288            assert_ne!(a.as_ptr(), b.as_ptr());
289        }
290        unsafe {
291            vec_znx::vec_znx_add(
292                module.ptr(),
293                res.at_mut_ptr(res_col, 0),
294                res.size() as u64,
295                res.sl() as u64,
296                a.at_ptr(a_col, 0),
297                a.size() as u64,
298                a.sl() as u64,
299                b.at_ptr(b_col, 0),
300                b.size() as u64,
301                b.sl() as u64,
302            )
303        }
304    }
305}
306
307unsafe impl VecZnxBigAddSmallInplaceImpl<FFT64> for FFT64 {
308    /// Adds `a` to `b` and stores the result on `b`.
309    fn vec_znx_big_add_small_inplace_impl<R, A>(module: &Module<FFT64>, res: &mut R, res_col: usize, a: &A, a_col: usize)
310    where
311        R: VecZnxBigToMut<FFT64>,
312        A: VecZnxToRef,
313    {
314        let a: VecZnx<&[u8]> = a.to_ref();
315        let mut res: VecZnxBig<&mut [u8], FFT64> = res.to_mut();
316
317        #[cfg(debug_assertions)]
318        {
319            assert_eq!(a.n(), res.n());
320        }
321        unsafe {
322            vec_znx::vec_znx_add(
323                module.ptr(),
324                res.at_mut_ptr(res_col, 0),
325                res.size() as u64,
326                res.sl() as u64,
327                res.at_ptr(res_col, 0),
328                res.size() as u64,
329                res.sl() as u64,
330                a.at_ptr(a_col, 0),
331                a.size() as u64,
332                a.sl() as u64,
333            )
334        }
335    }
336}
337
338unsafe impl VecZnxBigSubImpl<FFT64> for FFT64 {
339    /// Subtracts `a` to `b` and stores the result on `c`.
340    fn vec_znx_big_sub_impl<R, A, B>(
341        module: &Module<FFT64>,
342        res: &mut R,
343        res_col: usize,
344        a: &A,
345        a_col: usize,
346        b: &B,
347        b_col: usize,
348    ) where
349        R: VecZnxBigToMut<FFT64>,
350        A: VecZnxBigToRef<FFT64>,
351        B: VecZnxBigToRef<FFT64>,
352    {
353        let a: VecZnxBig<&[u8], FFT64> = a.to_ref();
354        let b: VecZnxBig<&[u8], FFT64> = b.to_ref();
355        let mut res: VecZnxBig<&mut [u8], FFT64> = res.to_mut();
356
357        #[cfg(debug_assertions)]
358        {
359            assert_eq!(a.n(), res.n());
360            assert_eq!(b.n(), res.n());
361            assert_ne!(a.as_ptr(), b.as_ptr());
362        }
363        unsafe {
364            vec_znx::vec_znx_sub(
365                module.ptr(),
366                res.at_mut_ptr(res_col, 0),
367                res.size() as u64,
368                res.sl() as u64,
369                a.at_ptr(a_col, 0),
370                a.size() as u64,
371                a.sl() as u64,
372                b.at_ptr(b_col, 0),
373                b.size() as u64,
374                b.sl() as u64,
375            )
376        }
377    }
378}
379
380unsafe impl VecZnxBigSubABInplaceImpl<FFT64> for FFT64 {
381    /// Subtracts `a` from `b` and stores the result on `b`.
382    fn vec_znx_big_sub_ab_inplace_impl<R, A>(module: &Module<FFT64>, res: &mut R, res_col: usize, a: &A, a_col: usize)
383    where
384        R: VecZnxBigToMut<FFT64>,
385        A: VecZnxBigToRef<FFT64>,
386    {
387        let a: VecZnxBig<&[u8], FFT64> = a.to_ref();
388        let mut res: VecZnxBig<&mut [u8], FFT64> = res.to_mut();
389
390        #[cfg(debug_assertions)]
391        {
392            assert_eq!(a.n(), res.n());
393        }
394        unsafe {
395            vec_znx::vec_znx_sub(
396                module.ptr(),
397                res.at_mut_ptr(res_col, 0),
398                res.size() as u64,
399                res.sl() as u64,
400                res.at_ptr(res_col, 0),
401                res.size() as u64,
402                res.sl() as u64,
403                a.at_ptr(a_col, 0),
404                a.size() as u64,
405                a.sl() as u64,
406            )
407        }
408    }
409}
410
411unsafe impl VecZnxBigSubBAInplaceImpl<FFT64> for FFT64 {
412    /// Subtracts `b` from `a` and stores the result on `b`.
413    fn vec_znx_big_sub_ba_inplace_impl<R, A>(module: &Module<FFT64>, res: &mut R, res_col: usize, a: &A, a_col: usize)
414    where
415        R: VecZnxBigToMut<FFT64>,
416        A: VecZnxBigToRef<FFT64>,
417    {
418        let a: VecZnxBig<&[u8], FFT64> = a.to_ref();
419        let mut res: VecZnxBig<&mut [u8], FFT64> = res.to_mut();
420
421        #[cfg(debug_assertions)]
422        {
423            assert_eq!(a.n(), res.n());
424        }
425        unsafe {
426            vec_znx::vec_znx_sub(
427                module.ptr(),
428                res.at_mut_ptr(res_col, 0),
429                res.size() as u64,
430                res.sl() as u64,
431                a.at_ptr(a_col, 0),
432                a.size() as u64,
433                a.sl() as u64,
434                res.at_ptr(res_col, 0),
435                res.size() as u64,
436                res.sl() as u64,
437            )
438        }
439    }
440}
441
442unsafe impl VecZnxBigSubSmallAImpl<FFT64> for FFT64 {
443    /// Subtracts `b` from `a` and stores the result on `c`.
444    fn vec_znx_big_sub_small_a_impl<R, A, B>(
445        module: &Module<FFT64>,
446        res: &mut R,
447        res_col: usize,
448        a: &A,
449        a_col: usize,
450        b: &B,
451        b_col: usize,
452    ) where
453        R: VecZnxBigToMut<FFT64>,
454        A: VecZnxToRef,
455        B: VecZnxBigToRef<FFT64>,
456    {
457        let a: VecZnx<&[u8]> = a.to_ref();
458        let b: VecZnxBig<&[u8], FFT64> = b.to_ref();
459        let mut res: VecZnxBig<&mut [u8], FFT64> = res.to_mut();
460
461        #[cfg(debug_assertions)]
462        {
463            assert_eq!(a.n(), res.n());
464            assert_eq!(b.n(), res.n());
465            assert_ne!(a.as_ptr(), b.as_ptr());
466        }
467        unsafe {
468            vec_znx::vec_znx_sub(
469                module.ptr(),
470                res.at_mut_ptr(res_col, 0),
471                res.size() as u64,
472                res.sl() as u64,
473                a.at_ptr(a_col, 0),
474                a.size() as u64,
475                a.sl() as u64,
476                b.at_ptr(b_col, 0),
477                b.size() as u64,
478                b.sl() as u64,
479            )
480        }
481    }
482}
483
484unsafe impl VecZnxBigSubSmallAInplaceImpl<FFT64> for FFT64 {
485    /// Subtracts `a` from `res` and stores the result on `res`.
486    fn vec_znx_big_sub_small_a_inplace_impl<R, A>(module: &Module<FFT64>, res: &mut R, res_col: usize, a: &A, a_col: usize)
487    where
488        R: VecZnxBigToMut<FFT64>,
489        A: VecZnxToRef,
490    {
491        let a: VecZnx<&[u8]> = a.to_ref();
492        let mut res: VecZnxBig<&mut [u8], FFT64> = res.to_mut();
493
494        #[cfg(debug_assertions)]
495        {
496            assert_eq!(a.n(), res.n());
497        }
498        unsafe {
499            vec_znx::vec_znx_sub(
500                module.ptr(),
501                res.at_mut_ptr(res_col, 0),
502                res.size() as u64,
503                res.sl() as u64,
504                res.at_ptr(res_col, 0),
505                res.size() as u64,
506                res.sl() as u64,
507                a.at_ptr(a_col, 0),
508                a.size() as u64,
509                a.sl() as u64,
510            )
511        }
512    }
513}
514
515unsafe impl VecZnxBigSubSmallBImpl<FFT64> for FFT64 {
516    /// Subtracts `b` from `a` and stores the result on `c`.
517    fn vec_znx_big_sub_small_b_impl<R, A, B>(
518        module: &Module<FFT64>,
519        res: &mut R,
520        res_col: usize,
521        a: &A,
522        a_col: usize,
523        b: &B,
524        b_col: usize,
525    ) where
526        R: VecZnxBigToMut<FFT64>,
527        A: VecZnxBigToRef<FFT64>,
528        B: VecZnxToRef,
529    {
530        let a: VecZnxBig<&[u8], FFT64> = a.to_ref();
531        let b: VecZnx<&[u8]> = b.to_ref();
532        let mut res: VecZnxBig<&mut [u8], FFT64> = res.to_mut();
533
534        #[cfg(debug_assertions)]
535        {
536            assert_eq!(a.n(), res.n());
537            assert_eq!(b.n(), res.n());
538            assert_ne!(a.as_ptr(), b.as_ptr());
539        }
540        unsafe {
541            vec_znx::vec_znx_sub(
542                module.ptr(),
543                res.at_mut_ptr(res_col, 0),
544                res.size() as u64,
545                res.sl() as u64,
546                a.at_ptr(a_col, 0),
547                a.size() as u64,
548                a.sl() as u64,
549                b.at_ptr(b_col, 0),
550                b.size() as u64,
551                b.sl() as u64,
552            )
553        }
554    }
555}
556
557unsafe impl VecZnxBigSubSmallBInplaceImpl<FFT64> for FFT64 {
558    /// Subtracts `res` from `a` and stores the result on `res`.
559    fn vec_znx_big_sub_small_b_inplace_impl<R, A>(module: &Module<FFT64>, res: &mut R, res_col: usize, a: &A, a_col: usize)
560    where
561        R: VecZnxBigToMut<FFT64>,
562        A: VecZnxToRef,
563    {
564        let a: VecZnx<&[u8]> = a.to_ref();
565        let mut res: VecZnxBig<&mut [u8], FFT64> = res.to_mut();
566
567        #[cfg(debug_assertions)]
568        {
569            assert_eq!(a.n(), res.n());
570        }
571        unsafe {
572            vec_znx::vec_znx_sub(
573                module.ptr(),
574                res.at_mut_ptr(res_col, 0),
575                res.size() as u64,
576                res.sl() as u64,
577                a.at_ptr(a_col, 0),
578                a.size() as u64,
579                a.sl() as u64,
580                res.at_ptr(res_col, 0),
581                res.size() as u64,
582                res.sl() as u64,
583            )
584        }
585    }
586}
587
588unsafe impl VecZnxBigNegateInplaceImpl<FFT64> for FFT64 {
589    fn vec_znx_big_negate_inplace_impl<A>(module: &Module<FFT64>, a: &mut A, a_col: usize)
590    where
591        A: VecZnxBigToMut<FFT64>,
592    {
593        let mut a: VecZnxBig<&mut [u8], FFT64> = a.to_mut();
594        unsafe {
595            vec_znx::vec_znx_negate(
596                module.ptr(),
597                a.at_mut_ptr(a_col, 0),
598                a.size() as u64,
599                a.sl() as u64,
600                a.at_ptr(a_col, 0),
601                a.size() as u64,
602                a.sl() as u64,
603            )
604        }
605    }
606}
607
608unsafe impl VecZnxBigNormalizeTmpBytesImpl<FFT64> for FFT64 {
609    fn vec_znx_big_normalize_tmp_bytes_impl(module: &Module<FFT64>, n: usize) -> usize {
610        unsafe { vec_znx::vec_znx_normalize_base2k_tmp_bytes(module.ptr(), n as u64) as usize }
611    }
612}
613
614unsafe impl VecZnxBigNormalizeImpl<FFT64> for FFT64 {
615    fn vec_znx_big_normalize_impl<R, A>(
616        module: &Module<FFT64>,
617        basek: usize,
618        res: &mut R,
619        res_col: usize,
620        a: &A,
621        a_col: usize,
622        scratch: &mut Scratch<FFT64>,
623    ) where
624        R: VecZnxToMut,
625        A: VecZnxBigToRef<FFT64>,
626    {
627        let a: VecZnxBig<&[u8], FFT64> = a.to_ref();
628        let mut res: VecZnx<&mut [u8]> = res.to_mut();
629
630        #[cfg(debug_assertions)]
631        {
632            assert_eq!(res.n(), a.n());
633        }
634
635        let (tmp_bytes, _) = scratch.take_slice(module.vec_znx_big_normalize_tmp_bytes(a.n()));
636        unsafe {
637            vec_znx::vec_znx_normalize_base2k(
638                module.ptr(),
639                a.n() as u64,
640                basek as u64,
641                res.at_mut_ptr(res_col, 0),
642                res.size() as u64,
643                res.sl() as u64,
644                a.at_ptr(a_col, 0),
645                a.size() as u64,
646                a.sl() as u64,
647                tmp_bytes.as_mut_ptr(),
648            );
649        }
650    }
651}
652
653unsafe impl VecZnxBigAutomorphismImpl<FFT64> for FFT64 {
654    /// Applies the automorphism X^i -> X^ik on `a` and stores the result on `b`.
655    fn vec_znx_big_automorphism_impl<R, A>(module: &Module<FFT64>, k: i64, res: &mut R, res_col: usize, a: &A, a_col: usize)
656    where
657        R: VecZnxBigToMut<FFT64>,
658        A: VecZnxBigToRef<FFT64>,
659    {
660        let a: VecZnxBig<&[u8], FFT64> = a.to_ref();
661        let mut res: VecZnxBig<&mut [u8], FFT64> = res.to_mut();
662
663        #[cfg(debug_assertions)]
664        {
665            assert_eq!(a.n(), res.n());
666        }
667        unsafe {
668            vec_znx::vec_znx_automorphism(
669                module.ptr(),
670                k,
671                res.at_mut_ptr(res_col, 0),
672                res.size() as u64,
673                res.sl() as u64,
674                a.at_ptr(a_col, 0),
675                a.size() as u64,
676                a.sl() as u64,
677            )
678        }
679    }
680}
681
682unsafe impl VecZnxBigAutomorphismInplaceImpl<FFT64> for FFT64 {
683    /// Applies the automorphism X^i -> X^ik on `a` and stores the result on `a`.
684    fn vec_znx_big_automorphism_inplace_impl<A>(module: &Module<FFT64>, k: i64, a: &mut A, a_col: usize)
685    where
686        A: VecZnxBigToMut<FFT64>,
687    {
688        let mut a: VecZnxBig<&mut [u8], FFT64> = a.to_mut();
689        unsafe {
690            vec_znx::vec_znx_automorphism(
691                module.ptr(),
692                k,
693                a.at_mut_ptr(a_col, 0),
694                a.size() as u64,
695                a.sl() as u64,
696                a.at_ptr(a_col, 0),
697                a.size() as u64,
698                a.sl() as u64,
699            )
700        }
701    }
702}
703
704impl<D: DataRef> fmt::Display for VecZnxBig<D, FFT64> {
705    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
706        writeln!(
707            f,
708            "VecZnxBig(n={}, cols={}, size={})",
709            self.n, self.cols, self.size
710        )?;
711
712        for col in 0..self.cols {
713            writeln!(f, "Column {}:", col)?;
714            for size in 0..self.size {
715                let coeffs = self.at(col, size);
716                write!(f, "  Size {}: [", size)?;
717
718                let max_show = 100;
719                let show_count = coeffs.len().min(max_show);
720
721                for (i, &coeff) in coeffs.iter().take(show_count).enumerate() {
722                    if i > 0 {
723                        write!(f, ", ")?;
724                    }
725                    write!(f, "{}", coeff)?;
726                }
727
728                if coeffs.len() > max_show {
729                    write!(f, ", ... ({} more)", coeffs.len() - max_show)?;
730                }
731
732                writeln!(f, "]")?;
733            }
734        }
735        Ok(())
736    }
737}