twenty_first/math/
traits.rs1use std::fmt::Debug;
2use std::fmt::Display;
3use std::hash::Hash;
4use std::ops::Add;
5use std::ops::AddAssign;
6use std::ops::Div;
7use std::ops::Mul;
8use std::ops::MulAssign;
9use std::ops::Neg;
10use std::ops::Sub;
11use std::ops::SubAssign;
12
13use num_traits::ConstOne;
14use num_traits::ConstZero;
15use num_traits::Zero;
16use rayon::prelude::*;
17use serde::Serialize;
18use serde::de::DeserializeOwned;
19
20pub trait CyclicGroupGenerator
21where
22 Self: Sized,
23{
24 fn get_cyclic_group_elements(&self, max: Option<usize>) -> Vec<Self>;
25}
26
27pub trait Inverse
29where
30 Self: Sized + Zero,
31{
32 fn inverse(&self) -> Self;
39
40 fn inverse_or_zero(&self) -> Self {
41 if self.is_zero() {
42 Self::zero()
43 } else {
44 self.inverse()
45 }
46 }
47}
48
49pub trait PrimitiveRootOfUnity
50where
51 Self: Sized,
52{
53 fn primitive_root_of_unity(n: u64) -> Option<Self>;
54}
55
56pub trait ModPowU64 {
57 #[must_use]
58 fn mod_pow_u64(&self, pow: u64) -> Self;
59}
60
61pub trait ModPowU32 {
62 #[must_use]
63 fn mod_pow_u32(&self, exp: u32) -> Self;
64}
65
66pub trait FiniteField:
67 Copy
68 + Debug
69 + Display
70 + Eq
71 + Serialize
72 + DeserializeOwned
73 + Hash
74 + ConstZero
75 + ConstOne
76 + Add<Output = Self>
77 + Mul<Output = Self>
78 + Sub<Output = Self>
79 + Div<Output = Self>
80 + Neg<Output = Self>
81 + AddAssign
82 + MulAssign
83 + SubAssign
84 + CyclicGroupGenerator
85 + PrimitiveRootOfUnity
86 + Inverse
87 + ModPowU32
88 + From<u64>
89 + Send
90 + Sync
91{
92 const NUM_BFE_LIMBS: Option<usize> = None;
102
103 fn batch_inversion(input: Vec<Self>) -> Vec<Self> {
106 let input_length = input.len();
107 if input_length == 0 {
108 return Vec::<Self>::new();
109 }
110
111 let zero = Self::zero();
112 let one = Self::one();
113 let mut scratch: Vec<Self> = vec![zero; input_length];
114 let mut acc = one;
115 scratch[0] = input[0];
116
117 for i in 0..input_length {
118 assert!(!input[i].is_zero(), "Cannot do batch inversion on zero");
119 scratch[i] = acc;
120 acc *= input[i];
121 }
122
123 acc = acc.inverse();
124
125 let mut res = input;
126 for i in (0..input_length).rev() {
127 let tmp = acc * res[i];
128 res[i] = acc * scratch[i];
129 acc = tmp;
130 }
131
132 res
133 }
134
135 fn par_batch_inversion(mut input: Vec<Self>) -> Vec<Self> {
141 const CHUNK_SIZE: usize = 1 << 12;
144
145 input.par_chunks_mut(CHUNK_SIZE).for_each(|chunk| {
146 let inverses = Self::batch_inversion(chunk.to_vec());
147 chunk.copy_from_slice(&inverses);
148 });
149 input
150 }
151
152 #[inline(always)]
153 fn square(self) -> Self {
154 self * self
155 }
156}
157
158#[cfg(test)]
159#[cfg_attr(coverage_nightly, coverage(off))]
160mod tests {
161 use super::*;
162 use crate::math::other::random_elements;
163 use crate::prelude::*;
164 use crate::tests::test;
165
166 #[macro_rules_attr::apply(test)]
167 fn parallel_and_serial_batch_inversion_agree() {
168 for len in [
170 0,
171 1,
172 7,
173 (1 << 12) - 1,
174 1 << 12,
175 (1 << 12) + 1,
176 (1 << 14) + 3,
177 ] {
178 let bfes: Vec<BFieldElement> = random_elements(len);
179 let bfes: Vec<_> = bfes.into_iter().filter(|x| !x.is_zero()).collect();
180 let serial = BFieldElement::batch_inversion(bfes.clone());
181 let parallel = BFieldElement::par_batch_inversion(bfes.clone());
182 assert_eq!(serial, parallel, "{len}");
183 for (x, x_inv) in bfes.into_iter().zip(parallel) {
184 assert_eq!(BFieldElement::ONE, x * x_inv);
185 }
186
187 let xfes: Vec<XFieldElement> = random_elements(len);
188 let xfes: Vec<_> = xfes.into_iter().filter(|x| !x.is_zero()).collect();
189 let serial_xfes = XFieldElement::batch_inversion(xfes.clone());
190 let parallel_xfes = XFieldElement::par_batch_inversion(xfes);
191 assert_eq!(serial_xfes, parallel_xfes, "{len}");
192 }
193 }
194}