poulpy/base2k/src/vmp.rs
base2k/src/vmp.rsRaw
1use crate::ffi::vmp;
2use crate::{assert_alignement, Infos, Module, VecZnxApi, VecZnxDft};
3
4/// Vector Matrix Product Prepared Matrix: a vector of [VecZnx],
5/// stored as a 3D matrix in the DFT domain in a single contiguous array.
6/// Each row of the [VmpPMat] can be seen as a [VecZnxDft].
7///
8/// The backend array of [VmpPMat] is allocate in C,
9/// and thus must be manually freed.
10///
11/// [VmpPMat] is used to permform a vector matrix product between a [VecZnx] and a [VmpPMat].
12/// See the trait [VmpPMatOps] for additional information.
13pub struct VmpPMat {
14 /// The pointer to the C memory.
15 pub data: *mut vmp::vmp_pmat_t,
16 /// The number of [VecZnxDft].
17 pub rows: usize,
18 /// The number of cols in each [VecZnxDft].
19 pub cols: usize,
20 /// The ring degree of each [VecZnxDft].
21 pub n: usize,
22}
23
24impl VmpPMat {
25 /// Returns the pointer to the [vmp_pmat_t].
26 pub fn data(&self) -> *mut vmp::vmp_pmat_t {
27 self.data
28 }
29
30 /// Returns a copy of the backend array at index (i, j) of the [VmpPMat].
31 /// When using [`crate::FFT64`] as backend, `T` should be [f64].
32 /// When using [`crate::NTT120`] as backend, `T` should be [i64].
33 ///
34 /// # Arguments
35 ///
36 /// * `row`: row index (i).
37 /// * `col`: col index (j).
38 pub fn at<T: Default + Copy>(&self, row: usize, col: usize) -> Vec<T> {
39 let mut res: Vec<T> = vec![T::default(); self.n];
40
41 if self.n < 8 {
42 res.copy_from_slice(
43 &self.get_backend_array::<T>()[(row + col * self.rows()) * self.n()
44 ..(row + col * self.rows()) * (self.n() + 1)],
45 );
46 } else {
47 (0..self.n >> 3).for_each(|blk| {
48 res[blk * 8..(blk + 1) * 8].copy_from_slice(&self.get_array(row, col, blk)[..8]);
49 });
50 }
51
52 res
53 }
54
55 /// When using [`crate::FFT64`] as backend, `T` should be [f64].
56 /// When using [`crate::NTT120`] as backend, `T` should be [i64].
57 fn get_array<T>(&self, row: usize, col: usize, blk: usize) -> &[T] {
58 let nrows: usize = self.rows();
59 let ncols: usize = self.cols();
60 if col == (ncols - 1) && (ncols & 1 == 1) {
61 &self.get_backend_array::<T>()[blk * nrows * ncols * 8 + col * nrows * 8 + row * 8..]
62 } else {
63 &self.get_backend_array::<T>()[blk * nrows * ncols * 8
64 + (col / 2) * (2 * nrows) * 8
65 + row * 2 * 8
66 + (col % 2) * 8..]
67 }
68 }
69
70 /// Returns a non-mutable reference of `T` of the entire contiguous array of the [VmpPMat].
71 /// When using [`crate::FFT64`] as backend, `T` should be [f64].
72 /// When using [`crate::NTT120`] as backend, `T` should be [i64].
73 /// The length of the returned array is rows * cols * n.
74 pub fn get_backend_array<T>(&self) -> &[T] {
75 let ptr: *const T = self.data as *const T;
76 let len: usize = (self.rows() * self.cols() * self.n() * 8) / std::mem::size_of::<T>();
77 unsafe { &std::slice::from_raw_parts(ptr, len) }
78 }
79}
80
81/// This trait implements methods for vector matrix product,
82/// that is, multiplying a [VecZnx] with a [VmpPMat].
83pub trait VmpPMatOps {
84 /// Allocates a new [VmpPMat] with the given number of rows and columns.
85 ///
86 /// # Arguments
87 ///
88 /// * `rows`: number of rows (number of [VecZnxDft]).
89 /// * `cols`: number of cols (number of cols of each [VecZnxDft]).
90 fn new_vmp_pmat(&self, rows: usize, cols: usize) -> VmpPMat;
91
92 /// Returns the number of bytes needed as scratch space for [VmpPMatOps::vmp_prepare_contiguous].
93 ///
94 /// # Arguments
95 ///
96 /// * `rows`: number of rows of the [VmpPMat] used in [VmpPMatOps::vmp_prepare_contiguous].
97 /// * `cols`: number of cols of the [VmpPMat] used in [VmpPMatOps::vmp_prepare_contiguous].
98 fn vmp_prepare_tmp_bytes(&self, rows: usize, cols: usize) -> usize;
99
100 /// Prepares a [VmpPMat] from a contiguous array of [i64].
101 /// The helper struct [Matrix3D] can be used to contruct and populate
102 /// the appropriate contiguous array.
103 ///
104 /// # Arguments
105 ///
106 /// * `b`: [VmpPMat] on which the values are encoded.
107 /// * `a`: the contiguous array of [i64] of the 3D matrix to encode on the [VmpPMat].
108 /// * `buf`: scratch space, the size of buf can be obtained with [VmpPMatOps::vmp_prepare_tmp_bytes].
109 ///
110 /// # Example
111 /// ```
112 /// use base2k::{Module, VmpPMat, VmpPMatOps, FFT64, Free, alloc_aligned};
113 /// use std::cmp::min;
114 ///
115 /// let n: usize = 1024;
116 /// let module = Module::new::<FFT64>(n);
117 /// let rows = 5;
118 /// let cols = 6;
119 ///
120 /// let mut b_mat: Vec<i64> = vec![0i64;n * cols * rows];
121 ///
122 /// let mut buf: Vec<u8> = alloc_aligned(module.vmp_prepare_tmp_bytes(rows, cols));
123 ///
124 /// let mut vmp_pmat: VmpPMat = module.new_vmp_pmat(rows, cols);
125 /// module.vmp_prepare_contiguous(&mut vmp_pmat, &b_mat, &mut buf);
126 ///
127 /// vmp_pmat.free() // don't forget to free the memory once vmp_pmat is not needed anymore.
128 /// ```
129 fn vmp_prepare_contiguous(&self, b: &mut VmpPMat, a: &[i64], buf: &mut [u8]);
130
131 /// Prepares a [VmpPMat] from a vector of [VecZnx].
132 ///
133 /// # Arguments
134 ///
135 /// * `b`: [VmpPMat] on which the values are encoded.
136 /// * `a`: the vector of [VecZnx] to encode on the [VmpPMat].
137 /// * `buf`: scratch space, the size of buf can be obtained with [VmpPMatOps::vmp_prepare_tmp_bytes].
138 ///
139 /// The size of buf can be obtained with [VmpPMatOps::vmp_prepare_tmp_bytes].
140 ///
141 /// # Example
142 /// ```
143 /// use base2k::{Module, FFT64, VmpPMat, VmpPMatOps, VecZnx, VecZnxApi, VecZnxOps, Free, alloc_aligned};
144 /// use std::cmp::min;
145 ///
146 /// let n: usize = 1024;
147 /// let module: Module = Module::new::<FFT64>(n);
148 /// let rows: usize = 5;
149 /// let cols: usize = 6;
150 ///
151 /// let mut vecznx: Vec<VecZnx>= Vec::new();
152 /// (0..rows).for_each(|_|{
153 /// vecznx.push(module.new_vec_znx(cols));
154 /// });
155 ///
156 /// let slices: Vec<&[i64]> = vecznx.iter().map(|v| v.data.as_slice()).collect();
157 ///
158 /// let mut buf: Vec<u8> = alloc_aligned(module.vmp_prepare_tmp_bytes(rows, cols));
159 ///
160 /// let mut vmp_pmat: VmpPMat = module.new_vmp_pmat(rows, cols);
161 /// module.vmp_prepare_dblptr(&mut vmp_pmat, &slices, &mut buf);
162 ///
163 /// vmp_pmat.free();
164 /// module.free();
165 /// ```
166 fn vmp_prepare_dblptr(&self, b: &mut VmpPMat, a: &[&[i64]], buf: &mut [u8]);
167
168 /// Prepares the ith-row of [VmpPMat] from a vector of [VecZnx].
169 ///
170 /// # Arguments
171 ///
172 /// * `b`: [VmpPMat] on which the values are encoded.
173 /// * `a`: the vector of [VecZnx] to encode on the [VmpPMat].
174 /// * `row_i`: the index of the row to prepare.
175 /// * `buf`: scratch space, the size of buf can be obtained with [VmpPMatOps::vmp_prepare_tmp_bytes].
176 ///
177 /// The size of buf can be obtained with [VmpPMatOps::vmp_prepare_tmp_bytes].
178 /// /// # Example
179 /// ```
180 /// use base2k::{Module, FFT64, VmpPMat, VmpPMatOps, VecZnx, VecZnxApi, VecZnxOps, Free, alloc_aligned};
181 /// use std::cmp::min;
182 ///
183 /// let n: usize = 1024;
184 /// let module: Module = Module::new::<FFT64>(n);
185 /// let rows: usize = 5;
186 /// let cols: usize = 6;
187 ///
188 /// let vecznx = module.new_vec_znx(cols);
189 ///
190 /// let mut buf: Vec<u8> = alloc_aligned(module.vmp_prepare_tmp_bytes(rows, cols));
191 ///
192 /// let mut vmp_pmat: VmpPMat = module.new_vmp_pmat(rows, cols);
193 /// module.vmp_prepare_row(&mut vmp_pmat, vecznx.raw(), 0, &mut buf);
194 ///
195 /// vmp_pmat.free();
196 /// module.free();
197 /// ```
198 fn vmp_prepare_row(&self, b: &mut VmpPMat, a: &[i64], row_i: usize, tmp_bytes: &mut [u8]);
199
200 /// Returns the size of the stratch space necessary for [VmpPMatOps::vmp_apply_dft].
201 ///
202 /// # Arguments
203 ///
204 /// * `c_cols`: number of cols of the output [VecZnxDft].
205 /// * `a_cols`: number of cols of the input [VecZnx].
206 /// * `rows`: number of rows of the input [VmpPMat].
207 /// * `cols`: number of cols of the input [VmpPMat].
208 fn vmp_apply_dft_tmp_bytes(
209 &self,
210 c_cols: usize,
211 a_cols: usize,
212 rows: usize,
213 cols: usize,
214 ) -> usize;
215
216 /// Applies the vector matrix product [VecZnxDft] x [VmpPMat].
217 ///
218 /// A vector matrix product is equivalent to a sum of [crate::SvpPPolOps::svp_apply_dft]
219 /// where each [crate::Scalar] is a limb of the input [VecZnxDft] (equivalent to an [crate::SvpPPol])
220 /// and each vector a [VecZnxDft] (row) of the [VmpPMat].
221 ///
222 /// As such, given an input [VecZnx] of `i` cols and a [VmpPMat] of `i` rows and
223 /// `j` cols, the output is a [VecZnx] of `j` cols.
224 ///
225 /// If there is a mismatch between the dimensions the largest valid ones are used.
226 ///
227 /// ```text
228 /// |a b c d| x |e f g| = (a * |e f g| + b * |h i j| + c * |k l m|) = |n o p|
229 /// |h i j|
230 /// |k l m|
231 /// ```
232 /// where each element is a [VecZnxDft].
233 ///
234 /// # Arguments
235 ///
236 /// * `c`: the output of the vector matrix product, as a [VecZnxDft].
237 /// * `a`: the left operand [VecZnx] of the vector matrix product.
238 /// * `b`: the right operand [VmpPMat] of the vector matrix product.
239 /// * `buf`: scratch space, the size can be obtained with [VmpPMatOps::vmp_apply_dft_tmp_bytes].
240 ///
241 /// # Example
242 /// ```
243 /// use base2k::{Module, VecZnx, VecZnxOps, VecZnxDft, VecZnxDftOps, VmpPMat, VmpPMatOps, FFT64, Free, VecZnxApi, alloc_aligned};
244 ///
245 /// let n = 1024;
246 ///
247 /// let module: Module = Module::new::<FFT64>(n);
248 /// let cols: usize = 5;
249 ///
250 /// let rows: usize = cols;
251 /// let cols: usize = cols + 1;
252 /// let c_cols: usize = cols;
253 /// let a_cols: usize = cols;
254 /// let mut buf: Vec<u8> = alloc_aligned(module.vmp_apply_dft_tmp_bytes(c_cols, a_cols, rows, cols));
255 /// let mut vmp_pmat: VmpPMat = module.new_vmp_pmat(rows, cols);
256 ///
257 /// let a: VecZnx = module.new_vec_znx(cols);
258 /// let mut c_dft: VecZnxDft = module.new_vec_znx_dft(cols);
259 /// module.vmp_apply_dft(&mut c_dft, &a, &vmp_pmat, &mut buf);
260 ///
261 /// c_dft.free();
262 /// vmp_pmat.free();
263 /// module.free();
264 /// ```
265 fn vmp_apply_dft<T: VecZnxApi + Infos>(
266 &self,
267 c: &mut VecZnxDft,
268 a: &T,
269 b: &VmpPMat,
270 buf: &mut [u8],
271 );
272
273 /// Returns the size of the stratch space necessary for [VmpPMatOps::vmp_apply_dft_to_dft].
274 ///
275 /// # Arguments
276 ///
277 /// * `c_cols`: number of cols of the output [VecZnxDft].
278 /// * `a_cols`: number of cols of the input [VecZnxDft].
279 /// * `rows`: number of rows of the input [VmpPMat].
280 /// * `cols`: number of cols of the input [VmpPMat].
281 fn vmp_apply_dft_to_dft_tmp_bytes(
282 &self,
283 c_cols: usize,
284 a_cols: usize,
285 rows: usize,
286 cols: usize,
287 ) -> usize;
288
289 /// Applies the vector matrix product [VecZnxDft] x [VmpPMat].
290 /// The size of `buf` is given by [VmpPMatOps::vmp_apply_dft_to_dft_tmp_bytes].
291 ///
292 /// A vector matrix product is equivalent to a sum of [crate::SvpPPolOps::svp_apply_dft]
293 /// where each [crate::Scalar] is a limb of the input [VecZnxDft] (equivalent to an [crate::SvpPPol])
294 /// and each vector a [VecZnxDft] (row) of the [VmpPMat].
295 ///
296 /// As such, given an input [VecZnx] of `i` cols and a [VmpPMat] of `i` rows and
297 /// `j` cols, the output is a [VecZnx] of `j` cols.
298 ///
299 /// If there is a mismatch between the dimensions the largest valid ones are used.
300 ///
301 /// ```text
302 /// |a b c d| x |e f g| = (a * |e f g| + b * |h i j| + c * |k l m|) = |n o p|
303 /// |h i j|
304 /// |k l m|
305 /// ```
306 /// where each element is a [VecZnxDft].
307 ///
308 /// # Arguments
309 ///
310 /// * `c`: the output of the vector matrix product, as a [VecZnxDft].
311 /// * `a`: the left operand [VecZnxDft] of the vector matrix product.
312 /// * `b`: the right operand [VmpPMat] of the vector matrix product.
313 /// * `buf`: scratch space, the size can be obtained with [VmpPMatOps::vmp_apply_dft_to_dft_tmp_bytes].
314 ///
315 /// # Example
316 /// ```
317 /// use base2k::{Module, VecZnx, VecZnxDft, VecZnxDftOps, VmpPMat, VmpPMatOps, FFT64, Free, alloc_aligned};
318 ///
319 /// let n = 1024;
320 ///
321 /// let module: Module = Module::new::<FFT64>(n);
322 /// let cols: usize = 5;
323 ///
324 /// let rows: usize = cols;
325 /// let cols: usize = cols + 1;
326 /// let c_cols: usize = cols;
327 /// let a_cols: usize = cols;
328 /// let mut tmp_bytes: Vec<u8> = alloc_aligned(module.vmp_apply_dft_to_dft_tmp_bytes(c_cols, a_cols, rows, cols));
329 /// let mut vmp_pmat: VmpPMat = module.new_vmp_pmat(rows, cols);
330 ///
331 /// let a_dft: VecZnxDft = module.new_vec_znx_dft(cols);
332 /// let mut c_dft: VecZnxDft = module.new_vec_znx_dft(cols);
333 /// module.vmp_apply_dft_to_dft(&mut c_dft, &a_dft, &vmp_pmat, &mut tmp_bytes);
334 ///
335 /// a_dft.free();
336 /// c_dft.free();
337 /// vmp_pmat.free();
338 /// module.free();
339 /// ```
340 fn vmp_apply_dft_to_dft(&self, c: &mut VecZnxDft, a: &VecZnxDft, b: &VmpPMat, buf: &mut [u8]);
341
342 /// Applies the vector matrix product [VecZnxDft] x [VmpPMat] in place.
343 /// The size of `buf` is given by [VmpPMatOps::vmp_apply_dft_to_dft_tmp_bytes].
344 ///
345 /// A vector matrix product is equivalent to a sum of [crate::SvpPPolOps::svp_apply_dft]
346 /// where each [crate::Scalar] is a limb of the input [VecZnxDft] (equivalent to an [crate::SvpPPol])
347 /// and each vector a [VecZnxDft] (row) of the [VmpPMat].
348 ///
349 /// As such, given an input [VecZnx] of `i` cols and a [VmpPMat] of `i` rows and
350 /// `j` cols, the output is a [VecZnx] of `j` cols.
351 ///
352 /// If there is a mismatch between the dimensions the largest valid ones are used.
353 ///
354 /// ```text
355 /// |a b c d| x |e f g| = (a * |e f g| + b * |h i j| + c * |k l m|) = |n o p|
356 /// |h i j|
357 /// |k l m|
358 /// ```
359 /// where each element is a [VecZnxDft].
360 ///
361 /// # Arguments
362 ///
363 /// * `b`: the input and output of the vector matrix product, as a [VecZnxDft].
364 /// * `a`: the right operand [VmpPMat] of the vector matrix product.
365 /// * `buf`: scratch space, the size can be obtained with [VmpPMatOps::vmp_apply_dft_to_dft_tmp_bytes].
366 ///
367 /// # Example
368 /// ```rust
369 /// use base2k::{Module, VecZnx, VecZnxOps, VecZnxDft, VmpPMat, VmpPMatOps, FFT64, Free, VecZnxApi, VecZnxDftOps,alloc_aligned};
370 ///
371 /// let n = 1024;
372 ///
373 /// let module: Module = Module::new::<FFT64>(n);
374 /// let cols: usize = 5;
375 ///
376 /// let rows: usize = cols;
377 /// let cols: usize = cols + 1;
378 /// let mut tmp_bytes: Vec<u8> = alloc_aligned(module.vmp_apply_dft_to_dft_tmp_bytes(cols, cols, rows, cols));
379 /// let a: VecZnx = module.new_vec_znx(cols);
380 /// let mut vmp_pmat: VmpPMat = module.new_vmp_pmat(rows, cols);
381 ///
382 /// let mut c_dft: VecZnxDft = module.new_vec_znx_dft(cols);
383 /// module.vmp_apply_dft_to_dft_inplace(&mut c_dft, &vmp_pmat, &mut tmp_bytes);
384 ///
385 /// c_dft.free();
386 /// vmp_pmat.free();
387 /// module.free();
388 /// ```
389 fn vmp_apply_dft_to_dft_inplace(&self, b: &mut VecZnxDft, a: &VmpPMat, buf: &mut [u8]);
390}
391
392impl VmpPMatOps for Module {
393 fn new_vmp_pmat(&self, rows: usize, cols: usize) -> VmpPMat {
394 unsafe {
395 VmpPMat {
396 data: vmp::new_vmp_pmat(self.0, rows as u64, cols as u64),
397 rows,
398 cols,
399 n: self.n(),
400 }
401 }
402 }
403
404 fn vmp_prepare_tmp_bytes(&self, rows: usize, cols: usize) -> usize {
405 unsafe { vmp::vmp_prepare_tmp_bytes(self.0, rows as u64, cols as u64) as usize }
406 }
407
408 fn vmp_prepare_contiguous(&self, b: &mut VmpPMat, a: &[i64], tmp_bytes: &mut [u8]) {
409 debug_assert_eq!(a.len(), b.n * b.rows * b.cols);
410 debug_assert!(tmp_bytes.len() >= self.vmp_prepare_tmp_bytes(b.rows(), b.cols()));
411 #[cfg(debug_assertions)]
412 {
413 assert_alignement(tmp_bytes.as_ptr());
414 }
415 unsafe {
416 vmp::vmp_prepare_contiguous(
417 self.0,
418 b.data(),
419 a.as_ptr(),
420 b.rows() as u64,
421 b.cols() as u64,
422 tmp_bytes.as_mut_ptr(),
423 );
424 }
425 }
426
427 fn vmp_prepare_dblptr(&self, b: &mut VmpPMat, a: &[&[i64]], tmp_bytes: &mut [u8]) {
428 let ptrs: Vec<*const i64> = a.iter().map(|v| v.as_ptr()).collect();
429 #[cfg(debug_assertions)]
430 {
431 debug_assert_eq!(a.len(), b.rows);
432 a.iter().for_each(|ai| {
433 debug_assert_eq!(ai.len(), b.n * b.cols);
434 });
435 debug_assert!(tmp_bytes.len() >= self.vmp_prepare_tmp_bytes(b.rows(), b.cols()));
436 assert_alignement(tmp_bytes.as_ptr());
437 }
438 unsafe {
439 vmp::vmp_prepare_dblptr(
440 self.0,
441 b.data(),
442 ptrs.as_ptr(),
443 b.rows() as u64,
444 b.cols() as u64,
445 tmp_bytes.as_mut_ptr(),
446 );
447 }
448 }
449
450 fn vmp_prepare_row(&self, b: &mut VmpPMat, a: &[i64], row_i: usize, tmp_bytes: &mut [u8]) {
451 debug_assert_eq!(a.len(), b.cols() * self.n());
452 debug_assert!(tmp_bytes.len() >= self.vmp_prepare_tmp_bytes(b.rows(), b.cols()));
453 #[cfg(debug_assertions)]
454 {
455 assert_alignement(tmp_bytes.as_ptr());
456 }
457 unsafe {
458 vmp::vmp_prepare_row(
459 self.0,
460 b.data(),
461 a.as_ptr(),
462 row_i as u64,
463 b.rows() as u64,
464 b.cols() as u64,
465 tmp_bytes.as_mut_ptr(),
466 );
467 }
468 }
469
470 fn vmp_apply_dft_tmp_bytes(
471 &self,
472 res_cols: usize,
473 a_cols: usize,
474 gct_rows: usize,
475 gct_cols: usize,
476 ) -> usize {
477 unsafe {
478 vmp::vmp_apply_dft_tmp_bytes(
479 self.0,
480 res_cols as u64,
481 a_cols as u64,
482 gct_rows as u64,
483 gct_cols as u64,
484 ) as usize
485 }
486 }
487
488 fn vmp_apply_dft<T: VecZnxApi + Infos>(
489 &self,
490 c: &mut VecZnxDft,
491 a: &T,
492 b: &VmpPMat,
493 tmp_bytes: &mut [u8],
494 ) {
495 debug_assert!(
496 tmp_bytes.len() >= self.vmp_apply_dft_tmp_bytes(c.cols(), a.cols(), b.rows(), b.cols())
497 );
498 #[cfg(debug_assertions)]
499 {
500 assert_alignement(tmp_bytes.as_ptr());
501 }
502 unsafe {
503 vmp::vmp_apply_dft(
504 self.0,
505 c.0,
506 c.cols() as u64,
507 a.as_ptr(),
508 a.cols() as u64,
509 a.n() as u64,
510 b.data(),
511 b.rows() as u64,
512 b.cols() as u64,
513 tmp_bytes.as_mut_ptr(),
514 )
515 }
516 }
517
518 fn vmp_apply_dft_to_dft_tmp_bytes(
519 &self,
520 res_cols: usize,
521 a_cols: usize,
522 gct_rows: usize,
523 gct_cols: usize,
524 ) -> usize {
525 unsafe {
526 vmp::vmp_apply_dft_to_dft_tmp_bytes(
527 self.0,
528 res_cols as u64,
529 a_cols as u64,
530 gct_rows as u64,
531 gct_cols as u64,
532 ) as usize
533 }
534 }
535
536 fn vmp_apply_dft_to_dft(
537 &self,
538 c: &mut VecZnxDft,
539 a: &VecZnxDft,
540 b: &VmpPMat,
541 tmp_bytes: &mut [u8],
542 ) {
543 debug_assert!(
544 tmp_bytes.len()
545 >= self.vmp_apply_dft_to_dft_tmp_bytes(c.cols(), a.cols(), b.rows(), b.cols())
546 );
547 #[cfg(debug_assertions)]
548 {
549 assert_alignement(tmp_bytes.as_ptr());
550 }
551 unsafe {
552 vmp::vmp_apply_dft_to_dft(
553 self.0,
554 c.0,
555 c.cols() as u64,
556 a.0,
557 a.cols() as u64,
558 b.data(),
559 b.rows() as u64,
560 b.cols() as u64,
561 tmp_bytes.as_mut_ptr(),
562 )
563 }
564 }
565
566 fn vmp_apply_dft_to_dft_inplace(&self, b: &mut VecZnxDft, a: &VmpPMat, tmp_bytes: &mut [u8]) {
567 debug_assert!(
568 tmp_bytes.len()
569 >= self.vmp_apply_dft_to_dft_tmp_bytes(b.cols(), b.cols(), a.rows(), a.cols())
570 );
571 #[cfg(debug_assertions)]
572 {
573 assert_alignement(tmp_bytes.as_ptr());
574 }
575 unsafe {
576 vmp::vmp_apply_dft_to_dft(
577 self.0,
578 b.0,
579 b.cols() as u64,
580 b.0,
581 b.cols() as u64,
582 a.data(),
583 a.rows() as u64,
584 a.cols() as u64,
585 tmp_bytes.as_mut_ptr(),
586 )
587 }
588 }
589}