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
11use 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 #[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
139pub type Result<T> = core::result::Result<T, Error>;
141
142pub trait OneWay {
153 type Source;
155 type Dest;
157 fn one_way(src: Self::Source) -> Result<Self::Dest>;
159}
160
161pub trait TwoWay: OneWay {
167 fn other_way(src: <Self as OneWay>::Dest) -> Result<<Self as OneWay>::Source>;
169}
170
171#[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
262one_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 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
346pub trait CloseTo {
356 type Item;
358
359 fn close_to(&self, x: &Self::Item, y: &Self::Item) -> bool;
361
362 fn close_to_zero(&self, x: &Self::Item) -> bool;
364
365 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#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
384pub struct CloseToEq<T>{
385 pub zero: T,
387}
388
389impl<T: Zero> CloseToEq<T> {
390 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#[derive(Debug, Clone, Copy, PartialEq, Eq)]
424pub struct RelativeParams<T, E=T>
425{
426 pub zero_thresh: E,
428
429 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 #[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 #[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
503pub trait PolyTraits {
517 type Coeff;
519
520 type SparseInterpEval: EvalTypes<Coeff=Self::Coeff>;
522
523 type SparseInterpInfo;
525
526 fn slice_mul(out: &mut [Self::Coeff], lhs: &[Self::Coeff], rhs: &[Self::Coeff]);
541
542 #[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 #[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 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 fn sparse_interp_slice(evals: &[<Self::SparseInterpEval as EvalTypes>::Eval],
624 info: &Self::SparseInterpInfo)
625 -> Result<Vec<(usize, Self::Coeff)>>;
626}
627
628#[derive(Debug)]
656pub struct EvalTrait<T: ?Sized, U>(PhantomData<T>,PhantomData<U>);
657
658pub trait EvalTypes {
666 type Coeff;
668 type Eval;
670 type EvalInfo;
672
673 fn prep(pts: impl Iterator<Item=Self::Eval>) -> Self::EvalInfo;
679
680 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 ErrorIter::new(info.iter().map(|x| horner_eval(coeffs.iter(), x)))
701 .try_use(|evals| out.extend(evals))
702 }
704}
705
706#[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 (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 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
781fn classical_sparse_interp_helper(x: &Vec<Complex64>, y: &Complex64) -> Result<Complex64> {
784 horner_eval(x.iter(), y)
785}
786
787#[derive(Debug)]
806#[repr(transparent)]
807pub struct Poly<T,U> {
808 rep: T,
809 traits: PhantomData<U>,
810}
811
812pub 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 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 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 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 #[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 #[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 #[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 #[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 #[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#[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 while curexp & 1 == 0 {
1217 acc *= acc.clone();
1218 curexp >>= 1;
1219 }
1220 if curexp > 1 {
1223 let mut basepow = acc.clone() * acc.clone();
1224 curexp >>= 1;
1225
1226 while curexp > 1 {
1228 if curexp & 1 == 1 {
1229 acc *= basepow.clone();
1230 }
1231 basepow *= basepow.clone();
1232 curexp >>= 1;
1233 }
1234 acc *= basepow.clone();
1237 }
1238 if exp & 1 == 1 {
1241 acc *= base.clone();
1242 }
1243 acc
1244 }
1245 }
1246}
1247
1248
1249fn 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 { 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 {
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 {
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}