poulpy/math/tests/automorphism.rs
math/tests/automorphism.rsRaw
1use itertools::izip;
2use math::poly::Poly;
3use math::ring::impl_u64::ring;
4use math::ring::Ring;
5
6#[test]
7fn automorphism_u64() {
8 let n: usize = 1 << 4;
9 let nth_root: usize = n << 1;
10 let q_base: u64 = 65537u64;
11 let q_power: usize = 1usize;
12 let ring: Ring<u64> = Ring::new(n, q_base, q_power);
13
14 sub_test("test_automorphism_u64::<NTT:false>", || {
15 test_automorphism_u64::<false>(&ring, nth_root)
16 });
17 sub_test("test_automorphism_u64::<NTT:true>", || {
18 test_automorphism_u64::<true>(&ring, nth_root)
19 });
20}
21
22fn sub_test<F: FnOnce()>(name: &str, f: F) {
23 println!("Running {}", name);
24 f();
25}
26
27fn test_automorphism_u64<const NTT: bool>(ring: &Ring<u64>, nth_root: usize) {
28 let n: usize = ring.n();
29 let q: u64 = ring.modulus.q;
30
31 let mut p0: Poly<u64> = ring.new_poly();
32 let mut p1: Poly<u64> = ring.new_poly();
33
34 for i in 0..p0.n() {
35 p0.0[i] = i as u64
36 }
37
38 if NTT {
39 ring.ntt_inplace::<false>(&mut p0);
40 }
41
42 ring.automorphism::<NTT>(&p0, 2 * n - 1, nth_root, &mut p1);
43
44 if NTT {
45 ring.intt_inplace::<false>(&mut p1);
46 }
47
48 p0.0[0] = 0;
49 for i in 1..p0.n() {
50 p0.0[i] = q - (n - i) as u64
51 }
52
53 izip!(p0.0, p1.0).for_each(|(a, b)| assert_eq!(a, b));
54}
55
56#[test]
57fn packing_u64() {
58 let n: usize = 1 << 5;
59 let q_base: u64 = 65537u64;
60 let q_power: usize = 1usize;
61 let ring: Ring<u64> = Ring::new(n, q_base, q_power);
62
63 sub_test("test_packing_u64::<NTT:false>", || {
64 test_packing_full_u64::<false>(&ring)
65 });
66 sub_test("test_packing_u64::<NTT:true>", || {
67 test_packing_full_u64::<true>(&ring)
68 });
69 sub_test("test_packing_sparse_u64::<NTT:false>", || {
70 test_packing_sparse_u64::<false>(&ring)
71 });
72 sub_test("test_packing_sparse_u64::<NTT:true>", || {
73 test_packing_sparse_u64::<true>(&ring)
74 });
75}
76
77fn test_packing_full_u64<const NTT: bool>(ring: &Ring<u64>) {
78 let n: usize = ring.n();
79
80 let mut result: Vec<Option<Poly<u64>>> = vec![None; n];
81
82 for i in 0..n {
83 let mut poly: Poly<u64> = ring.new_poly();
84 poly.fill(&(1 + i as u64));
85 if NTT {
86 ring.ntt_inplace::<false>(&mut poly);
87 }
88
89 result[i] = Some(poly);
90 }
91
92 ring.pack::<true, NTT>(&mut result, ring.log_n());
93
94 if let Some(poly) = result[0].as_mut() {
95 if NTT {
96 ring.intt_inplace::<false>(poly);
97 }
98
99 poly.0
100 .iter()
101 .enumerate()
102 .for_each(|(i, x)| assert_eq!(*x, 1 + i as u64));
103 }
104}
105
106fn test_packing_sparse_u64<const NTT: bool>(ring: &Ring<u64>) {
107 let n: usize = ring.n();
108
109 let mut result: Vec<Option<Poly<u64>>> = vec![None; n];
110
111 let gap: usize = 3;
112
113 for i in (0..n).step_by(gap) {
114 let mut poly: Poly<u64> = ring.new_poly();
115 poly.fill(&(1 + i as u64));
116 if NTT {
117 ring.ntt_inplace::<false>(&mut poly);
118 }
119 result[i] = Some(poly);
120 }
121
122 ring.pack::<true, NTT>(&mut result, ring.log_n());
123
124 if let Some(poly) = result[0].as_mut() {
125 if NTT {
126 ring.intt_inplace::<false>(poly);
127 }
128
129 poly.0.iter().enumerate().for_each(|(i, x)| {
130 if i % gap == 0 {
131 assert_eq!(*x, 1 + i as u64)
132 } else {
133 assert_eq!(*x, 0u64)
134 }
135 });
136 }
137}