Skip to main content

zinc_poly/univariate/
dense.rs

1use crate::{
2    ConstCoeffBitWidth, EvaluatablePolynomial, EvaluationError, Polynomial,
3    univariate::{binary_ref::BinaryRefPoly, binary_u64::BinaryU64Poly},
4};
5
6use core::slice;
7use crypto_primitives::{
8    FixedSemiring, FromWithConfig, IntoWithConfig, PrimeField, Ring, Semiring, boolean::Boolean,
9};
10use itertools::Itertools;
11use num_traits::{CheckedAdd, CheckedMul, CheckedNeg, CheckedSub, ConstOne, ConstZero, One, Zero};
12use rand::{distr::StandardUniform, prelude::*};
13use std::{
14    array,
15    fmt::Display,
16    hash::Hash,
17    iter::{Product, Sum},
18    marker::PhantomData,
19    ops::{Add, AddAssign, Deref, DerefMut, Mul, MulAssign, Neg, Sub, SubAssign},
20};
21use zinc_transcript::traits::{ConstTranscribable, GenTranscribable};
22use zinc_utils::{
23    from_ref::FromRef,
24    inner_product::{InnerProduct, InnerProductError},
25    mul_by_scalar::MulByScalar,
26    named::Named,
27    projectable_to_field::ProjectableToField,
28};
29
30#[derive(Debug, Clone, PartialEq, Eq)]
31pub struct DensePolynomial<R, const DEGREE_PLUS_ONE: usize> {
32    /// Coefficients of the polynomial, lowest degree first
33    pub coeffs: [R; DEGREE_PLUS_ONE],
34}
35
36impl<R: Semiring + Zero, const DEGREE_PLUS_ONE: usize> DensePolynomial<R, DEGREE_PLUS_ONE> {
37    /// Create a new polynomial with the given coefficients.
38    /// If the input has fewer than N+1 coefficients, the remaining slots will
39    /// be filled with zeros. If the input has more than N+1 coefficients,
40    /// it will panic.
41    #[allow(clippy::arithmetic_side_effects)]
42    pub fn new(coeffs: impl AsRef<[R]>) -> Self {
43        let coeffs = coeffs.as_ref();
44        assert!(
45            coeffs.len() <= DEGREE_PLUS_ONE,
46            "Too many coefficients provided: expected at most {}, got {}",
47            DEGREE_PLUS_ONE,
48            coeffs.len()
49        );
50
51        if coeffs.is_empty() {
52            return Self::zero();
53        }
54
55        let mut coeffs = coeffs.to_vec();
56        coeffs.resize(DEGREE_PLUS_ONE, R::zero());
57        let coeffs = coeffs.try_into().expect("unreachable");
58
59        DensePolynomial { coeffs }
60    }
61}
62
63impl<R: Semiring, const DEGREE_PLUS_ONE: usize> DensePolynomial<R, DEGREE_PLUS_ONE> {
64    /// Create a new polynomial with the given coefficients.
65    /// If the input has fewer than N+1 coefficients, the remaining slots will
66    /// be filled with zeros. If the input has more than N+1 coefficients,
67    /// it will panic.
68    #[allow(clippy::arithmetic_side_effects)]
69    pub fn new_with_zero(coeffs: impl AsRef<[R]>, zero: R) -> Self {
70        let coeffs = coeffs.as_ref();
71        assert!(
72            coeffs.len() <= DEGREE_PLUS_ONE,
73            "Too many coefficients provided: expected at most {}, got {}",
74            DEGREE_PLUS_ONE,
75            coeffs.len()
76        );
77
78        let mut coeffs = coeffs.to_vec();
79        coeffs.resize(DEGREE_PLUS_ONE, zero);
80        let coeffs = coeffs.try_into().expect("unreachable");
81
82        DensePolynomial { coeffs }
83    }
84}
85
86impl<R: Copy, const DEGREE_PLUS_ONE: usize> Copy for DensePolynomial<R, DEGREE_PLUS_ONE> {}
87
88impl<R: Default, const DEGREE_PLUS_ONE: usize> Default for DensePolynomial<R, DEGREE_PLUS_ONE> {
89    fn default() -> Self {
90        DensePolynomial {
91            coeffs: array::from_fn::<_, DEGREE_PLUS_ONE, _>(|_| R::default()),
92        }
93    }
94}
95
96impl<R: Display, const DEGREE_PLUS_ONE: usize> Display for DensePolynomial<R, DEGREE_PLUS_ONE> {
97    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
98        write!(f, "[")?;
99        let mut first = true;
100        for coeff in self.coeffs.iter() {
101            if first {
102                first = false;
103            } else {
104                write!(f, ", ")?;
105            }
106            write!(f, "{}", coeff)?;
107        }
108        write!(f, "]")?;
109        Ok(())
110    }
111}
112
113impl<R: Hash, const DEGREE_PLUS_ONE: usize> Hash for DensePolynomial<R, DEGREE_PLUS_ONE> {
114    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
115        for coeff in self.coeffs.iter() {
116            coeff.hash(state);
117        }
118    }
119}
120
121impl<R: Semiring + Zero, const DEGREE_PLUS_ONE: usize> Zero
122    for DensePolynomial<R, DEGREE_PLUS_ONE>
123{
124    fn zero() -> Self {
125        Self {
126            coeffs: array::from_fn::<_, DEGREE_PLUS_ONE, _>(|_| R::zero()),
127        }
128    }
129
130    fn is_zero(&self) -> bool {
131        self.coeffs.iter().all(|c| c.is_zero())
132    }
133}
134
135impl<F: PrimeField, const DEGREE_PLUS_ONE: usize> DensePolynomial<F, DEGREE_PLUS_ONE> {
136    pub fn zero_with_cfg(cfg: &F::Config) -> Self {
137        let zero = F::zero_with_cfg(cfg);
138        Self {
139            coeffs: array::from_fn(|_| zero.clone()),
140        }
141    }
142
143    pub fn one_with_cfg(cfg: &F::Config) -> Self {
144        Self::new_with_zero([F::one_with_cfg(cfg)], F::zero_with_cfg(cfg))
145    }
146}
147
148impl<R: Semiring + Zero + One, const DEGREE_PLUS_ONE: usize> One
149    for DensePolynomial<R, DEGREE_PLUS_ONE>
150{
151    fn one() -> Self {
152        Self::from(R::one())
153    }
154}
155
156impl<R: Ring + Neg<Output = R>, const DEGREE_PLUS_ONE: usize> Neg
157    for DensePolynomial<R, DEGREE_PLUS_ONE>
158{
159    type Output = Self;
160
161    #[allow(clippy::arithmetic_side_effects)] // By design
162    fn neg(mut self) -> Self::Output {
163        self.coeffs.iter_mut().for_each(|c| *c = -c.clone());
164        self
165    }
166}
167
168impl<R: Semiring, const DEGREE_PLUS_ONE: usize> Add for DensePolynomial<R, DEGREE_PLUS_ONE> {
169    type Output = Self;
170
171    #[allow(clippy::arithmetic_side_effects, clippy::op_ref)]
172    #[inline(always)]
173    fn add(self, rhs: Self) -> Self::Output {
174        self + &rhs
175    }
176}
177
178impl<'a, R: Semiring, const DEGREE_PLUS_ONE: usize> Add<&'a Self>
179    for DensePolynomial<R, DEGREE_PLUS_ONE>
180{
181    type Output = Self;
182
183    #[allow(clippy::arithmetic_side_effects)]
184    #[inline(always)]
185    fn add(mut self, rhs: &'a Self) -> Self::Output {
186        self += rhs;
187        self
188    }
189}
190
191impl<R: Semiring, const DEGREE_PLUS_ONE: usize> Sub for DensePolynomial<R, DEGREE_PLUS_ONE> {
192    type Output = Self;
193
194    #[allow(clippy::arithmetic_side_effects, clippy::op_ref)]
195    #[inline(always)]
196    fn sub(self, rhs: Self) -> Self::Output {
197        self - &rhs
198    }
199}
200
201impl<'a, R: Semiring, const DEGREE_PLUS_ONE: usize> Sub<&'a Self>
202    for DensePolynomial<R, DEGREE_PLUS_ONE>
203{
204    type Output = Self;
205
206    #[allow(clippy::arithmetic_side_effects)]
207    #[inline(always)]
208    fn sub(mut self, rhs: &'a Self) -> Self::Output {
209        self -= rhs;
210        self
211    }
212}
213
214impl<R: Semiring, const DEGREE_PLUS_ONE: usize> Mul for DensePolynomial<R, DEGREE_PLUS_ONE> {
215    type Output = Self;
216
217    #[allow(clippy::arithmetic_side_effects, clippy::op_ref)]
218    #[inline(always)]
219    fn mul(self, rhs: Self) -> Self::Output {
220        self * &rhs
221    }
222}
223
224impl<'a, R: Semiring, const DEGREE_PLUS_ONE: usize> Mul<&'a Self>
225    for DensePolynomial<R, DEGREE_PLUS_ONE>
226{
227    type Output = Self;
228
229    fn mul(self, _rhs: &'a Self) -> Self::Output {
230        unimplemented!("Polynomial multiplication is not implemented")
231    }
232}
233
234impl<R: Semiring, const DEGREE_PLUS_ONE: usize> AddAssign for DensePolynomial<R, DEGREE_PLUS_ONE> {
235    #[allow(clippy::arithmetic_side_effects)]
236    #[inline(always)]
237    fn add_assign(&mut self, rhs: Self) {
238        *self += &rhs;
239    }
240}
241
242impl<'a, R: Semiring, const DEGREE_PLUS_ONE: usize> AddAssign<&'a Self>
243    for DensePolynomial<R, DEGREE_PLUS_ONE>
244{
245    #[allow(clippy::arithmetic_side_effects)]
246    #[inline(always)]
247    fn add_assign(&mut self, rhs: &'a Self) {
248        for i in 0..DEGREE_PLUS_ONE {
249            self.coeffs[i] += &rhs.coeffs[i];
250        }
251    }
252}
253
254impl<R: Semiring, const DEGREE_PLUS_ONE: usize> SubAssign for DensePolynomial<R, DEGREE_PLUS_ONE> {
255    #[allow(clippy::arithmetic_side_effects)]
256    #[inline(always)]
257    fn sub_assign(&mut self, rhs: Self) {
258        *self -= &rhs;
259    }
260}
261
262impl<'a, R: Semiring, const DEGREE_PLUS_ONE: usize> SubAssign<&'a Self>
263    for DensePolynomial<R, DEGREE_PLUS_ONE>
264{
265    #[allow(clippy::arithmetic_side_effects)]
266    #[inline(always)]
267    fn sub_assign(&mut self, rhs: &'a Self) {
268        for i in 0..DEGREE_PLUS_ONE {
269            self.coeffs[i] -= &rhs.coeffs[i];
270        }
271    }
272}
273
274impl<R: Semiring, const DEGREE_PLUS_ONE: usize> MulAssign for DensePolynomial<R, DEGREE_PLUS_ONE> {
275    #[allow(clippy::arithmetic_side_effects)]
276    #[inline(always)]
277    fn mul_assign(&mut self, rhs: Self) {
278        *self *= &rhs;
279    }
280}
281
282impl<'a, R: Semiring, const DEGREE_PLUS_ONE: usize> MulAssign<&'a Self>
283    for DensePolynomial<R, DEGREE_PLUS_ONE>
284{
285    fn mul_assign(&mut self, _rhs: &'a Self) {
286        unimplemented!("Polynomial multiplication is not implemented")
287    }
288}
289
290impl<R: Ring + Zero, const DEGREE_PLUS_ONE: usize> CheckedNeg
291    for DensePolynomial<R, DEGREE_PLUS_ONE>
292{
293    fn checked_neg(&self) -> Option<Self> {
294        let mut coeffs = self.coeffs.clone();
295
296        coeffs
297            .iter_mut()
298            .filter(|coeff| !coeff.is_zero())
299            .try_for_each(|x| {
300                *x = x.checked_neg()?;
301                Some(())
302            })?;
303
304        Some(Self { coeffs })
305    }
306}
307
308impl<R: Semiring, const DEGREE_PLUS_ONE: usize> CheckedAdd for DensePolynomial<R, DEGREE_PLUS_ONE> {
309    fn checked_add(&self, other: &Self) -> Option<Self> {
310        let mut coeffs = self.coeffs.clone();
311
312        coeffs.iter_mut().zip(other).try_for_each(|(a, b)| {
313            *a = a.checked_add(b)?;
314            Some(())
315        })?;
316
317        Some(Self { coeffs })
318    }
319}
320
321impl<R: Semiring, const DEGREE_PLUS_ONE: usize> CheckedSub for DensePolynomial<R, DEGREE_PLUS_ONE> {
322    fn checked_sub(&self, other: &Self) -> Option<Self> {
323        let mut coeffs = self.coeffs.clone();
324
325        coeffs.iter_mut().zip(other).try_for_each(|(a, b)| {
326            *a = a.checked_sub(b)?;
327            Some(())
328        })?;
329
330        Some(Self { coeffs })
331    }
332}
333
334impl<R: Semiring, const DEGREE_PLUS_ONE: usize> CheckedMul for DensePolynomial<R, DEGREE_PLUS_ONE> {
335    fn checked_mul(&self, _other: &Self) -> Option<Self> {
336        unimplemented!("Polynomial multiplication is not implemented")
337    }
338}
339
340impl<R: FixedSemiring, const DEGREE_PLUS_ONE: usize> Sum for DensePolynomial<R, DEGREE_PLUS_ONE> {
341    fn sum<I: Iterator<Item = Self>>(iter: I) -> Self {
342        iter.fold(Self::zero(), |acc, x| {
343            acc.checked_add(&x).expect("overflow in sum")
344        })
345    }
346}
347
348impl<'a, R: FixedSemiring, const DEGREE_PLUS_ONE: usize> Sum<&'a Self>
349    for DensePolynomial<R, DEGREE_PLUS_ONE>
350{
351    fn sum<I: Iterator<Item = &'a Self>>(iter: I) -> Self {
352        iter.fold(Self::zero(), |acc, x| {
353            acc.checked_add(x).expect("overflow in sum")
354        })
355    }
356}
357
358impl<R: FixedSemiring, const DEGREE_PLUS_ONE: usize> Product
359    for DensePolynomial<R, DEGREE_PLUS_ONE>
360{
361    fn product<I: Iterator<Item = Self>>(iter: I) -> Self {
362        iter.fold(Self::one(), |acc, x| {
363            acc.checked_mul(&x).expect("overflow in product")
364        })
365    }
366}
367
368impl<'a, R: FixedSemiring, const DEGREE_PLUS_ONE: usize> Product<&'a Self>
369    for DensePolynomial<R, DEGREE_PLUS_ONE>
370{
371    fn product<I: Iterator<Item = &'a Self>>(iter: I) -> Self {
372        iter.fold(Self::one(), |acc, x| {
373            acc.checked_mul(x).expect("overflow in product")
374        })
375    }
376}
377
378impl<R: Semiring, const DEGREE_PLUS_ONE: usize> Semiring for DensePolynomial<R, DEGREE_PLUS_ONE> {}
379
380impl<R: Ring + FixedSemiring, const DEGREE_PLUS_ONE: usize> Ring
381    for DensePolynomial<R, DEGREE_PLUS_ONE>
382{
383}
384
385impl<R, const DEGREE_PLUS_ONE: usize> Distribution<DensePolynomial<R, DEGREE_PLUS_ONE>>
386    for StandardUniform
387where
388    StandardUniform: Distribution<R>,
389    StandardUniform: Distribution<[R; DEGREE_PLUS_ONE]>, // This one we get for free
390{
391    fn sample<Gen: Rng + ?Sized>(&self, rng: &mut Gen) -> DensePolynomial<R, DEGREE_PLUS_ONE> {
392        let coeffs: [R; DEGREE_PLUS_ONE] = rng.random();
393        DensePolynomial { coeffs }
394    }
395}
396
397//
398// Zip-specific traits
399//
400impl<R: Semiring, const DEGREE_PLUS_ONE: usize> Polynomial<R>
401    for DensePolynomial<R, DEGREE_PLUS_ONE>
402{
403    const DEGREE_BOUND: usize = DEGREE_PLUS_ONE - 1;
404}
405
406impl<R: Semiring, const DEGREE_PLUS_ONE: usize> EvaluatablePolynomial<R, R>
407    for DensePolynomial<R, DEGREE_PLUS_ONE>
408{
409    type EvaluationPoint = R;
410
411    fn evaluate_at_point(&self, point: &R) -> Result<R, EvaluationError> {
412        // Horner's method.
413        let mut result = self
414            .coeffs
415            .last()
416            .ok_or(EvaluationError::EmptyPolynomial)?
417            .clone();
418
419        for coeff in self.coeffs.iter().rev().skip(1) {
420            let term = result.checked_mul(point).ok_or(EvaluationError::Overflow)?;
421            result = term.checked_add(coeff).ok_or(EvaluationError::Overflow)?;
422        }
423
424        Ok(result)
425    }
426}
427
428impl<R: Semiring + ConstTranscribable, const DEGREE_PLUS_ONE: usize> ConstCoeffBitWidth
429    for DensePolynomial<R, DEGREE_PLUS_ONE>
430{
431    const COEFF_BIT_WIDTH: usize = R::NUM_BITS;
432}
433
434impl<R: Semiring + Named, const DEGREE_PLUS_ONE: usize> Named
435    for DensePolynomial<R, DEGREE_PLUS_ONE>
436{
437    fn type_name() -> String {
438        format!("Poly<{}, {}>", R::type_name(), Self::DEGREE_BOUND)
439    }
440}
441
442impl<R: ConstTranscribable + Default, const DEGREE_PLUS_ONE: usize> GenTranscribable
443    for DensePolynomial<R, DEGREE_PLUS_ONE>
444{
445    #[allow(clippy::arithmetic_side_effects)]
446    fn read_transcription_bytes_exact(bytes: &[u8]) -> Self {
447        assert_eq!(
448            bytes.len(),
449            R::NUM_BYTES * DEGREE_PLUS_ONE,
450            "Invalid byte length for DensePolynomial: expected {}, got {}",
451            R::NUM_BYTES * DEGREE_PLUS_ONE,
452            bytes.len()
453        );
454
455        // Can't use as_chunks because generic parameters may not be used in const
456        // operations.
457        let coeffs = bytes
458            .chunks_exact(R::NUM_BYTES)
459            .map(R::read_transcription_bytes_exact)
460            .collect_array()
461            .expect("Unreachable");
462        Self { coeffs }
463    }
464
465    fn write_transcription_bytes_exact(&self, buf: &mut [u8]) {
466        for (chunk, coeff) in buf.chunks_exact_mut(R::NUM_BYTES).zip(self.coeffs.iter()) {
467            coeff.write_transcription_bytes_exact(chunk);
468        }
469    }
470}
471
472impl<R: ConstTranscribable + Default, const DEGREE_PLUS_ONE: usize> ConstTranscribable
473    for DensePolynomial<R, DEGREE_PLUS_ONE>
474{
475    const NUM_BYTES: usize = R::NUM_BYTES * DEGREE_PLUS_ONE;
476}
477
478// Conversions.
479
480impl<R, S, const DEGREE_PLUS_ONE: usize> FromRef<DensePolynomial<S, DEGREE_PLUS_ONE>>
481    for DensePolynomial<R, DEGREE_PLUS_ONE>
482where
483    R: Semiring + FromRef<S> + Default,
484{
485    fn from_ref(value: &DensePolynomial<S, DEGREE_PLUS_ONE>) -> Self {
486        let mut coeffs = array::from_fn::<_, DEGREE_PLUS_ONE, _>(|_| R::default());
487        coeffs
488            .iter_mut()
489            .zip(value.coeffs.iter())
490            .for_each(|(coeff, other_coeff)| {
491                *coeff = R::from_ref(other_coeff);
492            });
493        DensePolynomial { coeffs }
494    }
495}
496
497impl<R, const DEGREE_PLUS_ONE: usize> FromRef<BinaryRefPoly<DEGREE_PLUS_ONE>>
498    for DensePolynomial<R, DEGREE_PLUS_ONE>
499where
500    R: Semiring + FromRef<Boolean> + Default,
501{
502    #[inline(always)]
503    fn from_ref(value: &BinaryRefPoly<DEGREE_PLUS_ONE>) -> Self {
504        Self::from_ref(value.inner())
505    }
506}
507
508impl<R, const DEGREE_PLUS_ONE: usize> FromRef<BinaryU64Poly<DEGREE_PLUS_ONE>>
509    for DensePolynomial<R, DEGREE_PLUS_ONE>
510where
511    R: Semiring + FromRef<Boolean> + Default,
512{
513    #[inline(always)]
514    fn from_ref(value: &BinaryU64Poly<DEGREE_PLUS_ONE>) -> Self {
515        let mut coeffs = array::from_fn::<_, DEGREE_PLUS_ONE, _>(|_| R::default());
516        coeffs.iter_mut().enumerate().for_each(|(i, coeff)| {
517            if value.inner() & (1 << i) != 0 {
518                *coeff = R::from_ref(&Boolean::ONE);
519            } else {
520                *coeff = R::from_ref(&Boolean::ZERO);
521            }
522        });
523        DensePolynomial { coeffs }
524    }
525}
526
527impl<R, S, const DEGREE_PLUS_ONE: usize> From<&DensePolynomial<S, DEGREE_PLUS_ONE>>
528    for DensePolynomial<R, DEGREE_PLUS_ONE>
529where
530    R: Semiring + FromRef<S> + Default,
531{
532    fn from(value: &DensePolynomial<S, DEGREE_PLUS_ONE>) -> Self {
533        Self::from_ref(value)
534    }
535}
536
537impl<R: Zero, const DEGREE_PLUS_ONE: usize> From<R> for DensePolynomial<R, DEGREE_PLUS_ONE> {
538    fn from(value: R) -> Self {
539        let mut coeffs = array::from_fn(|_| R::zero());
540        coeffs[0] = value;
541        Self { coeffs }
542    }
543}
544
545impl<const DEGREE_PLUS_ONE: usize> FromRef<i64> for DensePolynomial<i128, DEGREE_PLUS_ONE> {
546    fn from_ref(value: &i64) -> Self {
547        Self::from(i128::from(*value))
548    }
549}
550
551impl<'a, R, S, Out, const DEGREE_PLUS_ONE: usize>
552    MulByScalar<&'a S, DensePolynomial<Out, DEGREE_PLUS_ONE>>
553    for DensePolynomial<R, DEGREE_PLUS_ONE>
554where
555    R: FixedSemiring + MulByScalar<&'a S, Out>,
556    Out: FixedSemiring + Copy,
557{
558    fn mul_by_scalar<const CHECK: bool>(
559        &self,
560        rhs: &'a S,
561    ) -> Option<DensePolynomial<Out, DEGREE_PLUS_ONE>> {
562        let mut coeffs = [Out::default(); DEGREE_PLUS_ONE];
563
564        coeffs
565            .iter_mut()
566            .zip(self.coeffs.iter())
567            .filter(|(_, coeff)| !coeff.is_zero())
568            .try_for_each(|(out, x)| {
569                *out = x.mul_by_scalar::<CHECK>(rhs)?;
570                Some(())
571            })?;
572
573        Some(DensePolynomial { coeffs })
574    }
575}
576
577impl<R, F, const DEGREE_PLUS_ONE: usize> ProjectableToField<F>
578    for DensePolynomial<R, DEGREE_PLUS_ONE>
579where
580    R: Semiring,
581    F: PrimeField + for<'a> FromWithConfig<&'a R> + for<'a> MulByScalar<&'a F> + 'static,
582{
583    #![allow(clippy::arithmetic_side_effects)] // False alert, field operations are safe
584    fn prepare_projection(
585        sampled_value: &F,
586    ) -> impl Fn(&DensePolynomial<R, DEGREE_PLUS_ONE>) -> F + Send + Sync + 'static {
587        let sampled_value = sampled_value.clone();
588        let field_cfg = sampled_value.cfg().clone();
589
590        move |poly: &DensePolynomial<R, DEGREE_PLUS_ONE>| {
591            let coeffs: [F; DEGREE_PLUS_ONE] = poly
592                .coeffs
593                .iter()
594                .map(|v| v.into_with_cfg(&field_cfg))
595                .collect_array()
596                .expect("unreachable");
597
598            let poly2 = DensePolynomial { coeffs };
599            poly2
600                .evaluate_at_point(&sampled_value)
601                .expect("Failed to evaluate polynomial at point")
602        }
603    }
604}
605
606impl<R, const DEGREE_PLUS_ONE: usize> DensePolynomial<R, DEGREE_PLUS_ONE> {
607    #[inline(always)]
608    pub fn iter(&self) -> std::slice::Iter<'_, R> {
609        self.coeffs.iter()
610    }
611
612    #[inline(always)]
613    pub fn iter_mut(&mut self) -> std::slice::IterMut<'_, R> {
614        self.coeffs.iter_mut()
615    }
616}
617
618impl<R, const DEGREE_PLUS_ONE: usize> IntoIterator for DensePolynomial<R, DEGREE_PLUS_ONE> {
619    type Item = R;
620
621    type IntoIter = std::array::IntoIter<R, DEGREE_PLUS_ONE>;
622
623    #[inline(always)]
624    fn into_iter(self) -> Self::IntoIter {
625        self.coeffs.into_iter()
626    }
627}
628
629impl<'a, R, const DEGREE_PLUS_ONE: usize> IntoIterator for &'a DensePolynomial<R, DEGREE_PLUS_ONE> {
630    type Item = &'a R;
631
632    type IntoIter = slice::Iter<'a, R>;
633
634    fn into_iter(self) -> Self::IntoIter {
635        self.coeffs.iter()
636    }
637}
638
639impl<R, const DEGREE_PLUS_ONE: usize> AsRef<[R]> for DensePolynomial<R, DEGREE_PLUS_ONE> {
640    fn as_ref(&self) -> &[R] {
641        self.coeffs.as_slice()
642    }
643}
644
645impl<R, const DEGREE_PLUS_ONE: usize> Deref for DensePolynomial<R, DEGREE_PLUS_ONE> {
646    type Target = [R];
647
648    fn deref(&self) -> &Self::Target {
649        self.coeffs.as_slice()
650    }
651}
652
653impl<R, const DEGREE_PLUS_ONE: usize> DerefMut for DensePolynomial<R, DEGREE_PLUS_ONE> {
654    fn deref_mut(&mut self) -> &mut Self::Target {
655        &mut self.coeffs
656    }
657}
658
659#[derive(Clone, Debug)]
660pub struct DensePolyInnerProduct<
661    R,
662    Rhs,
663    Out,
664    I: InnerProduct<[R], Rhs, Out>,
665    const DEGREE_PLUS_ONE: usize,
666>(PhantomData<(I, R, Rhs, Out)>);
667
668impl<R, Rhs, Out, I, const DEGREE_PLUS_ONE: usize>
669    InnerProduct<DensePolynomial<R, DEGREE_PLUS_ONE>, Rhs, Out>
670    for DensePolyInnerProduct<R, Rhs, Out, I, DEGREE_PLUS_ONE>
671where
672    I: InnerProduct<[R], Rhs, Out>,
673{
674    #[inline(always)]
675    fn inner_product<const CHECK: bool>(
676        lhs: &DensePolynomial<R, DEGREE_PLUS_ONE>,
677        rhs: &[Rhs],
678        zero: Out,
679    ) -> Result<Out, InnerProductError> {
680        I::inner_product::<CHECK>(&lhs.coeffs, rhs, zero)
681    }
682}