mirror of
https://github.com/pseXperiments/icicle.git
synced 2026-01-09 23:48:10 -05:00
fix: bug regarding MixedRadix coset (I)NTT for NM/MN ordering (#497)
The bug is in how twiddles array is indexed when multiplied by a mixed (M) vector to implement (I)NTT on cosets. The fix is to use the DIF-digit-reverse to compute the index of the element in the natural (N) vector that moved to index 'i' in the M vector. This is emulating a DIT-digit-reverse (which is mixing like a DIF-compute) reorder of the twiddles array and element-wise multiplication without reordering the twiddles memory.
This commit is contained in:
@@ -378,6 +378,13 @@ macro_rules! impl_ntt_tests {
|
||||
check_ntt_coset_from_subgroup::<$field>()
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[parallel]
|
||||
fn test_ntt_coset_interpolation_nm() {
|
||||
INIT.get_or_init(move || init_domain::<$field>(MAX_SIZE, DEFAULT_DEVICE_ID, FAST_TWIDDLES_MODE));
|
||||
check_ntt_coset_interpolation_nm::<$field>();
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[parallel]
|
||||
fn test_ntt_arbitrary_coset() {
|
||||
|
||||
@@ -190,6 +190,62 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
pub fn check_ntt_coset_interpolation_nm<F: FieldImpl + ArkConvertible>()
|
||||
where
|
||||
F::ArkEquivalent: FftField,
|
||||
<F as FieldImpl>::Config: NTT<F, F> + GenerateRandom<F>,
|
||||
{
|
||||
let test_sizes = [1 << 9, 1 << 10, 1 << 11, 1 << 13, 1 << 14, 1 << 16];
|
||||
for test_size in test_sizes {
|
||||
let test_size_rou = F::ArkEquivalent::get_root_of_unity((test_size << 1) as u64).unwrap();
|
||||
let coset_generators = [F::from_ark(test_size_rou), F::Config::generate_random(1)[0]];
|
||||
|
||||
let scalars: Vec<F> = F::Config::generate_random(test_size);
|
||||
|
||||
let ark_domain = GeneralEvaluationDomain::<F::ArkEquivalent>::new(test_size).unwrap();
|
||||
|
||||
for coset_gen in coset_generators {
|
||||
// (1) intt from evals to coeffs
|
||||
let mut config = NTTConfig::default();
|
||||
config.ordering = Ordering::kNM;
|
||||
config.ntt_algorithm = NttAlgorithm::MixedRadix;
|
||||
|
||||
let mut intt_result = vec![F::zero(); test_size];
|
||||
let intt_result = HostSlice::from_mut_slice(&mut intt_result);
|
||||
ntt(HostSlice::from_slice(&scalars), NTTDir::kInverse, &config, intt_result).unwrap();
|
||||
|
||||
let mut ark_scalars = scalars
|
||||
.iter()
|
||||
.map(|v| v.to_ark())
|
||||
.collect::<Vec<F::ArkEquivalent>>();
|
||||
ark_domain.ifft_in_place(&mut ark_scalars);
|
||||
|
||||
// (2) coset-ntt (compute coset evals)
|
||||
config.coset_gen = coset_gen;
|
||||
config.ordering = Ordering::kMN;
|
||||
let mut coset_evals = vec![F::zero(); test_size];
|
||||
ntt(
|
||||
intt_result,
|
||||
NTTDir::kForward,
|
||||
&config,
|
||||
HostSlice::from_mut_slice(&mut coset_evals),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let ark_coset_domain = ark_domain
|
||||
.get_coset(coset_gen.to_ark())
|
||||
.unwrap();
|
||||
ark_coset_domain.fft_in_place(&mut ark_scalars); // to reuse in next iteration
|
||||
|
||||
let coest_evals_as_ark = coset_evals
|
||||
.iter()
|
||||
.map(|v| v.to_ark())
|
||||
.collect::<Vec<F::ArkEquivalent>>();
|
||||
assert_eq!(coest_evals_as_ark, ark_scalars);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn check_ntt_arbitrary_coset<F: FieldImpl + ArkConvertible>()
|
||||
where
|
||||
F::ArkEquivalent: FftField + ArkField,
|
||||
|
||||
Reference in New Issue
Block a user