1use crate::common::RadixFactor;
2use crate::Complex;
3use crate::FftNum;
4use std::ops::{Deref, DerefMut};
5
6pub unsafe fn transpose_small<T: Copy>(width: usize, height: usize, input: &[T], output: &mut [T]) {
10 for x in 0..width {
11 for y in 0..height {
12 let input_index = x + y * width;
13 let output_index = y + x * height;
14
15 *output.get_unchecked_mut(output_index) = *input.get_unchecked(input_index);
16 }
17 }
18}
19
20#[allow(unused)]
21pub unsafe fn workaround_transmute<T, U>(slice: &[T]) -> &[U] {
22 let ptr = slice.as_ptr() as *const U;
23 let len = slice.len();
24 std::slice::from_raw_parts(ptr, len)
25}
26#[allow(unused)]
27pub unsafe fn workaround_transmute_mut<T, U>(slice: &mut [T]) -> &mut [U] {
28 let ptr = slice.as_mut_ptr() as *mut U;
29 let len = slice.len();
30 std::slice::from_raw_parts_mut(ptr, len)
31}
32
33pub(crate) trait LoadStore<T: FftNum>: DerefMut {
34 unsafe fn load(&self, idx: usize) -> Complex<T>;
35 unsafe fn store(&mut self, val: Complex<T>, idx: usize);
36}
37
38impl<T: FftNum> LoadStore<T> for &mut [Complex<T>] {
39 #[inline(always)]
40 unsafe fn load(&self, idx: usize) -> Complex<T> {
41 debug_assert!(idx < self.len());
42 *self.get_unchecked(idx)
43 }
44 #[inline(always)]
45 unsafe fn store(&mut self, val: Complex<T>, idx: usize) {
46 debug_assert!(idx < self.len());
47 *self.get_unchecked_mut(idx) = val;
48 }
49}
50impl<T: FftNum, const N: usize> LoadStore<T> for &mut [Complex<T>; N] {
51 #[inline(always)]
52 unsafe fn load(&self, idx: usize) -> Complex<T> {
53 debug_assert!(idx < self.len());
54 *self.get_unchecked(idx)
55 }
56 #[inline(always)]
57 unsafe fn store(&mut self, val: Complex<T>, idx: usize) {
58 debug_assert!(idx < self.len());
59 *self.get_unchecked_mut(idx) = val;
60 }
61}
62
63pub(crate) struct DoubleBuf<'a, T> {
64 pub input: &'a [Complex<T>],
65 pub output: &'a mut [Complex<T>],
66}
67impl<'a, T> Deref for DoubleBuf<'a, T> {
68 type Target = [Complex<T>];
69 fn deref(&self) -> &Self::Target {
70 self.input
71 }
72}
73impl<'a, T> DerefMut for DoubleBuf<'a, T> {
74 fn deref_mut(&mut self) -> &mut Self::Target {
75 self.output
76 }
77}
78impl<'a, T: FftNum> LoadStore<T> for DoubleBuf<'a, T> {
79 #[inline(always)]
80 unsafe fn load(&self, idx: usize) -> Complex<T> {
81 debug_assert!(idx < self.input.len());
82 *self.input.get_unchecked(idx)
83 }
84 #[inline(always)]
85 unsafe fn store(&mut self, val: Complex<T>, idx: usize) {
86 debug_assert!(idx < self.output.len());
87 *self.output.get_unchecked_mut(idx) = val;
88 }
89}
90
91pub(crate) trait Load<T: FftNum>: Deref {
92 unsafe fn load(&self, idx: usize) -> Complex<T>;
93}
94
95impl<T: FftNum> Load<T> for &[Complex<T>] {
96 #[inline(always)]
97 unsafe fn load(&self, idx: usize) -> Complex<T> {
98 debug_assert!(idx < self.len());
99 *self.get_unchecked(idx)
100 }
101}
102impl<T: FftNum, const N: usize> Load<T> for &[Complex<T>; N] {
103 #[inline(always)]
104 unsafe fn load(&self, idx: usize) -> Complex<T> {
105 debug_assert!(idx < self.len());
106 *self.get_unchecked(idx)
107 }
108}
109
110#[cfg(test)]
111mod unit_tests {
112 use super::*;
113 use crate::test_utils::random_signal;
114 use num_complex::Complex;
115 use num_traits::Zero;
116
117 #[test]
118 fn test_transpose() {
119 let sizes: Vec<usize> = (1..16).collect();
120
121 for &width in &sizes {
122 for &height in &sizes {
123 let len = width * height;
124
125 let input: Vec<Complex<f32>> = random_signal(len);
126 let mut output = vec![Zero::zero(); len];
127
128 unsafe { transpose_small(width, height, &input, &mut output) };
129
130 for x in 0..width {
131 for y in 0..height {
132 assert_eq!(
133 input[x + y * width],
134 output[y + x * height],
135 "x = {}, y = {}",
136 x,
137 y
138 );
139 }
140 }
141 }
142 }
143 }
144}
145
146pub fn validate_and_iter<T>(
152 mut buffer: &mut [T],
153 scratch: &mut [T],
154 chunk_size: usize,
155 required_scratch: usize,
156 mut chunk_fn: impl FnMut(&mut [T], &mut [T]),
157) -> Result<(), ()> {
158 if scratch.len() < required_scratch {
159 return Err(());
160 }
161 let scratch = &mut scratch[..required_scratch];
162
163 while buffer.len() >= chunk_size {
165 let (head, tail) = buffer.split_at_mut(chunk_size);
166 buffer = tail;
167
168 chunk_fn(head, scratch);
169 }
170
171 if buffer.len() == 0 {
173 Ok(())
174 } else {
175 Err(())
176 }
177}
178
179pub fn validate_and_iter_unroll2x<T>(
183 mut buffer: &mut [T],
184 chunk_size: usize,
185 mut chunk2x_fn: impl FnMut(&mut [T]),
186 mut chunk_fn: impl FnMut(&mut [T]),
187) -> Result<(), ()> {
188 while buffer.len() >= chunk_size * 2 {
190 let (head, tail) = buffer.split_at_mut(chunk_size * 2);
191 buffer = tail;
192
193 chunk2x_fn(head);
194 }
195
196 if buffer.len() == chunk_size {
197 chunk_fn(buffer);
198 Ok(())
199 } else if buffer.len() == 0 {
200 Ok(())
201 } else {
202 Err(())
203 }
204}
205
206pub fn validate_and_zip<T>(
213 mut buffer1: &[T],
214 mut buffer2: &mut [T],
215 scratch: &mut [T],
216 chunk_size: usize,
217 required_scratch: usize,
218 mut chunk_fn: impl FnMut(&[T], &mut [T], &mut [T]),
219) -> Result<(), ()> {
220 if scratch.len() < required_scratch {
221 return Err(());
222 }
223 let scratch = &mut scratch[..required_scratch];
224
225 if buffer1.len() != buffer2.len() {
226 return Err(());
227 }
228
229 while buffer1.len() >= chunk_size {
231 let (head1, tail1) = buffer1.split_at(chunk_size);
232 buffer1 = tail1;
233
234 let (head2, tail2) = buffer2.split_at_mut(chunk_size);
235 buffer2 = tail2;
236
237 chunk_fn(head1, head2, scratch);
238 }
239
240 if buffer1.len() == 0 {
242 Ok(())
243 } else {
244 Err(())
245 }
246}
247
248pub fn validate_and_zip_unroll2x<T>(
255 mut buffer1: &[T],
256 mut buffer2: &mut [T],
257 chunk_size: usize,
258 mut chunk2x_fn: impl FnMut(&[T], &mut [T]),
259 mut chunk_fn: impl FnMut(&[T], &mut [T]),
260) -> Result<(), ()> {
261 if buffer1.len() != buffer2.len() {
262 return Err(());
263 }
264
265 while buffer1.len() >= chunk_size * 2 {
267 let (head1, tail1) = buffer1.split_at(chunk_size * 2);
268 buffer1 = tail1;
269
270 let (head2, tail2) = buffer2.split_at_mut(chunk_size * 2);
271 buffer2 = tail2;
272
273 chunk2x_fn(head1, head2);
274 }
275
276 if buffer1.len() == chunk_size {
278 chunk_fn(buffer1, buffer2);
279 Ok(())
280 } else if buffer1.len() == 0 {
281 Ok(())
282 } else {
283 Err(())
284 }
285}
286
287pub fn validate_and_zip_mut<T>(
294 mut buffer1: &mut [T],
295 mut buffer2: &mut [T],
296 scratch: &mut [T],
297 chunk_size: usize,
298 required_scratch: usize,
299 mut chunk_fn: impl FnMut(&mut [T], &mut [T], &mut [T]),
300) -> Result<(), ()> {
301 if scratch.len() < required_scratch {
302 return Err(());
303 }
304 let scratch = &mut scratch[..required_scratch];
305
306 if buffer1.len() != buffer2.len() {
307 return Err(());
308 }
309
310 while buffer1.len() >= chunk_size {
312 let (head1, tail1) = buffer1.split_at_mut(chunk_size);
313 buffer1 = tail1;
314
315 let (head2, tail2) = buffer2.split_at_mut(chunk_size);
316 buffer2 = tail2;
317
318 chunk_fn(head1, head2, scratch);
319 }
320
321 if buffer1.len() == 0 {
323 Ok(())
324 } else {
325 Err(())
326 }
327}
328
329pub fn validate_and_zip_mut_unroll2x<T>(
336 mut buffer1: &mut [T],
337 mut buffer2: &mut [T],
338 chunk_size: usize,
339 mut chunk2x_fn: impl FnMut(&mut [T], &mut [T]),
340 mut chunk_fn: impl FnMut(&mut [T], &mut [T]),
341) -> Result<(), ()> {
342 if buffer1.len() != buffer2.len() {
343 return Err(());
344 }
345
346 while buffer1.len() >= chunk_size * 2 {
348 let (head1, tail1) = buffer1.split_at_mut(chunk_size * 2);
349 buffer1 = tail1;
350
351 let (head2, tail2) = buffer2.split_at_mut(chunk_size * 2);
352 buffer2 = tail2;
353
354 chunk2x_fn(head1, head2);
355 }
356
357 if buffer1.len() == chunk_size {
359 chunk_fn(buffer1, buffer2);
360 Ok(())
361 } else if buffer1.len() == 0 {
362 Ok(())
363 } else {
364 Err(())
365 }
366}
367
368pub fn bitreversed_transpose<T: Copy, const D: usize>(
373 height: usize,
374 input: &[T],
375 output: &mut [T],
376) {
377 let width = input.len() / height;
378
379 assert!(D > 1 && input.len() % height == 0 && input.len() == output.len());
381
382 let strided_width = width / D;
383 let rev_digits = if D.is_power_of_two() {
384 let width_bits = width.trailing_zeros();
385 let d_bits = D.trailing_zeros();
386
387 assert!(width_bits % d_bits == 0);
389 width_bits / d_bits
390 } else {
391 compute_logarithm::<D>(width).unwrap()
392 };
393
394 for x in 0..strided_width {
395 let mut i = 0;
396 let x_fwd = [(); D].map(|_| {
397 let value = D * x + i;
398 i += 1;
399 value
400 }); let x_rev = x_fwd.map(|x| reverse_bits::<D>(x, rev_digits));
402
403 for r in x_rev {
408 assert!(r < width);
409 }
410 for y in 0..height {
411 for (fwd, rev) in x_fwd.iter().zip(x_rev.iter()) {
412 let input_index = *fwd + y * width;
413 let output_index = y + *rev * height;
414
415 unsafe {
416 let temp = *input.get_unchecked(input_index);
417 *output.get_unchecked_mut(output_index) = temp;
418 }
419 }
420 }
421 }
422}
423
424pub fn reverse_bits<const D: usize>(value: usize, rev_digits: u32) -> usize {
428 assert!(D > 1);
429
430 let mut result: usize = 0;
431 let mut value = value;
432 for _ in 0..rev_digits {
433 result = (result * D) + (value % D);
434 value = value / D;
435 }
436 result
437}
438
439pub fn compute_logarithm<const D: usize>(value: usize) -> Option<u32> {
441 if value == 0 || D < 2 {
442 return None;
443 }
444
445 let mut current_exponent = 0;
446 let mut current_value = value;
447
448 while current_value % D == 0 {
449 current_exponent += 1;
450 current_value /= D;
451 }
452
453 if current_value == 1 {
454 Some(current_exponent)
455 } else {
456 None
457 }
458}
459
460pub(crate) struct TransposeFactor {
461 pub factor: RadixFactor,
462 pub count: u8,
463}
464
465pub(crate) fn factor_transpose<T: Copy, const D: usize>(
470 height: usize,
471 input: &[T],
472 output: &mut [T],
473 factors: &[TransposeFactor],
474) {
475 let width = input.len() / height;
476
477 assert!(width % D == 0 && D > 1 && input.len() % width == 0 && input.len() == output.len());
479
480 let strided_width = width / D;
481 for x in 0..strided_width {
482 let mut i = 0;
483 let x_fwd = [(); D].map(|_| {
484 let value = D * x + i;
485 i += 1;
486 value
487 }); let x_rev = x_fwd.map(|x| reverse_remainders(x, factors));
489
490 for r in x_rev {
495 assert!(r < width);
496 }
497 for y in 0..height {
498 for (fwd, rev) in x_fwd.iter().zip(x_rev.iter()) {
499 let input_index = *fwd + y * width;
500 let output_index = y + *rev * height;
501
502 unsafe {
503 let temp = *input.get_unchecked(input_index);
504 *output.get_unchecked_mut(output_index) = temp;
505 }
506 }
507 }
508 }
509}
510
511pub(crate) fn reverse_remainders(value: usize, factors: &[TransposeFactor]) -> usize {
515 let mut result: usize = 0;
516 let mut value = value;
517 for f in factors.iter() {
518 match f.factor {
519 RadixFactor::Factor2 => {
520 for _ in 0..f.count {
521 result = (result * 2) + (value % 2);
522 value = value / 2;
523 }
524 }
525 RadixFactor::Factor3 => {
526 for _ in 0..f.count {
527 result = (result * 3) + (value % 3);
528 value = value / 3;
529 }
530 }
531 RadixFactor::Factor4 => {
532 for _ in 0..f.count {
533 result = (result * 4) + (value % 4);
534 value = value / 4;
535 }
536 }
537 RadixFactor::Factor5 => {
538 for _ in 0..f.count {
539 result = (result * 5) + (value % 5);
540 value = value / 5;
541 }
542 }
543 RadixFactor::Factor6 => {
544 for _ in 0..f.count {
545 result = (result * 6) + (value % 6);
546 value = value / 6;
547 }
548 }
549 RadixFactor::Factor7 => {
550 for _ in 0..f.count {
551 result = (result * 7) + (value % 7);
552 value = value / 7;
553 }
554 }
555 }
556 }
557 result
558}