sparse_interp/
lib.rs

1#![warn(missing_docs)]
2#![warn(missing_crate_level_docs)]
3#![warn(macro_use_extern_crate)]
4#![warn(invalid_html_tags)]
5#![warn(missing_copy_implementations)]
6#![warn(missing_debug_implementations)]
7#![warn(unreachable_pub)]
8#![warn(unused_extern_crates)]
9#![warn(unused_lifetimes)]
10
11//! Basic polynomial arithmetic, multi-point evaluation, and sparse interpolation.
12//!
13//! This crate is **very limited** so far in its functionality and under **active development**.
14//! The current functionality isi mostly geared towards
15//! sparse interpolation with a known set of possible exponents.
16//! Expect frequent breaking changes as things get started.
17//!
18//! The [`Poly`] type is used to represent dense polynomials along with traits for
19//! algorithm choices. The [`ClassicalPoly`] type alias specifies classical arithmetic
20//! algorithms via the [`ClassicalTraits`] trait.
21//!
22//! ```
23//! use sparse_interp::ClassicalPoly;
24//!
25//! // f represents 4 + 3x^2 - x^3
26//! let f = ClassicalPoly::<f32>::new(vec![4., 0., 3., -1.]);
27//!
28//! // g prepresents 2x
29//! let g = ClassicalPoly::<f32>::new(vec![0., 2.]);
30//!
31//! // basic arithmetic is supported
32//! let h = f + g;
33//! assert_eq!(h, ClassicalPoly::new(vec![4., 2., 3., -1.]));
34//! ```
35//!
36//! # Evaluation
37//!
38//! Single-point and multi-point evaluation work as follows.
39//!
40//! ```
41//! # use sparse_interp::ClassicalPoly;
42//! type CP = ClassicalPoly<f32>;
43//! let h = CP::new(vec![4., 2., 3., -1.]);
44//! assert_eq!(h.eval(&0.), Ok(4.));
45//! assert_eq!(h.eval(&1.), Ok(8.));
46//! assert_eq!(h.eval(&-1.), Ok(6.));
47//! let eval_info = CP::mp_eval_prep([0., 1., -1.].iter().copied());
48//! assert_eq!(h.mp_eval(&eval_info).unwrap(), [4.,8.,6.]);
49//! ```
50//!
51//! # Sparse interpolation
52//!
53//! Sparse interpolation should work over any type supporting
54//! *field operations* of addition, subtration, multiplication,
55//! and division.
56//!
57//! For a polynomial *f* with at most *t* terms, sparse interpolation requires
58//! eactly 2*t* evaluations at consecutive powers of some value θ, starting
59//! with θ<sup>0</sup> = 1.
60//!
61//! This value θ must have sufficiently high order in the underlying field;
62//! that is, all powers of θ up to the degree of the polynomial must be distinct.
63//!
64//! Calling [`Poly::sparse_interp()`] returns on success a vector of (exponent, coefficient)
65//! pairs, sorted by exponent, corresponding to the nonzero terms of the
66//! evaluated polynomial.
67//!
68//! ```
69//! # use sparse_interp::{ClassicalPoly, RelativeParams};
70//! type CP = ClassicalPoly<f64>;
71//! let f = CP::new(vec![0., -2.5, 0., 0., 0., 7.1]);
72//! let t = 2;
73//! let (eval_info, interp_info) = ClassicalPoly::sparse_interp_prep(
74//!     t,          // upper bound on nonzero terms
75//!     0..8,       // iteration over possible exponents
76//!     &f64::MAX,  // upper bound on coefficient magnitude
77//! );
78//! let evals = f.mp_eval(&eval_info).unwrap();
79//! let mut result = CP::sparse_interp(&evals, &interp_info).unwrap();
80//!
81//! // round the coefficients to nearest 0.1
82//! for (_,c) in result.iter_mut() {
83//!     *c = (*c * 10.).round() / 10.;
84//! }
85//!
86//! assert_eq!(result, [(1, -2.5), (5, 7.1)]);
87//! ```
88
89use core::{
90    ops::{
91        Add,
92        Mul,
93        AddAssign,
94        SubAssign,
95        MulAssign,
96    },
97    borrow::{
98        Borrow,
99        BorrowMut,
100    },
101    iter::{
102        self,
103        FromIterator,
104        IntoIterator,
105        ExactSizeIterator,
106        Extend,
107    },
108    marker::{
109        PhantomData,
110    },
111    convert::{
112        self,
113    },
114};
115use num_traits::{
116    Zero,
117    One,
118    Inv,
119};
120use num_complex::{
121    Complex,
122    Complex32,
123    Complex64,
124};
125use custom_error::custom_error;
126
127custom_error!{
128    /// Errors that arise in polynomial arithmetic or sparse interpolation.
129    #[derive(PartialEq)]
130    #[allow(missing_docs)]
131    pub Error
132        CoeffConv{cause: String}
133            = "Could not convert coefficient: {cause}",
134        Singular = "Encountered singular matrix when expecting nonsingular; perhaps sparsity was set too low",
135        SparsityTooLow = "Sparsity bound set too low in sparse interpolation",
136        MissingExponents = "The exponent of a non-zero term was missing from the list",
137}
138
139/// A specialized [core::result::Result] type for sparse interpolation.
140pub type Result<T> = core::result::Result<T, Error>;
141
142/// A trait for 1-way conversions between numeric types that may fail.
143///
144/// Provides basically the same functionality as [`std::convert::TryFrom`]
145/// from `std`, but a new trait was needed in order to implement it for
146/// conversions such as `f64` to `u32`, or
147/// [`num_complex::Complex32`] to `f32`.
148///
149/// See also the [conv crate](https://crates.io/crates/conv), which was
150/// also considered but cannot be used here because it is not compatible
151/// with [`num_complex::Complex32`].
152pub trait OneWay {
153    /// The type being converted from.
154    type Source;
155    /// The type being converted to.
156    type Dest;
157    /// Conversion from Source to Dest that may fail.
158    fn one_way(src: Self::Source) -> Result<Self::Dest>;
159}
160
161/// A trait for 2-way conversions that may fail.
162///
163/// Of course, for any `x: Source`, it should be the case that
164/// `other_way(one_way(x)?)? == x` when possible, but this is not
165/// required.
166pub trait TwoWay: OneWay {
167    /// Conversion from Dest to Source that may fail.
168    fn other_way(src: <Self as OneWay>::Dest) -> Result<<Self as OneWay>::Source>;
169}
170
171/// The default conversion from S to D, if it exists.
172#[derive(Debug)]
173pub struct DefConv<S,D>(PhantomData<(S,D)>);
174
175impl<S,D> TwoWay for DefConv<S,D>
176where Self: OneWay<Source=S, Dest=D>,
177      DefConv<D,S>: OneWay<Source=D, Dest=S>,
178{
179    fn other_way(src: D) -> Result<S> {
180        <DefConv<D,S> as OneWay>::one_way(src)
181    }
182}
183
184impl<S> OneWay for DefConv<S,S>
185{
186    type Source = S;
187    type Dest = S;
188
189    #[inline(always)]
190    fn one_way(src: S) -> Result<S> {
191        Ok(src)
192    }
193}
194
195macro_rules! one_way_as {
196    ($s:ty, $($ds:ty),+) => {
197        $(
198            impl OneWay for DefConv<$s,$ds> {
199                type Source = $s;
200                type Dest = $ds;
201                fn one_way(src: $s) -> Result<$ds> {
202                    Ok(src as $ds)
203                }
204            }
205        )+
206    };
207}
208
209macro_rules! one_way_as_check {
210    ($s:ty, $($ds:ty),+) => {
211        $(
212            impl OneWay for DefConv<$s,$ds> {
213                type Source = $s;
214                type Dest = $ds;
215                fn one_way(src: $s) -> Result<$ds> {
216                    let dest = src as $ds;
217                    if (dest as $s) == src {
218                        Ok(dest)
219                    } else {
220                        Err(Error::CoeffConv{cause: format!("{} not representable as {}", src, stringify!($ds))})
221                    }
222                }
223            }
224        )+
225    }
226}
227
228macro_rules! one_way_round {
229    ($s:ty, $($ds:ty),+) => {
230        $(
231            impl OneWay for DefConv<$s,$ds> {
232                type Source = $s;
233                type Dest = $ds;
234                fn one_way(src: $s) -> Result<$ds> {
235                    let rounded = src.round();
236                    let dest = rounded as $ds;
237                    if (dest as $s) == rounded {
238                        Ok(dest)
239                    } else {
240                        Err(Error::CoeffConv{cause: format!("{} not representable as {}", src, stringify!($ds))})
241                    }
242                }
243            }
244        )+
245    }
246}
247
248macro_rules! one_way_try {
249    ($s:ty, $($ds:ty),+) => {
250        $(
251            impl OneWay for DefConv<$s,$ds> {
252                type Source = $s;
253                type Dest = $ds;
254                fn one_way(src: $s) -> Result<$ds> {
255                    convert::TryInto::<$ds>::try_into(src).map_err(|e| Error::CoeffConv{cause: e.to_string()})
256                }
257            }
258        )+
259    }
260}
261
262//one_way_as!(i8, i8);
263one_way_try!(i8, u8);
264one_way_as!(i8, i16, u16, i32, u32, i64, u64, i128, u128, f32, f64);
265
266one_way_try!(u8, i8);
267one_way_as!(u8, i16, u16, i32, u32, i64, u64, i128, u128, f32, f64);
268
269one_way_try!(i16, i8, u8, u16);
270one_way_as!(i16, i32, u32, i64, u64, i128, u128, f32, f64);
271
272one_way_try!(u16, i8, u8, i16);
273one_way_as!(u16, i32, u32, i64, u64, i128, u128, f32, f64);
274
275one_way_try!(i32, i8, u8, i16, u16, u32);
276one_way_as!(i32, i64, u64, i128, u128, f64);
277one_way_as_check!(i32, f32);
278
279one_way_try!(u32, i8, u8, i16, u16, i32);
280one_way_as!(u32, i64, u64, i128, u128, f64);
281one_way_as_check!(u32, f32);
282
283one_way_try!(i64, i8, u8, i16, u16, i32, u32, u64);
284one_way_as!(i64, i128, u128);
285one_way_as_check!(i64, f32, f64);
286
287one_way_try!(u64, i8, u8, i16, u16, i32, u32, i64);
288one_way_as!(u64, i128, u128);
289one_way_as_check!(u64, f32, f64);
290
291one_way_try!(i128, i8, u8, i16, u16, i32, u32, i64, u64, u128);
292one_way_as_check!(i128, f32, f64);
293
294one_way_try!(u128, i8, u8, i16, u16, i32, u32, i64, u64, i128);
295one_way_as_check!(u128, f32, f64);
296
297one_way_round!(f32, i8, u8, i16, u16, i32, u32, i64, u64, i128, u128);
298one_way_as!(f32, f64);
299
300one_way_round!(f64, i8, u8, i16, u16, i32, u32, i64, u64, i128, u128);
301
302impl OneWay for DefConv<f64, f32> {
303    type Source = f64;
304    type Dest = f32;
305
306    fn one_way(src: f64) -> Result<f32> {
307        let dest = src as f32;
308        if dest.log2().round() == (src.log2().round() as f32) {
309            Ok(dest)
310        } else {
311            Err(Error::CoeffConv{cause: format!("f64->f32 exponent overflow on {}", src)})
312        }
313    }
314}
315
316macro_rules! two_way_complex {
317    ($t:ty, $($us:ty),+) => {
318        $(
319            impl OneWay for DefConv<$us, Complex<$t>> {
320                type Source = $us;
321                type Dest = Complex<$t>;
322
323                #[inline(always)]
324                fn one_way(src: Self::Source) -> Result<Self::Dest> {
325                    Ok(Complex::from(DefConv::<$us,$t>::one_way(src)?))
326                }
327            }
328
329            impl OneWay for DefConv<Complex<$t>, $us> {
330                type Source = Complex<$t>;
331                type Dest = $us;
332
333                #[inline(always)]
334                fn one_way(src: Self::Source) -> Result<Self::Dest> {
335                    // TODO maybe return Err if imaginary part is too large?
336                    DefConv::<$t,$us>::one_way(src.re)
337                }
338            }
339        )+
340    };
341}
342
343two_way_complex!(f32, i8, u8, i16, u16, i32, u32, i64, u64, i128, u128, f32, f64);
344two_way_complex!(f64, i8, u8, i16, u16, i32, u32, i64, u64, i128, u128, f32, f64);
345
346/// A possibly-stateful comparison for exact or approximate types.
347///
348/// Implementors of this trait can be used to compare `Item`s for
349/// "closeness". The idea is that closeness should encompass absolute
350/// equality as well as approximate equality.
351///
352/// For exact types, use the [CloseToEq] struct to just fall back to direct
353/// comparison. For inexact types, use the [RelativeParams] struct to specify
354/// the acceptable (relative) error.
355pub trait CloseTo {
356    /// The type of thing that can be compared.
357    type Item;
358
359    /// Returns `true` iff `x` is approximatey equal to `y`.
360    fn close_to(&self, x: &Self::Item, y: &Self::Item) -> bool;
361
362    /// Indicates `true` if `x` is approximately zero.
363    fn close_to_zero(&self, x: &Self::Item) -> bool;
364
365    /// Checks closeness over an iteration.
366    fn close_to_iter<'a, Iter1, Iter2>(&'a self, x: Iter1, y: Iter2) -> bool
367    where Iter1: Iterator<Item=&'a Self::Item>,
368          Iter2: Iterator<Item=&'a Self::Item>,
369    {
370        x.zip(y).all(|(xi, yi)| self.close_to(xi, yi))
371    }
372}
373
374/// A struct to use for exact equality in the [`CloseTo`] trait.
375///
376/// ```
377/// # use sparse_interp::*;
378/// let test = CloseToEq::new();
379/// assert!(test.close_to(&15, &15));
380/// assert!(! test.close_to(&15, &16));
381/// assert!(test.close_to_zero(&0));
382/// ```
383#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
384pub struct CloseToEq<T>{
385    /// The zero element (additive identity) for type `T`.
386    pub zero: T,
387}
388
389impl<T: Zero> CloseToEq<T> {
390    /// Creates a new struct for exact equality, using [`num_traits::Zero::zero`] to get the zero element.
391    pub fn new() -> Self {
392        Self {
393            zero: T::zero(),
394        }
395    }
396}
397
398impl<T: PartialEq> CloseTo for CloseToEq<T> {
399    type Item = T;
400
401    #[inline(always)]
402    fn close_to(&self, x: &Self::Item, y: &Self::Item) -> bool {
403        x.eq(y)
404    }
405
406    #[inline(always)]
407    fn close_to_zero(&self, x: &Self::Item) -> bool {
408        x.eq(&self.zero)
409    }
410}
411
412/// A struct to use for approximate equality.
413///
414/// ```
415/// # use sparse_interp::*;
416/// let test = RelativeParams::<f32>::new(Some(0.05), Some(0.001));
417/// assert!(test.close_to(&1.0, &1.001));
418/// assert!(test.close_to(&1001., &1000.));
419/// assert!(test.close_to_zero(&-0.05));
420/// assert!(! test.close_to(&0.1, &0.11));
421/// assert!(! test.close_to_zero(&0.06));
422/// ```
423#[derive(Debug, Clone, Copy, PartialEq, Eq)]
424pub struct RelativeParams<T, E=T>
425{
426    /// Below this threshold in absolute value, values are considered close to zero.
427    pub zero_thresh: E,
428
429    /// Values not close to zero are considered close to each other if their relative
430    /// error is at most this large.
431    pub max_relative: E,
432
433    phantom: PhantomData<T>,
434}
435
436macro_rules! impl_relative_params {
437    ($t:ident, $e:ident, $norm:ident) => {
438        impl RelativeParams<$t,$e> {
439            /// Create a new closeness tester with the given parameters.
440            ///
441            /// For both arguments, `zero_thresh` and `max_relative`,
442            /// either the given bound is used, or machine epsilon if the argument
443            /// is `None`.
444            #[inline(always)]
445            pub fn new(zero_thresh: Option<$e>, max_relative: Option<$e>) -> Self {
446                Self {
447                    zero_thresh: zero_thresh.unwrap_or($e::EPSILON),
448                    max_relative: max_relative.unwrap_or($e::EPSILON),
449                    phantom: PhantomData,
450                }
451            }
452        }
453
454        impl Default for RelativeParams<$t,$e> {
455            /// Create a closeness tester with machine epsilon precision.
456            #[inline(always)]
457            fn default() -> Self {
458                Self::new(None, None)
459            }
460        }
461
462        impl CloseTo for RelativeParams<$t,$e> {
463            type Item = $t;
464
465            #[inline]
466            fn close_to(&self, x: &Self::Item, y: &Self::Item) -> bool {
467                if x == y {
468                    return true
469                };
470                if $t::is_infinite(*x) || $t::is_infinite(*y) {
471                    return false
472                };
473
474                let absx = $t::$norm(*x);
475                let absy = $t::$norm(*y);
476
477                let largest = if absx <= absy {
478                    absy
479                } else {
480                    absx
481                };
482
483                if largest <= self.zero_thresh {
484                    true
485                } else {
486                    $t::$norm(x - y) / largest <= self.max_relative
487                }
488            }
489
490            #[inline(always)]
491            fn close_to_zero(&self, x: &Self::Item) -> bool {
492                $t::$norm(*x) <= self.zero_thresh
493            }
494        }
495    };
496}
497
498impl_relative_params!(f32, f32, abs);
499impl_relative_params!(f64, f64, abs);
500impl_relative_params!(Complex32, f32, norm);
501impl_relative_params!(Complex64, f64, norm);
502
503/// Algorithms to enable polynomial arithmetic.
504///
505/// Generally, `PolyTraits` methods should not be used directly, but only
506/// within the various method impls for [`Poly`].
507///
508/// This is implemented as a separate, possibly stateless traits object
509/// in order to allow selecting different underlying algorithms separately
510/// from the overall representation.
511///
512/// The methods here generally work on slice references so as to be
513/// representation-agnostic.
514///
515/// So far the only implementation is [`ClassicalTraits`].
516pub trait PolyTraits {
517    /// The type of polynomial coefficients.
518    type Coeff;
519
520    /// The evaluation needed for sparse interpolation.
521    type SparseInterpEval: EvalTypes<Coeff=Self::Coeff>;
522
523    /// An opaque type returned by the pre-processing method [`Self::sparse_interp_prep()`].
524    type SparseInterpInfo;
525
526    /// Multiplies two polynomails (represented by slices) and stores the result in another slice.
527    ///
528    /// Implementations may assume that all slices are non-empty, and that
529    /// `out.len() == lhs.len() + rhs.len() - 1`.
530    ///
531    /// ```
532    /// # use sparse_interp::*;
533    /// # type TraitImpl = ClassicalTraits<f32>;
534    /// let a = [1., 2., 3.];
535    /// let b = [4., 5.];
536    /// let mut c = [0.; 4];
537    /// TraitImpl::slice_mul(&mut c[..], &a[..], &b[..]);
538    /// assert_eq!(c, [1.*4., 1.*5. + 2.*4., 2.*5. + 3.*4., 3.*5.]);
539    /// ```
540    fn slice_mul(out: &mut [Self::Coeff], lhs: &[Self::Coeff], rhs: &[Self::Coeff]);
541
542    /// Pre-processing for multi-point evaluation.
543    ///
544    /// This method must be called to specify the evaluation points prior to
545    /// calling [`Self::mp_eval_slice()`].
546    ///
547    /// The same pre-processed output can be used repeatedly to
548    /// evaluate possibly different polynomials at the same points.
549    ///
550    /// The default implementation should be used; it relies on the [`EvalTypes::prep()`]
551    /// trait method specialized for the coefficient and evaluation types.
552    #[inline(always)]
553    fn mp_eval_prep<U>(pts: impl Iterator<Item=U>) -> <EvalTrait<Self,U> as EvalTypes>::EvalInfo
554    where EvalTrait<Self,U>: EvalTypes<Coeff=Self::Coeff, Eval=U>
555    {
556        <EvalTrait<Self,U> as EvalTypes>::prep(pts)
557    }
558
559
560    /// Multi-point evaluation.
561    ///
562    /// Evaluates the polynomial (given by a slice of coefficients) at all points
563    /// specified in a previous call to [`Self::mp_eval_prep()`].
564    ///
565    /// ```
566    /// # use sparse_interp::*;
567    /// # type TraitImpl = ClassicalTraits<f32>;
568    /// let pts = [10., -5.];
569    /// let preprocess = TraitImpl::mp_eval_prep(pts.iter().copied());
570    ///
571    /// let f = [1., 2., 3.];
572    /// let mut evals = Vec::new();
573    /// TraitImpl::mp_eval_slice(&mut evals, &f[..], &preprocess);
574    /// assert_eq!(evals, vec![321., 66.]);
575    ///
576    /// let g = [4., 5., 6., 7.];
577    /// TraitImpl::mp_eval_slice(&mut evals, &g[..], &preprocess);
578    /// assert_eq!(evals, vec![321., 66., 7654., 4. - 5.*5. + 6.*25. - 7.*125.]);
579    /// ```
580    ///
581    /// The provided implementation should generally be used; it relies on the
582    /// [`EvalTypes::post()`] trait method specialized for the coefficient and
583    /// evaluation types.
584    #[inline(always)]
585    fn mp_eval_slice<U>(out: &mut impl Extend<U>,
586                        coeffs: &[Self::Coeff],
587                        info: &<EvalTrait<Self,U> as EvalTypes>::EvalInfo) -> Result<()>
588    where EvalTrait<Self,U>: EvalTypes<Coeff=Self::Coeff, Eval=U>
589    {
590        <EvalTrait<Self,U> as EvalTypes>::post(out, coeffs, info)
591    }
592
593    /// Pre-processing for sparse interpolation.
594    ///
595    /// This method must be called prior to
596    /// calling [`Self::sparse_interp_slice()`].
597    ///
598    /// A later call to sparse interpolation is guaranteed to succeed only when, for some
599    /// unknown polynomial `f`, the following are all true:
600    /// *   `f` has at most `sparsity` non-zero terms
601    /// *   The exponents of all non-zero terms of `f` appear in `expons`
602    /// *   The coefficients of `f` are bounded by `max_coeff` in magnitude.
603    ///
604    /// The list `expons` must be sorted in ascending order.
605    ///
606    /// The same pre-processed output can be used repeatedly to
607    /// interpolate possibly different polynomials under the same settings.
608    fn sparse_interp_prep(sparsity: usize, expons: impl Iterator<Item=usize>, max_coeff: &Self::Coeff)
609        -> (<Self::SparseInterpEval as EvalTypes>::EvalInfo, Self::SparseInterpInfo)
610    ;
611
612    /// Sparse interpolation following evaluation.
613    ///
614    /// The evaluations in `eval` should correspond to what was specified by
615    /// [`Self::sparse_interp_prep()`].
616    ///
617    /// If those requirements are met, the function will return Some(..) containing
618    /// a list of exponent-coefficient pairs, sorted in ascending order of exponents.
619    ///
620    /// Otherwise, for example if the evaluated function has more non-zero terms
621    /// than the pre-specified limit, this function *may* return None or may return
622    /// Some(..) with incorrect values.
623    fn sparse_interp_slice(evals: &[<Self::SparseInterpEval as EvalTypes>::Eval],
624                           info: &Self::SparseInterpInfo)
625        -> Result<Vec<(usize, Self::Coeff)>>;
626}
627
628/// A trait struct used for multi-point evaluation of polynomials.
629///
630/// Typically, `T` will be a type which implements `PolyTraits` and
631/// `U` will be the type of evaluation point. If the combination of `T`
632/// and `U` is meaningful, then `EvalTrait<T,U>` should implement
633/// `EvalTypes`; this indicates that polynomials under trait `T`
634/// can be evaluated at points of type `U`.
635///
636/// The purpose of this is to allow a polynomial with coefficients of
637/// one type (say, integers) to be evaluated at a point with another type
638/// (say, complex numbers, or integers modulo a prime).
639///
640/// ```
641/// # use sparse_interp::*;
642/// type Eval = EvalTrait<ClassicalTraits<i32>, f32>;
643/// let coeffs = [1, 0, -2];
644/// let pts = [0.5, -1.5];
645/// let info = Eval::prep(pts.iter().copied());
646/// let mut result = Vec::new();
647/// Eval::post(&mut result, &coeffs, &info);
648/// assert_eq!(result, vec![0.5, -3.5]);
649/// ```
650///
651/// This is essentially a work-around for a problem better solved by
652/// [GATs](https://github.com/rust-lang/rust/issues/44265).
653/// (At the time of this writing, GAT is merged in nightly rust but not
654/// stable.)
655#[derive(Debug)]
656pub struct EvalTrait<T: ?Sized, U>(PhantomData<T>,PhantomData<U>);
657
658/// Trait for evaluating polynomials over (possibly) a different domain.
659///
660/// Evaluation is divided into pre-processing [`EvalTypes::prep`] stage, which depends only on the
661/// evaluation points, and the actual evaluation phase [`EvalTypes::post`].
662///
663/// Typically the provided blanket implementations for [`EvalTrait`] should be sufficient,
664/// unless you care creating a new polynomial type.
665pub trait EvalTypes {
666    /// Coefficient type of the polynomial being evaluated.
667    type Coeff;
668    /// Type of the evaluation point(s) and the output(s) of the polynomial evaluation.
669    type Eval;
670    /// Opaque type to hold pre-processing results.
671    type EvalInfo;
672
673    /// Pre-processing for multi-point evaluation.
674    ///
675    /// Takes a list of evaluation points and prepares an `EvalInfo` opaque
676    /// object which can be re-used to evaluate multiple polynomials over
677    /// the same evaluation points.
678    fn prep(pts: impl Iterator<Item=Self::Eval>) -> Self::EvalInfo;
679
680    /// Multi-point evaluation after pre-processing.
681    fn post(out: &mut impl Extend<Self::Eval>, coeffs: &[Self::Coeff], info: &Self::EvalInfo) -> Result<()>;
682}
683
684impl<C,U> EvalTypes for EvalTrait<ClassicalTraits<C>, U>
685where C: Clone,
686      U: Clone + Zero + MulAssign + AddAssign,
687      DefConv<C,U>: OneWay<Source=C, Dest=U>,
688{
689    type Coeff = C;
690    type Eval = U;
691    type EvalInfo = Vec<U>;
692
693    #[inline(always)]
694    fn prep(pts: impl Iterator<Item=Self::Eval>) -> Self::EvalInfo {
695        pts.collect()
696    }
697
698    fn post(out: &mut impl Extend<Self::Eval>, coeffs: &[Self::Coeff], info: &Self::EvalInfo) -> Result<()> {
699        //out.extend(coeffs.iter().zip(info.iter()).map(|(c,x)| { let mut out = x.clone(); out *= c; out }));
700		ErrorIter::new(info.iter().map(|x| horner_eval(coeffs.iter(), x)))
701            .try_use(|evals| out.extend(evals))
702        //out.extend(info.iter().map(|x| horner_eval(coeffs.iter(), x)));
703    }
704}
705
706/// PolyTraits implementation for classical (slow) algorithms.
707///
708/// The underlying algorithms are neither fast nor numerically stable.
709/// They should be used only for very small sizes, or for debugging.
710///
711/// *   [`ClassicalTraits::slice_mul()`] uses a classical quadratic-time algorithm
712/// *   [`ClassicalTraits::mp_eval_slice()`] simply evaluates each point one at a time, using
713///     Horner's rule. O(num_points * poly_degree) time.
714/// *   [`ClassicalTraits::sparse_interp_slice()`] uses unstructured linear algebra and classical
715///     root finding, with complexity O(sparsity^3).
716#[derive(Debug,Default,Clone,Copy,PartialEq,Eq)]
717pub struct ClassicalTraits<C>(PhantomData<C>);
718
719impl<C> PolyTraits for ClassicalTraits<C>
720where C: Clone + Mul<Output=C> + AddAssign,
721      DefConv<C, Complex64>: TwoWay<Source=C, Dest=Complex64>,
722{
723    type Coeff = C;
724    type SparseInterpEval = EvalTrait<Self, Complex64>;
725    type SparseInterpInfo = (usize, Vec<(usize, Complex64)>, RelativeParams<Complex64, f64>);
726
727    #[inline(always)]
728    fn slice_mul(out: &mut [Self::Coeff], lhs: &[Self::Coeff], rhs: &[Self::Coeff]) {
729        classical_slice_mul(out, lhs, rhs);
730    }
731
732    fn sparse_interp_prep(sparsity: usize, expons: impl Iterator<Item=usize>, _max_coeff: &Self::Coeff)
733        -> (<Self::SparseInterpEval as EvalTypes>::EvalInfo, Self::SparseInterpInfo)
734    {
735        let mut theta_pows: Vec<_> = expons.map(|d| (d, Complex64::default())).collect();
736        let theta = match theta_pows.iter().map(|pair| pair.0).max() {
737            Some(max_pow) => Complex64::from_polar(1., 2.*core::f64::consts::PI / (max_pow as f64 + 1.)),
738            None => Complex64::default(),
739        };
740        for (ref expon, ref mut power) in theta_pows.iter_mut() {
741            *power = theta.powu(*expon as u32);
742        }
743        //TODO work out precise bounds to use for RelativeParams here
744        (EvalTrait::<Self, Complex64>::prep((0..2*sparsity).map(|e| theta.powu(e as u32))),
745         (sparsity, theta_pows, RelativeParams::<Complex64,f64>::new(Some(1e-8), Some(1e-8)))
746        )
747    }
748
749    fn sparse_interp_slice(
750        evals: &[Complex64],
751        info: &Self::SparseInterpInfo,
752        ) -> Result<Vec<(usize, Self::Coeff)>>
753    {
754        let (sparsity, pows, close) = info;
755        assert_eq!(evals.len(), 2*sparsity);
756        let mut lambda = bad_berlekamp_massey(evals, close)?;
757        lambda.push(Complex64::from(-1.));
758        let (degs, roots): (Vec<usize>, Vec<Complex64>) = pows.iter().filter_map(
759            |(deg, rootpow)| {
760            // TODO I have no idea why this helper function is needed instead of the line below.
761            //horner_eval(lambda.iter(), rootpow).ok().and_then(
762            classical_sparse_interp_helper(&lambda, rootpow).ok().and_then(
763                |eval| match close.close_to_zero(&eval) {
764                    true => Some((deg, rootpow)),
765                    false => None,
766                }
767            )}
768        ).unzip();
769        if degs.len() != lambda.len() - 1 {
770            Err(Error::MissingExponents)
771        } else {
772            let evslice = &evals[..degs.len()];
773            ErrorIter::new(
774                bad_trans_vand_solve(&roots, evslice, close)?.into_iter()
775                    .map(|c| DefConv::<C,Complex64>::other_way(c))
776            ).try_use(|it| degs.into_iter().zip(it).collect())
777        }
778    }
779}
780
781// TODO helper function because for some reason I could not get this
782// to compile otherwise.
783fn classical_sparse_interp_helper(x: &Vec<Complex64>, y: &Complex64) -> Result<Complex64> {
784    horner_eval(x.iter(), y)
785}
786
787/// Generic struct to hold a polynomial and traits for operations.
788///
789/// The idea here is to combine some representation of the polynomial
790/// (say, a vector of coefficients) with an implementation of [`PolyTraits`],
791/// to allow implementing all the standard arithmetic and other user-facing
792/// polynomial operations.
793///
794/// ```
795/// # use sparse_interp::*;
796/// let f = ClassicalPoly::<f64>::new(vec![1., 2., 3.]);
797/// let g = ClassicalPoly::<f64>::new(vec![4., 5.]);
798///
799/// assert_eq!(&f * &g, ClassicalPoly::new(vec![4., 13., 22., 15.]));
800/// assert_eq!(&f + &g, ClassicalPoly::new(vec![5., 7., 3.]));
801/// ```
802///
803/// Type aliases are provided for various combinations that will work well.
804/// So far the only alias is [`ClassicalPoly`].
805#[derive(Debug)]
806#[repr(transparent)]
807pub struct Poly<T,U> {
808    rep: T,
809    traits: PhantomData<U>,
810}
811
812/// Univeriate polynomial representation using classical arithmetic algorithms.
813///
814/// Objects of this type implement many standard numeric operations like +, -,
815/// usually on *references* to the type.
816///
817/// Multi-point evaluation and sparse interpolation routines are also supported.
818pub type ClassicalPoly<C> = Poly<Vec<C>, ClassicalTraits<C>>;
819
820impl<T,U,V,W> PartialEq<Poly<V,W>> for Poly<T,U>
821where U: PolyTraits,
822      W: PolyTraits,
823      T: Borrow<[U::Coeff]>,
824      V: Borrow<[W::Coeff]>,
825      U::Coeff: PartialEq<W::Coeff>,
826{
827    fn eq(&self, other: &Poly<V,W>) -> bool {
828        self.rep.borrow() == other.rep.borrow()
829    }
830}
831
832impl<T,U> Eq for Poly<T,U>
833where U: PolyTraits,
834      T: Borrow<[U::Coeff]>,
835      U::Coeff: Eq,
836{ }
837
838impl<U> Poly<Vec<U::Coeff>,U>
839where U: PolyTraits,
840      U::Coeff: Zero,
841{
842    /// Creates a new `Poly` from a vector of coefficients.
843    pub fn new(rep: Vec<U::Coeff>) -> Self {
844        let mut out = Self {
845            rep,
846            traits: PhantomData,
847        };
848        out.normalize();
849        out
850    }
851
852    /// Ensures nonzero leading coefficient (or empty).
853    fn normalize(&mut self) {
854        while self.rep.last().map_or(false, Zero::is_zero) {
855            self.rep.pop();
856        }
857    }
858}
859
860impl<T,U> Poly<T,U>
861where U: PolyTraits,
862      T: Borrow<[U::Coeff]>,
863      U::Coeff: Zero,
864{
865    /// Creates a new `Poly` from the underlying representation which has nonzero
866    /// leading coefficient.
867    ///
868    /// # Panics
869    /// Panics if `rep` if not empty and has a leading coefficient which is zero.
870    pub fn new_norm(rep: T) -> Self {
871        assert!(rep.borrow().last().map_or(true, |x| !x.is_zero()));
872        Self {
873            rep,
874            traits: PhantomData,
875        }
876    }
877}
878
879impl<T,U> Default for Poly<T,U>
880where T: Default,
881{
882    #[inline(always)]
883    fn default() -> Self {
884        Self {
885            rep: T::default(),
886            traits: PhantomData,
887        }
888    }
889}
890
891impl<T,U> FromIterator<U::Coeff> for Poly<T,U>
892where U: PolyTraits,
893      T: FromIterator<U::Coeff> + Borrow<[U::Coeff]>,
894      U::Coeff: Zero,
895{
896    fn from_iter<V>(iter: V) -> Self
897    where V: IntoIterator<Item=U::Coeff>,
898    {
899        struct Trimmed<I: Iterator>(I, Option<(usize, I::Item)>);
900        impl<I: Iterator> Iterator for Trimmed<I>
901        where I::Item: Zero,
902        {
903            type Item = I::Item;
904            fn next(&mut self) -> Option<Self::Item> {
905                match self.1.take() {
906                    Some((count, nzcoeff)) => Some(
907                        if count == 0 {
908                            nzcoeff
909                        } else {
910                            self.1 = Some((count - 1, nzcoeff));
911                            Zero::zero()
912                        }
913                    ),
914                    None => self.0.next().and_then(|coeff| {
915                        if coeff.is_zero() {
916                            let mut count = 1;
917                            while let Some(coeff) = self.0.next() {
918                                if ! coeff.is_zero() {
919                                    self.1 = Some((count-1, coeff));
920                                    return Some(Zero::zero());
921                                }
922                                count += 1;
923                            }
924                            None
925                        } else {
926                            Some(coeff)
927                        }
928                    }),
929                }
930            }
931        }
932        Self::new_norm(Trimmed(iter.into_iter(), None).collect())
933    }
934}
935
936impl<T,U> Poly<T,U>
937where U: PolyTraits,
938      T: Borrow<[U::Coeff]>,
939      U::Coeff: Clone + Zero + AddAssign + MulAssign,
940{
941    /// Evaluate this polynomial at the given point.
942    ///
943    /// Uses Horner's rule to perform the evaluation using exactly d multiplications
944    /// and d additions, where d is the degree of self.
945    #[inline(always)]
946    pub fn eval<V>(&self, x: &V) -> Result<V>
947    where DefConv<U::Coeff, V>: OneWay<Source=U::Coeff, Dest=V>,
948          V: Clone + Zero + AddAssign + MulAssign,
949    {
950        horner_eval(self.rep.borrow().iter(), x)
951    }
952
953    /// Perform pre-processing for multi-point evaluation.
954    ///
955    /// `pts` is an iterator over the desired evaluation points.
956    ///
957    /// See [`PolyTraits::mp_eval_prep()`] for more details.
958    #[inline(always)]
959    pub fn mp_eval_prep<V>(pts: impl Iterator<Item=V>) -> <EvalTrait<U,V> as EvalTypes>::EvalInfo
960    where EvalTrait<U, V>: EvalTypes<Coeff=U::Coeff, Eval=V>,
961    {
962        U::mp_eval_prep(pts)
963    }
964
965    /// Evaluate this polynomial at all of the given points.
966    ///
967    /// Performs multi-point evaluation using the underlying trait algorithms.
968    /// In general, this can be much more efficient than repeatedly calling
969    /// [`self.eval()`].
970    ///
971    /// `info` should be the result of calling [`Self::mp_eval_prep()`].
972    #[inline]
973    pub fn mp_eval<V>(&self, info: &<EvalTrait<U,V> as EvalTypes>::EvalInfo) -> Result<Vec<V>>
974    where EvalTrait<U, V>: EvalTypes<Coeff=U::Coeff, Eval=V>,
975    {
976        let mut out = Vec::new();
977        U::mp_eval_slice(&mut out, self.rep.borrow(), info)?;
978        Ok(out)
979    }
980}
981
982impl<T,U> Poly<T,U>
983where U: PolyTraits,
984{
985    /// Perform pre-processing for sparse interpolation.
986    ///
987    /// *   `sparsity` is an upper bound on the number of nonzero terms in the evaluated
988    ///     polynomial.
989    /// *   `expons` is an iteration over the possible exponents which may appear in nonzero
990    ///     terms.
991    /// *   `max_coeff` is an upper bound on the magnitude of any coefficient.
992    ///
993    /// See [`PolyTraits::sparse_interp_prep()`] for more details.
994    #[inline(always)]
995    pub fn sparse_interp_prep(sparsity: usize, expons: impl Iterator<Item=usize>, max_coeff: &U::Coeff)
996        -> (<U::SparseInterpEval as EvalTypes>::EvalInfo, U::SparseInterpInfo)
997    {
998        U::sparse_interp_prep(sparsity, expons, max_coeff)
999    }
1000
1001    /// Perform sparse interpolation after evaluation.
1002    ///
1003    /// Beforehand, [`Self::sparse_interp_prep()`] must be called to generate two info
1004    /// structs for evaluation and interpolation. These can be used repeatedly to
1005    /// evaluate and interpolate many polynomials with the same sparsity and degree
1006    /// bounds.
1007    ///
1008    /// *   `evals` should correspond evaluations according to the `EvalInfo` struct
1009    ///     returned from preprocessing.
1010    ///     at consecutive powers of the `theta` used in preprocessing.
1011    /// *   `info` should come from a previous call to [`Self::sparse_interp_prep()`].
1012    ///
1013    /// On success, a vector of (exponent, nonzero coefficient) pairs is returned,
1014    /// sorted by increasing exponent values.
1015    #[inline(always)]
1016    pub fn sparse_interp(evals: &[<U::SparseInterpEval as EvalTypes>::Eval], info: &U::SparseInterpInfo)
1017        -> Result<Vec<(usize, U::Coeff)>>
1018    {
1019        U::sparse_interp_slice(evals, info)
1020    }
1021}
1022
1023#[must_use]
1024struct LongZip<A,B,F,G,H>(A,B,F,G,H);
1025
1026impl<A,B,F,G,H,O> Iterator for LongZip<A,B,F,G,H>
1027where A: Iterator,
1028      B: Iterator,
1029      F: FnMut(A::Item, B::Item) -> O,
1030      G: FnMut(A::Item) -> O,
1031      H: FnMut(B::Item) -> O,
1032{
1033    type Item = O;
1034
1035    fn next(&mut self) -> Option<Self::Item> {
1036        match self.0.next() {
1037            Some(x) => Some(match self.1.next() {
1038                Some(y) => self.2(x,y),
1039                None => self.3(x),
1040            }),
1041            None => self.1.next().map(|y| self.4(y)),
1042        }
1043    }
1044}
1045
1046impl<'a,'b,T,U,V,W> Add<&'b Poly<V,W>> for &'a Poly<T,U>
1047where U: PolyTraits,
1048      W: PolyTraits,
1049      &'a T: IntoIterator<Item=&'a U::Coeff>,
1050      &'b V: IntoIterator<Item=&'b W::Coeff>,
1051      &'a U::Coeff: Add<&'b W::Coeff, Output=U::Coeff>,
1052      U::Coeff: AddAssign<&'b W::Coeff>,
1053      U::Coeff: Clone + Zero
1054{
1055    type Output = Poly<Vec<U::Coeff>, U>;
1056
1057    fn add(self, rhs: &'b Poly<V,W>) -> Self::Output {
1058        Poly::from_iter(LongZip(
1059            self.rep.into_iter(),
1060            rhs.rep.into_iter(),
1061            Add::add,
1062            Clone::clone,
1063            |x| {
1064                let mut sum = U::Coeff::zero();
1065                sum += x;
1066                sum
1067            },
1068        ))
1069    }
1070}
1071
1072impl<T,U,V,W> Add<Poly<V,W>> for Poly<T,U>
1073where U: PolyTraits,
1074      W: PolyTraits,
1075      T: IntoIterator<Item=U::Coeff>,
1076      V: IntoIterator<Item=W::Coeff>,
1077      U::Coeff: Zero + From<W::Coeff> + Add<W::Coeff, Output=U::Coeff>,
1078{
1079    type Output = Poly<Vec<U::Coeff>, U>;
1080
1081    fn add(self, rhs: Poly<V,W>) -> Self::Output {
1082        Poly::from_iter(LongZip(
1083            self.rep.into_iter(),
1084            rhs.rep.into_iter(),
1085            Add::add,
1086            convert::identity,
1087            From::from,
1088        ))
1089    }
1090}
1091
1092impl<'a,'b,T,U,V> Mul<&'b Poly<V,U>> for &'a Poly<T,U>
1093where U: PolyTraits,
1094      T: Borrow<[U::Coeff]>,
1095      V: Borrow<[U::Coeff]>,
1096      U::Coeff: Zero,
1097{
1098    type Output = Poly<Box<[U::Coeff]>, U>;
1099
1100    fn mul(self, rhs: &'b Poly<V,U>) -> Self::Output {
1101        let aslice = self.rep.borrow();
1102        let bslice = rhs.rep.borrow();
1103        if aslice.is_empty() || bslice.is_empty() {
1104            return Poly::new_norm(Box::new([]));
1105        }
1106
1107        let clen = aslice.len() + bslice.len() - 1;
1108        let mut outbox = {
1109            let mut vec = Vec::with_capacity(clen);
1110            vec.resize_with(clen, U::Coeff::zero);
1111            vec.into_boxed_slice()
1112        };
1113
1114        U::slice_mul(outbox.borrow_mut(), aslice, bslice);
1115
1116        Poly::new_norm(outbox)
1117    }
1118}
1119
1120fn dot_product<'a,'b,T,U>(lhs: impl Iterator<Item=&'a T>, rhs: impl Iterator<Item=&'b U>) -> T
1121where T: 'a + Clone + Mul<Output=T> + AddAssign,
1122      U: 'b + Clone + Into<T>,
1123{
1124    let mut zipit = lhs.cloned().zip(rhs.cloned());
1125    let (a,b) = zipit.next().expect("dot product must be with non-empty iterators");
1126    let mut out = a * b.into();
1127    for (a,b) in zipit {
1128        out += a * b.into();
1129    }
1130    out
1131}
1132
1133fn classical_slice_mul<T,U>(output: &mut [T], lhs: &[T], rhs: &[U])
1134where T: Clone + Mul<Output=T> + AddAssign,
1135      U: Clone + Into<T>,
1136{
1137    if lhs.len() == 0 || rhs.len() == 0 {
1138        assert_eq!(output.len(), 0);
1139        return;
1140    }
1141
1142    assert_eq!(lhs.len() + rhs.len(), output.len() + 1);
1143
1144    let mut i = 0;
1145
1146    while i < lhs.len() && i < rhs.len() {
1147        output[i] = dot_product(lhs[..i+1].iter(), rhs[..i+1].iter().rev());
1148        i = i + 1;
1149    }
1150
1151    let mut j = 1;
1152    while i < lhs.len() {
1153        output[i] = dot_product(lhs[j..i+1].iter(), rhs.iter().rev());
1154        i = i + 1;
1155        j = j + 1;
1156    }
1157
1158    let mut k = 1;
1159    while i < rhs.len() {
1160        output[i] = dot_product(lhs.iter(), rhs[k..i+1].iter().rev());
1161        i = i + 1;
1162        k = k + 1;
1163    }
1164
1165    while i < output.len() {
1166        output[i] = dot_product(lhs[j..].iter(), rhs[k..].iter().rev());
1167        i = i + 1;
1168        j = j + 1;
1169        k = k + 1;
1170    }
1171}
1172
1173fn horner_eval<'a,'b,T,U,I>(mut coeffs: I, x: &'b U)
1174    -> Result<U>
1175where T: 'a + Clone,
1176      U: Clone + Zero + MulAssign + AddAssign,
1177      I: DoubleEndedIterator<Item=&'a T>,
1178      DefConv<T,U>: OneWay<Source=T, Dest=U>,
1179{
1180    if let Some(leading) = coeffs.next_back() {
1181        let mut out = DefConv::<T,U>::one_way(leading.clone())?;
1182        for coeff in coeffs.rev() {
1183            out *= x.clone();
1184            out += DefConv::<T,U>::one_way(coeff.clone())?;
1185        }
1186        Ok(out)
1187    } else {
1188        Ok(U::zero())
1189    }
1190}
1191
1192/// Computes base^exp, where the base is a reference and not an owned value.
1193///
1194/// The number of clones is kept to a minimum. This is useful when objects of type T
1195/// are large and copying them is expensive.
1196///
1197/// ```
1198/// # use sparse_interp::refpow;
1199/// let x = 10u128;
1200/// assert_eq!(refpow(&x, 11), 100000000000u128)
1201/// ```
1202///
1203/// see also: <https://docs.rs/num-traits/0.2.14/src/num_traits/pow.rs.html#189-211>
1204#[inline]
1205pub fn refpow<T>(base: &T, exp: usize) -> T
1206where T: Clone + One + Mul<Output=T> + MulAssign,
1207{
1208    match exp {
1209        0 => T::one(),
1210        1 => base.clone(),
1211        _ => {
1212            let mut acc = base.clone() * base.clone();
1213            let mut curexp = exp >> 1;
1214
1215            // invariant: curexp > 0 and base^exp = acc^curexp * base^(exp mod 2)
1216            while curexp & 1 == 0 {
1217                acc *= acc.clone();
1218                curexp >>= 1;
1219            }
1220            // now: curexp positive odd, base^exp = acc^curexp * base^(exp mod 2)
1221
1222            if curexp > 1 {
1223                let mut basepow = acc.clone() * acc.clone();
1224                curexp >>= 1;
1225
1226                // invariant: curexp > 0 and base^exp = acc * basepow^curexp * base^(exp mod 2)
1227                while curexp > 1 {
1228                    if curexp & 1 == 1 {
1229                        acc *= basepow.clone();
1230                    }
1231                    basepow *= basepow.clone();
1232                    curexp >>= 1;
1233                }
1234                // now: curexp == 1 and base^exp = acc * basepow * base^(exp mod 2)
1235
1236                acc *= basepow.clone();
1237            }
1238            // now: curexp == 1 and base^exp = acc * base^(exp mod 2)
1239
1240            if exp & 1 == 1 {
1241                acc *= base.clone();
1242            }
1243            acc
1244        }
1245    }
1246}
1247
1248
1249// --- BAD LINEAR SOLVER, TODO REPLACE WITH BETTER "SUPERFAST" SOLVERS ---
1250
1251fn bad_linear_solve<'a,'b,M,T>(
1252    matrix: M,
1253    rhs: impl IntoIterator<Item=&'b T>,
1254    close: &impl CloseTo<Item=T>,
1255    ) -> Result<Vec<T>>
1256where M: IntoIterator,
1257      M::Item: IntoIterator<Item=&'a T>,
1258      T: 'a + 'b + Clone + One + Mul<Output=T> + SubAssign + MulAssign + Inv<Output=T>,
1259{
1260    let mut workmat: Vec<Vec<_>> =
1261        matrix .into_iter()
1262            .map(|row| row.into_iter().map(Clone::clone).collect())
1263            .collect();
1264    let mut sol: Vec<_> = rhs.into_iter().map(Clone::clone).collect();
1265
1266    let n = workmat.len();
1267    assert!(workmat.iter().all(|row| row.len() == n));
1268    assert_eq!(sol.len(), n);
1269
1270    for i in 0..n {
1271        { // find pivot
1272            let mut j = i;
1273            while close.close_to_zero(&workmat[j][i]) {
1274                j += 1;
1275                if j == n {
1276                    return Err(Error::Singular);
1277                }
1278            }
1279            if i != j {
1280                workmat.swap(i, j);
1281                sol.swap(i, j);
1282            }
1283        }
1284        // normalize pivot row
1285        {
1286            let pivot_inverse = workmat[i][i].clone().inv();
1287            for x in workmat[i].split_at_mut(i+1).1 {
1288                *x *= pivot_inverse.clone();
1289            }
1290            sol[i] *= pivot_inverse;
1291            workmat[i][i].set_one();
1292        }
1293        // cancel
1294        {
1295            let (top, midbot) = workmat.split_at_mut(i);
1296            let (pivrow, bottom) = midbot.split_first_mut().expect("row index i must exist");
1297            let (soltop, solmidbot) = sol.split_at_mut(i);
1298            let (solpiv, solbot) = solmidbot.split_first_mut().expect("row index imust exist");
1299            for (row, solx) in top.iter_mut().chain(bottom.iter_mut())
1300                               .zip(soltop.iter_mut().chain(solbot.iter_mut()))
1301            {
1302                if !close.close_to_zero(&row[i]) {
1303                    let (left, right) = row.split_at_mut(i+1);
1304                    for (j, x) in (i+1..n).zip(right) {
1305                        *x -= left[i].clone() * pivrow[j].clone();
1306                    }
1307                    *solx -= left[i].clone() * solpiv.clone();
1308                }
1309            }
1310        }
1311    }
1312    Ok(sol)
1313}
1314
1315fn bad_berlekamp_massey<T>(seq: &[T], close: &impl CloseTo<Item=T>) -> Result<Vec<T>>
1316where T: Clone + One + Mul<Output=T> + SubAssign + MulAssign + Inv<Output=T>,
1317{
1318    assert_eq!(seq.len() % 2, 0);
1319    let n = seq.len() / 2;
1320    for k in (1..=n).rev() {
1321        if let Ok(res) = bad_linear_solve(
1322            (0..k).map(|i| &seq[i..i+k]),
1323            &seq[k..2*k],
1324            close)
1325        {
1326            return Ok(res);
1327        }
1328    }
1329    Err(Error::SparsityTooLow)
1330}
1331
1332fn bad_trans_vand_solve<'a,'b,T,U>(
1333    roots: U,
1334    rhs: impl IntoIterator<Item=&'b T>,
1335    close: &impl CloseTo<Item=T>)
1336    -> Result<Vec<T>>
1337where T: 'a + 'b + Clone + One + Mul<Output=T> + SubAssign + MulAssign + Inv<Output=T>,
1338      U: Copy + IntoIterator<Item=&'a T>,
1339      U::IntoIter: ExactSizeIterator,
1340{
1341    let n = roots.into_iter().len();
1342    let mat: Vec<_> = iter::successors(
1343        Some(iter::repeat_with(One::one).take(n).collect::<Vec<T>>()),
1344        |row| Some(row.iter().cloned().zip(roots.into_iter().cloned()).map(|(x,y)| x * y).collect())
1345    ).take(n).collect();
1346    bad_linear_solve(&mat, rhs, close)
1347}
1348
1349struct ErrorIter<I,E> {
1350    iter: I,
1351    err: Option<E>,
1352}
1353
1354impl<'a,I,E,T> Iterator for &'a mut ErrorIter<I,E>
1355where
1356    I: 'a + Iterator<Item=core::result::Result<T,E>>,
1357    T: 'a,
1358    E: 'a,
1359{
1360    type Item = T;
1361
1362    fn next(&mut self) -> Option<Self::Item> {
1363        match self.err {
1364            Some(_) => None,
1365            None => {
1366                match self.iter.next() {
1367                    Some(Ok(x)) => Some(x),
1368                    Some(Err(e)) => {
1369                        self.err = Some(e);
1370                        None
1371                    }
1372                    None => None,
1373                }
1374            }
1375        }
1376    }
1377}
1378
1379impl<I,E> ErrorIter<I,E> {
1380    fn new(iter: I) -> Self {
1381        Self {
1382            iter,
1383            err: None,
1384        }
1385    }
1386
1387    fn try_use<F,T>(mut self, f: F) -> core::result::Result<T,E>
1388    where F: FnOnce(&mut Self) -> T
1389    {
1390        let x = f(&mut self);
1391        match self.err {
1392            Some(e) => Err(e),
1393            None => Ok(x),
1394        }
1395    }
1396}
1397
1398#[cfg(test)]
1399mod tests {
1400    use super::*;
1401
1402    #[test]
1403    fn bad_linear_algebra() {
1404        let very_close = RelativeParams::<f64>::default();
1405        {
1406            let mat :Vec<Vec<f64>> = vec![
1407                vec![2., 2., 2.],
1408                vec![-3., -3., -1.],
1409                vec![5., 3., -3.],
1410            ];
1411            let rhs = vec![12., -12., 10.];
1412            assert!(very_close.close_to_iter(
1413                bad_linear_solve(&mat, &rhs, &very_close).unwrap().iter(),
1414                [5., -2., 3.].iter()));
1415        }
1416
1417        {
1418            let mat :Vec<Vec<f64>> = vec![
1419                vec![2., 8., 10., 52.],
1420                vec![1., 4., 5., 24.],
1421                vec![-2., -6., -4., -40.],
1422                vec![3., 11., 12., 77.],
1423            ];
1424            let rhs = vec![1., 2., 3., 4.];
1425            assert_eq!(bad_linear_solve(&mat, &rhs, &very_close), Err(Error::Singular));
1426        }
1427
1428        {
1429            let seq = vec![1., 0., 5., -2., 12., -1.];
1430            assert!(very_close.close_to_iter(
1431                bad_berlekamp_massey(&seq, &very_close).unwrap().iter(),
1432                [3., 2., -1.].iter()));
1433        }
1434
1435        {
1436            let roots = vec![2., -1., 3.];
1437            let rhs = vec![8.5, 29., 70.];
1438            assert!(very_close.close_to_iter(
1439                bad_trans_vand_solve(&roots, &rhs, &very_close).unwrap().iter(),
1440                [4.5,-2.,6.].iter()));
1441        }
1442    }
1443
1444    #[test]
1445    fn add() {
1446        let a = vec![10, 20, 30, 40];
1447        let b = vec![3, 4, 5];
1448        let c = vec![13, 24, 35, 40];
1449
1450        let ap: ClassicalPoly<_> = a.iter().copied().collect();
1451        let bp: ClassicalPoly<_> = b.iter().copied().collect();
1452        let cp: ClassicalPoly<_> = c.iter().copied().collect();
1453
1454        assert_eq!(ap + bp, cp);
1455    }
1456
1457    #[test]
1458    fn mul() {
1459        let a = vec![1, 2, 3, 4, 5];
1460        let b = vec![300, 4, 50000];
1461        let c = vec![300, 604, 50908, 101212, 151516, 200020, 250000];
1462
1463        let ap: ClassicalPoly<_> = a.iter().copied().collect();
1464        let bp: ClassicalPoly<_> = b.iter().copied().collect();
1465        let cp: ClassicalPoly<_> = c.iter().copied().collect();
1466
1467        assert_eq!(&ap * &bp, cp);
1468        assert_eq!(&bp * &ap, cp);
1469    }
1470
1471    #[test]
1472    fn eval() {
1473        type CP = ClassicalPoly<i16>;
1474        let f = CP::new(vec![-5,3,-1,2]);
1475
1476        assert_eq!(f.eval(&-3.0f32),
1477            Ok((-5 + 3*-3 + -1*-3*-3 + 2*-3*-3*-3) as f32));
1478        {
1479            let pts = vec![-2,0,7];
1480            let prep = CP::mp_eval_prep(pts.iter().copied());
1481            assert!(f.mp_eval(&prep).unwrap().into_iter().eq(
1482                pts.iter().map(|x| f.eval(x).unwrap())));
1483        }
1484    }
1485
1486    #[test]
1487    fn pow() {
1488        assert_eq!(refpow(&3u64, 0), 1);
1489        assert_eq!(refpow(&25u64, 1), 25);
1490        assert_eq!(refpow(&4u64, 2), 16);
1491        assert_eq!(refpow(&-5i32, 3), -125);
1492        assert_eq!(refpow(&2u16, 8), 256);
1493        let mut pow3 = 1u64;
1494        for d in 1..41 {
1495            pow3 *= 3u64;
1496            assert_eq!(refpow(&3u64, d), pow3);
1497        }
1498    }
1499
1500    #[test]
1501    fn classical_sparse_interp_exact() {
1502        type CP = ClassicalPoly<i32>;
1503        let f = CP::new(vec![3, 0, -2, 0, 0, 0, -1]);
1504        let t = 3;
1505        let (eval_info, interp_info) = CP::sparse_interp_prep(t, 0..10, &100);
1506        let evals = f.mp_eval(&eval_info).unwrap();
1507        let expected_sparse: Vec<_> = f.rep.iter().enumerate().filter(|(_,c)| **c != 0).map(|(e,c)| (e,*c)).collect();
1508        let sparse_f = CP::sparse_interp(&evals, &interp_info).unwrap();
1509        assert_eq!(expected_sparse, sparse_f);
1510    }
1511
1512    #[test]
1513    fn classical_sparse_interp_overshoot() {
1514        type CP = ClassicalPoly<i32>;
1515        let f = CP::new(vec![3, 0, -2, 0, 0, 0, -1]);
1516        let t = 5;
1517        let (eval_info, interp_info) = CP::sparse_interp_prep(t, 0..10, &100);
1518        let evals = f.mp_eval(&eval_info).unwrap();
1519        let expected_sparse: Vec<_> = f.rep.iter().enumerate().filter(|(_,c)| **c != 0).map(|(e,c)| (e,*c)).collect();
1520        let sparse_f = CP::sparse_interp(&evals, &interp_info).unwrap();
1521        assert_eq!(expected_sparse, sparse_f);
1522    }
1523
1524    #[test]
1525    fn classical_spinterp_big() {
1526        type CP = ClassicalPoly<f64>;
1527        let mut coeffs = vec![0.0f64; 200];
1528        let expected_sparse: Vec<(usize, f64)> = vec![
1529            (3, 1.9),
1530            (4, -3.),
1531            (31, 18.),
1532            (101, 19.4),
1533            (108, 0.5),
1534            (109, 0.6),
1535            (110, -1.),
1536            (151, -12.6),
1537            (199, 2.5),
1538        ];
1539        for (e, c) in expected_sparse.iter() {
1540            coeffs[*e] = *c;
1541        }
1542        let f = CP::new(coeffs.clone());
1543        let (eval_info, interp_info) = CP::sparse_interp_prep(15, 0..200, &20000.);
1544        let evals = f.mp_eval(&eval_info).unwrap();
1545        let (computed_expons, computed_coeffs): (Vec<_>, Vec<_>)
1546            = CP::sparse_interp(&evals, &interp_info).unwrap().into_iter().unzip();
1547        let (expected_expons, expected_coeffs): (Vec<_>, Vec<_>)
1548            = expected_sparse.into_iter().unzip();
1549        assert_eq!(expected_expons, computed_expons);
1550        let close = RelativeParams::<f64>::new(Some(0.001), Some(0.001));
1551        assert!(close.close_to_iter(expected_coeffs.iter(), computed_coeffs.iter()));
1552    }
1553}