use crate::field::Field;
use crate::uni::Uni;
#[derive(Clone, Debug)]
pub struct Newton<F> {
xs: Vec<F>,
cs: Vec<F>,
}
impl<F> Default for Newton<F> {
fn default() -> Self {
Self {
xs: Vec::new(),
cs: Vec::new(),
}
}
}
impl<F: Field> Newton<F> {
pub fn add(&mut self, x: F, y: F) -> bool {
let (mut v, mut w) = (F::zero(), F::one());
for (xi, c) in self.xs.iter().zip(&self.cs) {
v = v + c.clone() * w.clone();
w = w * (x.clone() - xi.clone());
}
let c = (y - v) / w;
let fresh = !c.is_zero();
self.xs.push(x);
self.cs.push(c);
fresh
}
pub fn contains(&self, x: &F) -> bool {
self.xs.contains(x)
}
pub const fn len(&self) -> usize {
self.xs.len()
}
pub const fn is_empty(&self) -> bool {
self.xs.is_empty()
}
pub fn poly(&self) -> Uni<F> {
let mut r = Uni::zero();
for (xi, c) in self.xs.iter().zip(&self.cs).rev() {
r.mul_linear(xi);
match r.0.first_mut() {
Some(r0) => *r0 = r0.clone() + c.clone(),
None if !c.is_zero() => r.0.push(c.clone()),
None => {}
}
}
r
}
}
#[derive(Clone, Debug)]
pub struct Thiele<F> {
ts: Vec<F>,
cs: Vec<F>,
}
impl<F> Default for Thiele<F> {
fn default() -> Self {
Self {
ts: Vec::new(),
cs: Vec::new(),
}
}
}
impl<F: Field> Thiele<F> {
pub fn add(&mut self, t: F, y: F) -> bool {
let mut v = y;
for (ti, ci) in self.ts.iter().zip(&self.cs) {
let Some(d) = (v - ci.clone()).inverse() else {
return false;
};
v = (t.clone() - ti.clone()) * d;
}
self.ts.push(t);
self.cs.push(v);
true
}
pub fn contains(&self, t: &F) -> bool {
self.ts.contains(t)
}
pub const fn len(&self) -> usize {
self.ts.len()
}
pub const fn is_empty(&self) -> bool {
self.ts.is_empty()
}
pub fn eval(&self, t: &F) -> Option<F> {
let mut pairs = self.ts.iter().zip(&self.cs).rev();
let (_, last) = pairs.next()?;
pairs.try_fold(last.clone(), |v, (ti, ci)| {
Some(ci.clone() + (t.clone() - ti.clone()) * v.inverse()?)
})
}
pub fn rational(&self) -> (Uni<F>, Uni<F>) {
let mut pairs = self.ts.iter().zip(&self.cs).rev();
let Some((_, last)) = pairs.next() else {
return (Uni::zero(), Uni::constant(F::one()));
};
let (num, den) = pairs.fold(
(Uni::constant(last.clone()), Uni::constant(F::one())),
|(num, mut den), (ti, ci)| {
den.mul_linear(ti);
(&den + &num.scale(ci), num)
},
);
let g = num.gcd(&den);
let (num, den) = (&num / &g, &den / &g);
let l = den.lc().inverse().expect("nonzero denominator");
(num.scale(&l), den.scale(&l))
}
}
pub fn master<F: Field>(vals: &[F]) -> Uni<F> {
let mut m = Uni::constant(F::one());
for v in vals {
m.mul_linear(v);
}
m
}
pub fn solve<F: Field>(vals: &[F], master: &Uni<F>, w: &[F]) -> Vec<F> {
vals.iter()
.map(|v| {
let (q, _) = master.deflate(v);
let num =
q.0.iter()
.zip(w)
.fold(F::zero(), |acc, (a, b)| acc + a.clone() * b.clone());
num / (q.eval(v) * v.clone())
})
.collect()
}
#[derive(Clone, Debug)]
pub struct Massey<F> {
seq: Vec<F>,
c: Vec<F>,
b: Vec<F>,
l: usize,
shift: usize,
last: F,
zeros: usize,
}
impl<F: Field> Default for Massey<F> {
fn default() -> Self {
Self {
seq: Vec::new(),
c: vec![F::one()],
b: vec![F::one()],
l: 0,
shift: 1,
last: F::one(),
zeros: 0,
}
}
}
impl<F: Field> Massey<F> {
pub fn push(&mut self, a: F) {
self.seq.push(a);
let k = self.seq.len() - 1;
let d = self
.c
.iter()
.zip(self.seq.iter().rev())
.fold(F::zero(), |acc, (c, x)| acc + c.clone() * x.clone());
if d.is_zero() {
self.shift += 1;
self.zeros += 1;
return;
}
self.zeros = 0;
let r = d.clone() / self.last.clone();
let mut c = self.c.clone();
c.resize(c.len().max(self.b.len() + self.shift), F::zero());
for (i, x) in self.b.iter().enumerate() {
c[i + self.shift] = c[i + self.shift].clone() - r.clone() * x.clone();
}
if 2 * self.l <= k {
self.l = k + 1 - self.l;
self.b = std::mem::replace(&mut self.c, c);
self.last = d;
self.shift = 1;
} else {
self.c = c;
self.shift += 1;
}
}
pub const fn len(&self) -> usize {
self.seq.len()
}
pub const fn is_empty(&self) -> bool {
self.seq.is_empty()
}
pub const fn complexity(&self) -> usize {
self.l
}
pub const fn settled(&self, margin: usize) -> bool {
self.zeros >= margin && self.seq.len() >= 2 * self.l + margin
}
pub fn generator(&self) -> Uni<F> {
let mut c = self.c.clone();
c.resize(self.l + 1, F::zero());
c.reverse();
Uni::new(c)
}
}