ark_poly/polynomial/multivariate/
mod.rs1use ark_ff::Field;
3use ark_serialize::{CanonicalDeserialize, CanonicalSerialize};
4use ark_std::{
5 cfg_into_iter,
6 cmp::Ordering,
7 fmt::{Debug, Error, Formatter},
8 hash::Hash,
9 ops::Deref,
10 vec::*,
11};
12
13#[cfg(feature = "parallel")]
14use rayon::prelude::*;
15
16mod sparse;
17pub use sparse::SparsePolynomial;
18
19pub trait Term:
21 Clone
22 + PartialOrd
23 + Ord
24 + PartialEq
25 + Eq
26 + Hash
27 + Default
28 + Debug
29 + Deref<Target = [(usize, usize)]>
30 + Send
31 + Sync
32 + CanonicalSerialize
33 + CanonicalDeserialize
34{
35 fn new(term: Vec<(usize, usize)>) -> Self;
37
38 fn degree(&self) -> usize;
41
42 fn vars(&self) -> Vec<usize>;
44
45 fn powers(&self) -> Vec<usize>;
47
48 fn is_constant(&self) -> bool;
50
51 fn evaluate<F: Field>(&self, p: &[F]) -> F;
53}
54
55#[derive(Clone, PartialEq, Eq, Hash, Default, CanonicalSerialize, CanonicalDeserialize)]
58pub struct SparseTerm(Vec<(usize, usize)>);
59
60impl SparseTerm {
61 fn combine(term: &[(usize, usize)]) -> Vec<(usize, usize)> {
63 let mut term_dedup: Vec<(usize, usize)> = Vec::new();
64 for (var, pow) in term {
65 if let Some(prev) = term_dedup.last_mut() {
66 if prev.0 == *var {
67 prev.1 += pow;
68 continue;
69 }
70 }
71 term_dedup.push((*var, *pow));
72 }
73 term_dedup
74 }
75}
76
77impl Term for SparseTerm {
78 fn new(mut term: Vec<(usize, usize)>) -> Self {
80 term.retain(|(_, pow)| *pow != 0);
82 if term.len() > 1 {
85 term.sort_by(|(v1, _), (v2, _)| v1.cmp(v2));
86 term = Self::combine(&term);
87 }
88 Self(term)
89 }
90
91 fn degree(&self) -> usize {
93 self.iter().fold(0, |sum, acc| sum + acc.1)
94 }
95
96 fn vars(&self) -> Vec<usize> {
98 self.iter().map(|(v, _)| *v).collect()
99 }
100
101 fn powers(&self) -> Vec<usize> {
103 self.iter().map(|(_, p)| *p).collect()
104 }
105
106 fn is_constant(&self) -> bool {
108 self.is_empty() || self.degree() == 0
109 }
110
111 fn evaluate<F: Field>(&self, point: &[F]) -> F {
113 cfg_into_iter!(self)
114 .map(|(var, power)| point[*var].pow([*power as u64]))
115 .product()
116 }
117}
118
119impl Debug for SparseTerm {
120 fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error> {
121 for variable in self.iter() {
122 if variable.1 == 1 {
123 write!(f, " * x_{}", variable.0)?;
124 } else {
125 write!(f, " * x_{}^{}", variable.0, variable.1)?;
126 }
127 }
128 Ok(())
129 }
130}
131
132impl Deref for SparseTerm {
133 type Target = [(usize, usize)];
134
135 fn deref(&self) -> &[(usize, usize)] {
136 &self.0
137 }
138}
139
140impl PartialOrd for SparseTerm {
141 #[allow(clippy::non_canonical_partial_ord_impl)]
145 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
146 if self.degree() == other.degree() {
147 for ((cur_variable, cur_power), (other_variable, other_power)) in
150 self.iter().zip(other.iter())
151 {
152 if other_variable == cur_variable {
153 if cur_power != other_power {
154 return Some(cur_power.cmp(other_power));
155 }
156 } else {
157 return Some(other_variable.cmp(cur_variable));
158 }
159 }
160 Some(Ordering::Equal)
161 } else {
162 Some(self.degree().cmp(&other.degree()))
163 }
164 }
165}
166
167impl Ord for SparseTerm {
168 fn cmp(&self, other: &Self) -> Ordering {
169 self.partial_cmp(other).unwrap()
170 }
171}
172
173#[cfg(test)]
174mod tests {
175 use super::*;
176 use ark_ff::{Fp64, MontBackend, MontConfig};
177 use ark_std::vec;
178
179 #[derive(MontConfig)]
180 #[modulus = "5"]
181 #[generator = "2"]
182 pub(crate) struct F5Config;
183
184 pub(crate) type F5 = Fp64<MontBackend<F5Config, 1>>;
185
186 #[test]
187 fn test_sparse_term_combine() {
188 let term = vec![(1, 2), (1, 3), (2, 1)];
189 let combined = SparseTerm::combine(&term);
190 assert_eq!(combined, vec![(1, 5), (2, 1)]);
191 }
192
193 #[test]
194 fn test_sparse_term_new() {
195 let term = vec![(2, 1), (1, 2), (1, 3), (3, 0)];
196 let sparse_term = SparseTerm::new(term);
197 assert_eq!(sparse_term, SparseTerm(vec![(1, 5), (2, 1)]));
202 }
203
204 #[test]
205 fn test_sparse_term_degree() {
206 let term = SparseTerm::new(vec![(1, 2), (2, 3)]);
207 assert_eq!(term.degree(), 5); }
209
210 #[test]
211 fn test_sparse_term_vars() {
212 let term = SparseTerm::new(vec![(1, 1), (1, 2), (2, 3)]);
213 assert_eq!(term.vars(), vec![1, 2]);
214 }
215
216 #[test]
217 fn test_sparse_term_powers() {
218 let term = SparseTerm::new(vec![(1, 2), (1, 3), (2, 3)]);
219 assert_eq!(term.powers(), vec![5, 3]);
220 }
221
222 #[test]
223 fn test_sparse_term_is_constant() {
224 let constant_term = SparseTerm::new(vec![]);
225 assert!(constant_term.is_constant());
226
227 let non_constant_term = SparseTerm::new(vec![(1, 2)]);
228 assert!(!non_constant_term.is_constant());
229 }
230
231 #[test]
232 fn test_evaluate() {
233 let term = SparseTerm::new(vec![(0, 2), (1, 3)]);
234 let point = vec![F5::from(1u64), F5::from(2u64)];
235 let result = term.evaluate::<F5>(&point);
236 assert_eq!(result, F5::from(8u64)); }
238
239 #[test]
240 fn test_partial_cmp() {
241 let term1 = SparseTerm::new(vec![(1, 2), (2, 3)]);
242 let term2 = SparseTerm::new(vec![(1, 2), (2, 2)]);
243 let term3 = SparseTerm::new(vec![(2, 3), (1, 2)]);
244 let term4 = SparseTerm::new(vec![(1, 2)]);
245 let term5 = SparseTerm::new(vec![(2, 2)]);
246 let term6 = SparseTerm::new(vec![(1, 0), (2, 0)]);
248 let term7 = SparseTerm::new(vec![]);
250
251 assert_eq!(term1.partial_cmp(&term2), Some(Ordering::Greater)); assert_eq!(term1.partial_cmp(&term3), Some(Ordering::Equal)); assert_eq!(term2.partial_cmp(&term3), Some(Ordering::Less)); assert_eq!(term1.partial_cmp(&term4), Some(Ordering::Greater)); assert_eq!(term4.partial_cmp(&term5), Some(Ordering::Greater)); assert_eq!(term4.partial_cmp(&term6), Some(Ordering::Greater)); assert_eq!(term6.partial_cmp(&term7), Some(Ordering::Equal)); assert_eq!(term7.partial_cmp(&term1), Some(Ordering::Less)); }
265
266 #[test]
267 fn test_cmp() {
268 let term1 = SparseTerm::new(vec![(1, 2), (2, 3)]);
269 let term2 = SparseTerm::new(vec![(1, 2), (2, 2)]);
270 let term3 = SparseTerm::new(vec![(2, 3), (1, 2)]);
271 let term4 = SparseTerm::new(vec![(1, 2)]);
272 let term5 = SparseTerm::new(vec![(2, 2)]);
273 let term6 = SparseTerm::new(vec![(1, 0), (2, 0)]);
275 let term7 = SparseTerm::new(vec![]);
277
278 assert_eq!(term1.cmp(&term2), Ordering::Greater); assert_eq!(term1.cmp(&term3), Ordering::Equal); assert_eq!(term2.cmp(&term3), Ordering::Less); assert_eq!(term1.cmp(&term4), Ordering::Greater); assert_eq!(term4.cmp(&term5), Ordering::Greater); assert_eq!(term4.cmp(&term6), Ordering::Greater); assert_eq!(term6.cmp(&term7), Ordering::Equal); assert_eq!(term7.cmp(&term1), Ordering::Less); }
292}