fit.rs

3.3 kB · rust · 138 lines

1const P: u128 = (1 << 61) - 1;23fn power(mut a: u128, mut e: u128) -> u128 {4    let mut r = 1;5    a %= P;6    while e > 0 {7        if e & 1 == 1 {8            r = r * a % P;9        }10        a = a * a % P;11        e >>= 1;12    }13    r14}1516fn massey(s: &[u128]) -> Vec<u128> {17    let (mut c, mut b) = (vec![1u128], vec![1u128]);18    let (mut l, mut m, mut last) = (0usize, 1usize, 1u128);19    for n in 0..s.len() {20        let mut d = s[n] % P;21        for i in 1..=l.min(c.len() - 1) {22            d = (d + c[i] * (s[n - i] % P)) % P;23        }24        if d == 0 {25            m += 1;26            continue;27        }28        let t = c.clone();29        let coef = d * power(last, P - 2) % P;30        if c.len() < b.len() + m {31            c.resize(b.len() + m, 0);32        }33        for i in 0..b.len() {34            c[i + m] = (c[i + m] + P - coef * b[i] % P) % P;35        }36        if 2 * l <= n {37            l = n + 1 - l;38            b = t;39            last = d;40            m = 1;41        } else {42            m += 1;43        }44    }45    c.resize(l + 1, 0);46    c47}4849pub struct Fit {50    pub poly: Vec<i128>,51    pub margin: i64,52}5354pub fn fit(s: &[u128]) -> Option<Fit> {55    let c = massey(s);56    let poly: Vec<i128> = c57        .iter()58        .map(|&x| {59            if x > P / 2 {60                x as i128 - P as i12861            } else {62                x as i12863            }64        })65        .collect();66    let l = poly.len() - 1;67    for n in l..s.len() {68        let mut acc = 0i128;69        for (i, &k) in poly.iter().enumerate() {70            acc = acc.checked_add(k.checked_mul(s[n - i] as i128)?)?;71        }72        if acc != 0 {73            return None;74        }75    }76    Some(Fit {77        poly,78        margin: s.len() as i64 - 2 * l as i64,79    })80}8182fn eval(poly: &[i128], r: i128) -> Option<i128> {83    poly.iter()84        .try_fold(0i128, |acc, &k| acc.checked_mul(r)?.checked_add(k))85}8687pub fn roots(poly: &[i128]) -> (Vec<i128>, Vec<i128>) {88    let mut rest = poly.to_vec();89    let mut found = Vec::new();90    for r in (0..=64i128).flat_map(|r| if r == 0 { vec![0] } else { vec![r, -r] }) {91        while rest.len() > 1 && eval(&rest, r) == Some(0) {92            let mut q = Vec::with_capacity(rest.len() - 1);93            let mut acc = 0i128;94            for &k in &rest[..rest.len() - 1] {95                acc = acc * r + k;96                q.push(acc);97            }98            rest = q;99            found.push(r);100        }101    }102    found.sort_by(|a, b| b.cmp(a));103    (found, rest)104}105106pub fn show(poly: &[i128]) -> String {107    let d = poly.len() - 1;108    let mut out = String::new();109    for (i, &k) in poly.iter().enumerate() {110        if k == 0 {111            continue;112        }113        let e = d - i;114        let sign = if k < 0 {115            " - "116        } else if out.is_empty() {117            ""118        } else {119            " + "120        };121        let a = k.abs();122        let lead = if out.is_empty() && k < 0 {123            "-".to_string()124        } else {125            sign.to_string()126        };127        let body = match (a, e) {128            (_, 0) => format!("{a}"),129            (1, 1) => "x".to_string(),130            (1, _) => format!("x^{e}"),131            (_, 1) => format!("{a} x"),132            _ => format!("{a} x^{e}"),133        };134        out.push_str(&lead);135        out.push_str(&body);136    }137    out138}