signed.rs

22.6 kB · rust · 765 lines

1use crate::menergy::{bits_of, box_row, boxes, column, exps, qpow, random_column, Bits, Rng};23// SIEVES45pub fn spf_table(lim: usize) -> Vec<u32> {6    let mut spf = vec![0u32; lim + 1];7    let mut i = 2usize;8    while i <= lim {9        if spf[i] == 0 {10            let mut j = i;11            while j <= lim {12                if spf[j] == 0 {13                    spf[j] = i as u32;14                }15                j += i;16            }17        }18        i += 1;19    }20    spf21}2223pub fn mobius(lim: usize, spf: &[u32]) -> Vec<i8> {24    let mut mu = vec![0i8; lim + 1];25    if lim >= 1 {26        mu[1] = 1;27    }28    for n in 2..=lim {29        let p = spf[n] as usize;30        let m = n / p;31        mu[n] = if m % p == 0 { 0 } else { -mu[m] };32    }33    mu34}3536fn liouville(lim: usize, spf: &[u32]) -> Vec<i8> {37    let mut lam = vec![0i8; lim + 1];38    if lim >= 1 {39        lam[1] = 1;40    }41    for n in 2..=lim {42        lam[n] = -lam[n / spf[n] as usize];43    }44    lam45}4647fn sign_draw(lim: usize, seed: u64) -> Vec<i8> {48    let mut rng = Rng::new(seed);49    (0..=lim)50        .map(|_| if rng.sign() > 0.0 { 1i8 } else { -1i8 })51        .collect()52}5354pub fn coefficients(lim: usize) -> (Vec<&'static str>, Vec<Vec<i8>>) {55    let spf = spf_table(lim);56    let mu = mobius(lim, &spf);57    let names = vec![58        "1", "mu", "lambda", "rand1", "rand2", "rand3", "sfr1", "sfr2", "sfr3",59    ];60    let masked = |seed: u64| -> Vec<i8> {61        let d = sign_draw(lim, seed);62        (0..=lim).map(|n| d[n] * mu[n] * mu[n]).collect()63    };64    let vals = vec![65        vec![1i8; lim + 1],66        mu.clone(),67        liouville(lim, &spf),68        sign_draw(lim, 0x51_6e_ed_01),69        sign_draw(lim, 0x51_6e_ed_02),70        sign_draw(lim, 0x51_6e_ed_03),71        masked(0x5f_6e_ed_01),72        masked(0x5f_6e_ed_02),73        masked(0x5f_6e_ed_03),74    ];75    (names, vals)76}7778// THE ROW7980pub struct SignedRow {81    pub m: u64,82    pub n: u64,83    pub r: u128,84    pub e: u128,85    pub num: Vec<i128>,86    pub diag: Vec<f64>,87    pub rms: Option<f64>,88    pub csloss: Vec<f64>,89}9091pub fn signed_row(bits: &Bits, mm: u64, nn: u64, g: u128, x: u128, coefs: &[Vec<i8>]) -> SignedRow {92    let nb = coefs.len();93    let mut cprime = vec![0i64; nn as usize];94    let mut qq = vec![0i128; nb];95    let mut cc = vec![0i128; nb];96    let mut u = vec![0i64; nb];97    let mut r: u128 = 0;98    let mut e: u128 = 0;99    let dl = g as f64 / x as f64;100    let bsum: Vec<f64> = coefs101        .iter()102        .map(|b| (nn..2 * nn).map(|l| b[l as usize] as f64).sum())103        .collect();104    let mut l1 = vec![0.0f64; nb];105    let mut sq = vec![0.0f64; nb];106    for m in mm..2 * mm {107        u.iter_mut().for_each(|v| *v = 0);108        let mut c = 0i64;109        for l in nn..2 * nn {110            if bits.get((m * l) as usize) {111                c += 1;112                cprime[(l - nn) as usize] += 1;113                for (j, b) in coefs.iter().enumerate() {114                    u[j] += b[l as usize] as i64;115                }116            }117        }118        r += c as u128;119        e += (c as u128) * (c as u128);120        for j in 0..nb {121            qq[j] += (u[j] as i128) * (u[j] as i128);122            cc[j] += u[j] as i128;123            let v = u[j] as f64 - dl * bsum[j];124            l1[j] += v.abs();125            sq[j] += v * v;126        }127    }128    let csloss: Vec<f64> = (0..nb)129        .map(|j| {130            let bd = (mm as f64 * sq[j]).sqrt();131            if bd > 0.0 {132                l1[j] / bd133            } else {134                0.0135            }136        })137        .collect();138    let xi = x as i128;139    let gi = g as i128;140    let mi = mm as i128;141    let delta = g as f64 / x as f64;142    let mut num = Vec::with_capacity(nb);143    let mut diag = Vec::with_capacity(nb);144    for (j, b) in coefs.iter().enumerate() {145        let mut bs = 0i128;146        let mut s2 = 0i128;147        let mut pp = 0i128;148        for l in nn..2 * nn {149            let v = b[l as usize] as i128;150            bs += v;151            s2 += v * v;152            pp += v * v * cprime[(l - nn) as usize] as i128;153        }154        num.push(155            xi * xi * (qq[j] - pp) - 2 * gi * xi * (bs * cc[j] - pp)156                + mi * gi * gi * (bs * bs - s2),157        );158        diag.push(159            pp as f64 * (1.0 - delta) * (1.0 - delta) + (mi * s2 - pp) as f64 * delta * delta,160        );161    }162    SignedRow {163        m: mm,164        n: nn,165        r,166        e,167        num,168        diag,169        rms: None,170        csloss,171    }172}173174const RMSCAP: u64 = 2048;175176pub fn pair_rms(bits: &Bits, mm: u64, nn: u64, g: u128, x: u128) -> Option<f64> {177    if mm > RMSCAP {178        return None;179    }180    let ms = mm as usize;181    let mut tt = vec![0u32; ms * ms];182    let mut cm = vec![0u32; ms];183    let mut cprime = vec![0u32; nn as usize];184    let mut hits: Vec<u32> = Vec::with_capacity(ms);185    for l in nn..2 * nn {186        hits.clear();187        for m in mm..2 * mm {188            if bits.get((m * l) as usize) {189                hits.push((m - mm) as u32);190            }191        }192        cprime[(l - nn) as usize] = hits.len() as u32;193        for &a in hits.iter() {194            cm[a as usize] += 1;195            for &b in hits.iter() {196                tt[a as usize * ms + b as usize] += 1;197            }198        }199    }200    let delta = g as f64 / x as f64;201    let nf = nn as f64;202    let mut all = 0.0f64;203    for a in 0..ms {204        for b in 0..ms {205            let gg =206                tt[a * ms + b] as f64 - delta * (cm[a] as f64 + cm[b] as f64) + nf * delta * delta;207            all += gg * gg;208        }209    }210    let mut dg = 0.0f64;211    for &c in cprime.iter() {212        let w = c as f64 * (1.0 - delta) * (1.0 - delta) + (mm as f64 - c as f64) * delta * delta;213        dg += w * w;214    }215    Some((2.0 * (all - dg)).max(0.0).sqrt())216}217218pub fn engineered(219    bits: &Bits,220    mm: u64,221    nn: u64,222    g: u128,223    x: u128,224    rounds: usize,225) -> (f64, f64, usize) {226    let delta = g as f64 / x as f64;227    let ms = mm as usize;228    let ns = nn as usize;229    let mut b = vec![1.0f64; ns];230    let mut v = vec![0.0f64; ms];231    let mut cprime = vec![0u32; ns];232    for (i, m) in (mm..2 * mm).enumerate() {233        let mut acc = 0.0f64;234        for (j, l) in (nn..2 * nn).enumerate() {235            if bits.get((m * l) as usize) {236                acc += 1.0 - delta;237                cprime[j] += 1;238            } else {239                acc -= delta;240            }241        }242        v[i] = acc;243    }244    let w: Vec<f64> = cprime245        .iter()246        .map(|&c| c as f64 * (1.0 - delta) * (1.0 - delta) + (mm as f64 - c as f64) * delta * delta)247        .collect();248    let mut flips = 0usize;249    let mut grad = vec![0.0f64; ns];250    for _ in 0..rounds {251        grad.iter_mut().for_each(|z| *z = 0.0);252        for (i, m) in (mm..2 * mm).enumerate() {253            for (j, l) in (nn..2 * nn).enumerate() {254                let ps = if bits.get((m * l) as usize) {255                    1.0 - delta256                } else {257                    -delta258                };259                grad[j] += v[i] * ps;260            }261        }262        let mut best = 0usize;263        let mut gain = 0.0f64;264        for j in 0..ns {265            let d = -4.0 * b[j] * grad[j] + 4.0 * w[j];266            if d < gain {267                gain = d;268                best = j;269            }270        }271        if gain >= 0.0 {272            break;273        }274        let l = nn + best as u64;275        for (i, m) in (mm..2 * mm).enumerate() {276            let ps = if bits.get((m * l) as usize) {277                1.0 - delta278            } else {279                -delta280            };281            v[i] -= 2.0 * b[best] * ps;282        }283        b[best] = -b[best];284        flips += 1;285    }286    let form: f64 = v.iter().map(|z| z * z).sum();287    let dg: f64 = w.iter().sum();288    (form, dg, flips)289}290291fn round_div(num: i128, den: i128) -> i128 {292    if num >= 0 {293        (num + den / 2) / den294    } else {295        -((-num + den / 2) / den)296    }297}298299// THE SWEEP300301pub struct SignedSweep {302    pub top: SignedRow,303    pub l5: Option<SignedRow>,304    pub seen: usize,305    pub live: usize,306}307308pub fn sweep(bits: &Bits, x: u128, g: u128, coefs: &[Vec<i8>]) -> Option<SignedSweep> {309    let all = boxes(x);310    let edge = (x as f64).powf(0.4);311    let mut top: Option<SignedRow> = None;312    let mut l5: Option<SignedRow> = None;313    let mut live = 0usize;314    for &(mm, nn) in all.iter() {315        let row = signed_row(bits, mm, nn, g, x, coefs);316        if row.r == 0 {317            continue;318        }319        live += 1;320        let score = row.num[0].abs();321        if top.as_ref().map(|b| score > b.num[0].abs()).unwrap_or(true) {322            top = Some(signed_row(bits, mm, nn, g, x, coefs));323        }324        if mm as f64 >= edge325            && nn as f64 >= edge326            && l5.as_ref().map(|b| score > b.num[0].abs()).unwrap_or(true)327        {328            l5 = Some(row);329        }330    }331    top.map(|t| SignedSweep {332        top: t,333        l5,334        seen: all.len(),335        live,336    })337}338339// STUDY340341pub struct Cell {342    pub q: u64,343    pub digits: Vec<u64>,344    pub label: &'static str,345    pub depths: [usize; 2],346}347348fn ex(q: u64, e: u64) -> Vec<u64> {349    (0..q).filter(|&f| f != e).collect()350}351352pub fn cells() -> Vec<Cell> {353    vec![354        Cell {355            q: 3,356            digits: vec![0, 1],357            label: "01",358            depths: [12, 14],359        },360        Cell {361            q: 4,362            digits: vec![0, 1, 2],363            label: "012",364            depths: [8, 9],365        },366        Cell {367            q: 5,368            digits: vec![0, 1, 2, 3],369            label: "0123",370            depths: [7, 8],371        },372        Cell {373            q: 10,374            digits: ex(10, 7),375            label: "ex7",376            depths: [5, 6],377        },378    ]379}380381const PAIRCAP: usize = 8_000_000;382383pub struct Tally {384    pub cells: usize,385    pub rand: [usize; 3],386    pub sf: [usize; 3],387    pub mu_under_lam: usize,388    pub musq: (f64, f64),389    pub lamsq: (f64, f64),390    pub under_r: usize,391    pub one_over_r: usize,392    pub fd: (f64, f64),393    pub murms: (f64, f64),394    pub sfrms: (f64, f64),395    pub cs: (f64, f64),396}397398fn place(v: f64, lo: f64, hi: f64) -> usize {399    if v < lo {400        0401    } else if v > hi {402        2403    } else {404        1405    }406}407408fn emit(409    q: u64,410    label: &str,411    l: usize,412    x: u128,413    kind: &str,414    tag: &str,415    sw: &SignedSweep,416    row: &SignedRow,417    tally: &mut Tally,418) {419    let den = (x as i128) * (x as i128);420    let sig: Vec<i128> = row.num.iter().map(|&n| round_div(n, den)).collect();421    let val = |n: i128| (n as f64) / (den as f64);422    let base = row.num[0].abs() as f64;423    let ratio = |n: i128| {424        if base == 0.0 {425            0.0426        } else {427            (n.abs() as f64) / base428        }429    };430    let band = |a: usize, b: usize, c: usize| -> (f64, f64) {431        let v = [ratio(row.num[a]), ratio(row.num[b]), ratio(row.num[c])];432        (433            v.iter().cloned().fold(f64::INFINITY, f64::min),434            v.iter().cloned().fold(f64::NEG_INFINITY, f64::max),435        )436    };437    let (rlo, rhi) = band(3, 4, 5);438    let (slo, shi) = band(6, 7, 8);439    let mut fdlo = f64::INFINITY;440    let mut fdhi = f64::NEG_INFINITY;441    for j in 1..row.num.len() {442        let f = (val(row.num[j]) + row.diag[j]) / row.diag[j];443        fdlo = fdlo.min(f);444        fdhi = fdhi.max(f);445    }446    let (rtxt, mrms, lrms) = match row.rms {447        Some(v) if v > 0.0 => (448            format!("{:.4e}", v),449            format!("{:.4}", val(row.num[1]).abs() / v),450            format!("{:.4}", val(row.num[2]).abs() / v),451        ),452        _ => ("-".to_string(), "-".to_string(), "-".to_string()),453    };454    let root = val(row.num[0]).abs().sqrt();455    let sq = |n: i128| {456        if root == 0.0 {457            0.0458        } else {459            val(n).abs() / root460        }461    };462    let sqband = [sq(row.num[6]), sq(row.num[7]), sq(row.num[8])];463    let sqlo = sqband.iter().cloned().fold(f64::INFINITY, f64::min);464    let sqhi = sqband.iter().cloned().fold(f64::NEG_INFINITY, f64::max);465    if kind == "digit" {466        tally.cells += 1;467        tally.rand[place(ratio(row.num[1]), rlo, rhi)] += 1;468        tally.sf[place(ratio(row.num[1]), slo, shi)] += 1;469        if row.num[1].abs() < row.num[2].abs() {470            tally.mu_under_lam += 1;471        }472        tally.musq.0 = tally.musq.0.min(sq(row.num[1]));473        tally.musq.1 = tally.musq.1.max(sq(row.num[1]));474        tally.lamsq.0 = tally.lamsq.0.min(sq(row.num[2]));475        tally.lamsq.1 = tally.lamsq.1.max(sq(row.num[2]));476        let rr = row.r as f64;477        if val(row.num[1]).abs() < rr && val(row.num[2]).abs() < rr {478            tally.under_r += 1;479        }480        if val(row.num[0]).abs() > rr {481            tally.one_over_r += 1;482        }483        for j in 1..row.num.len() {484            let f = (val(row.num[j]) + row.diag[j]) / row.diag[j];485            tally.fd.0 = tally.fd.0.min(f);486            tally.fd.1 = tally.fd.1.max(f);487        }488        tally.cs.0 = tally.cs.0.min(row.csloss[1]);489        tally.cs.1 = tally.cs.1.max(row.csloss[1]);490        if let Some(rv) = row.rms {491            if rv > 0.0 {492                tally.murms.0 = tally.murms.0.min(val(row.num[1]).abs() / rv);493                tally.murms.1 = tally.murms.1.max(val(row.num[1]).abs() / rv);494                for j in 6..9 {495                    tally.sfrms.0 = tally.sfrms.0.min(val(row.num[j]).abs() / rv);496                    tally.sfrms.1 = tally.sfrms.1.max(val(row.num[j]).abs() / rv);497                }498            }499        }500    }501    println!(502        "| {} | {} | {} | {} | {} | {} | {}/{} | {} | {} | {} | {} | {} | {} | {:.6} | {:.6} | {:.6} | {:.4} | {:.4} | {:.4} | {:.4} | {:.4} | {:.4} | {:.4} | {:.4} | {:.4} | {:.4} | {} | {} | {} | {:.4} | {:.4} |",503        q,504        label,505        l,506        x,507        kind,508        tag,509        sw.live,510        sw.seen,511        row.m,512        row.n,513        row.r,514        sig[0],515        sig[1],516        sig[2],517        exps(val(row.num[0]).abs(), x),518        exps(val(row.num[1]).abs(), x),519        exps(val(row.num[2]).abs(), x),520        ratio(row.num[1]),521        ratio(row.num[2]),522        rlo,523        rhi,524        slo,525        shi,526        sq(row.num[1]),527        sq(row.num[2]),528        sqlo,529        sqhi,530        rtxt,531        mrms,532        lrms,533        fdlo,534        fdhi535    );536}537538pub fn run() {539    let cs = cells();540    let mut lim = 16usize;541    for c in cs.iter() {542        for &l in c.depths.iter() {543            let x = qpow(c.q, l);544            for &(_, nn) in boxes(x).iter() {545                lim = lim.max(2 * nn as usize);546            }547        }548    }549    let (_, coefs) = coefficients(lim);550    println!("menergy signed");551    println!("| q | F | L | x | kind | box | live/seen | M | N | R | Sigma_1 | Sigma_mu | Sigma_lam | exp_1 | exp_mu | exp_lam | mu/1 | lam/1 | rand lo | rand hi | sf lo | sf hi | mu/sq | lam/sq | sf sq lo | sf sq hi | rms | mu/rms | lam/rms | fd lo | fd hi |");552    let mut tally = Tally {553        cells: 0,554        rand: [0; 3],555        sf: [0; 3],556        mu_under_lam: 0,557        musq: (f64::INFINITY, f64::NEG_INFINITY),558        lamsq: (f64::INFINITY, f64::NEG_INFINITY),559        under_r: 0,560        one_over_r: 0,561        fd: (f64::INFINITY, f64::NEG_INFINITY),562        murms: (f64::INFINITY, f64::NEG_INFINITY),563        sfrms: (f64::INFINITY, f64::NEG_INFINITY),564        cs: (f64::INFINITY, f64::NEG_INFINITY),565    };566    for c in cs.iter() {567        for (d, &l) in c.depths.iter().enumerate() {568            let x = qpow(c.q, l);569            let vals = column(c.q, &c.digits, l);570            let g = vals.len() as u128;571            let bits = bits_of(&vals, x);572            let mut sw = match sweep(&bits, x, g, &coefs) {573                Some(s) => s,574                None => continue,575            };576            sw.top.rms = pair_rms(&bits, sw.top.m, sw.top.n, g, x);577            if let Some(r) = sw.l5.as_mut() {578                r.rms = pair_rms(&bits, r.m, r.n, g, x);579            }580            let delta = g as f64 / x as f64;581            for (tag, row) in [Some(("top", &sw.top)), sw.l5.as_ref().map(|r| ("l5", r))]582                .into_iter()583                .flatten()584            {585                if let Some(chk) = box_row(&bits, row.m, row.n, delta, PAIRCAP) {586                    assert_eq!(chk.r, row.r, "R disagrees with the census routine");587                    assert_eq!(chk.e, row.e, "E_x(M,N) disagrees with the census routine");588                }589                emit(c.q, c.label, l, x, "digit", tag, &sw, row, &mut tally);590            }591            if d + 1 == c.depths.len() {592                let mut rng = Rng::new(0x51_6e_ed_00 + c.q * 131 + l as u64);593                let rv = random_column(x, vals.len(), &mut rng);594                let rbits = bits_of(&rv, x);595                if let Some(mut rs) = sweep(&rbits, x, g, &coefs) {596                    rs.top.rms = pair_rms(&rbits, rs.top.m, rs.top.n, g, x);597                    if let Some(r) = rs.l5.as_mut() {598                        r.rms = pair_rms(&rbits, r.m, r.n, g, x);599                    }600                    let tag = if rs.l5.is_some() { "l5" } else { "top" };601                    let row = rs.l5.as_ref().unwrap_or(&rs.top);602                    emit(c.q, c.label, l, x, "random", tag, &rs, row, &mut tally);603                }604            }605        }606    }607    println!("menergy signed summary");608    println!("| digit cells | mu below rand | mu inside rand | mu above rand | mu below sf | mu inside sf | mu above sf | mu under lam | mu/sq lo | mu/sq hi | lam/sq lo | lam/sq hi | signed under R | unsigned over R | form/diag lo | form/diag hi | mu/rms lo | mu/rms hi | sf/rms lo | sf/rms hi | mu cs lo | mu cs hi |");609    println!(610        "| {} | {} | {} | {} | {} | {} | {} | {} | {:.4} | {:.4} | {:.4} | {:.4} | {} | {} | {:.4} | {:.4} | {:.4} | {:.4} | {:.4} | {:.4} | {:.4} | {:.4} |",611        tally.cells,612        tally.rand[0],613        tally.rand[1],614        tally.rand[2],615        tally.sf[0],616        tally.sf[1],617        tally.sf[2],618        tally.mu_under_lam,619        tally.musq.0,620        tally.musq.1,621        tally.lamsq.0,622        tally.lamsq.1,623        tally.under_r,624        tally.one_over_r,625        tally.fd.0,626        tally.fd.1,627        tally.murms.0,628        tally.murms.1,629        tally.sfrms.0,630        tally.sfrms.1,631        tally.cs.0,632        tally.cs.1633    );634    println!("menergy signed engineered");635    println!("| q | F | L | box | M | N | R | flips | form | diag | form/diag | bound | floor | bound/floor |");636    for c in cs.iter() {637        let l = c.depths[0];638        let x = qpow(c.q, l);639        let vals = column(c.q, &c.digits, l);640        let g = vals.len() as u128;641        let delta = g as f64 / x as f64;642        let bits = bits_of(&vals, x);643        let sw = match sweep(&bits, x, g, &coefs) {644            Some(s) => s,645            None => continue,646        };647        for (tag, row) in [Some(("top", &sw.top)), sw.l5.as_ref().map(|r| ("l5", r))]648            .into_iter()649            .flatten()650        {651            let (form, dg, flips) = engineered(&bits, row.m, row.n, g, x, 4000);652            let bound = (row.m as f64 * form).max(0.0).sqrt();653            let floor = (1.0 - delta) * (row.m as f64 * row.r as f64).sqrt();654            println!(655                "| {} | {} | {} | {} | {} | {} | {} | {} | {:.4e} | {:.4e} | {:.4} | {:.4e} | {:.4e} | {:.4} |",656                c.q, c.label, l, tag, row.m, row.n, row.r, flips, form, dg, form / dg, bound, floor, bound / floor657            );658        }659    }660}661662// TESTS663664#[cfg(test)]665mod tests {666    use super::*;667668    #[test]669    fn the_sieves_are_right() {670        let spf = spf_table(20);671        let mu = mobius(20, &spf);672        let lam = liouville(20, &spf);673        assert_eq!(&mu[1..=12], &[1, -1, -1, 0, -1, 1, -1, 0, 0, 1, -1, 0][..]);674        assert_eq!(675            &lam[1..=12],676            &[1, -1, -1, 1, -1, 1, -1, -1, 1, 1, -1, -1][..]677        );678    }679680    fn brute_num(bits: &Bits, mm: u64, nn: u64, g: u128, x: u128, b: &[i8]) -> i128 {681        let xi = x as i128;682        let gi = g as i128;683        let mut total = 0i128;684        for l1 in nn..2 * nn {685            for l2 in nn..2 * nn {686                if l1 == l2 {687                    continue;688                }689                let mut w = 0i128;690                for m in mm..2 * mm {691                    let p1 = if bits.get((m * l1) as usize) { xi } else { 0 } - gi;692                    let p2 = if bits.get((m * l2) as usize) { xi } else { 0 } - gi;693                    w += p1 * p2;694                }695                total += b[l1 as usize] as i128 * b[l2 as usize] as i128 * w;696            }697        }698        total699    }700701    #[test]702    fn signed_row_matches_the_definition() {703        let (_, coefs) = coefficients(256);704        for (q, digits, l, mm, nn) in [705            (3u64, vec![0u64, 1], 8usize, 8u64, 16u64),706            (3, vec![1, 2], 8, 16, 16),707            (4, vec![0, 1, 2], 6, 8, 32),708            (5, vec![0, 1, 2, 3], 5, 16, 32),709        ] {710            let x = qpow(q, l);711            let vals = column(q, &digits, l);712            let g = vals.len() as u128;713            let bits = bits_of(&vals, x);714            let row = signed_row(&bits, mm, nn, g, x, &coefs);715            for (j, b) in coefs.iter().enumerate() {716                assert_eq!(717                    row.num[j],718                    brute_num(&bits, mm, nn, g, x, b),719                    "coefficient {j} at q={q} L={l}"720                );721            }722        }723    }724725    #[test]726    fn the_unsigned_row_matches_the_census() {727        let (_, coefs) = coefficients(1024);728        for (q, digits, l, mm, nn) in [729            (3u64, vec![0u64, 1], 12usize, 256u64, 512u64),730            (4, vec![0, 1, 2], 9, 256u64, 256u64),731            (5, vec![0, 1, 2, 3], 8, 256u64, 256u64),732        ] {733            let x = qpow(q, l);734            let vals = column(q, &digits, l);735            let g = vals.len() as u128;736            let delta = g as f64 / x as f64;737            let bits = bits_of(&vals, x);738            let row = signed_row(&bits, mm, nn, g, x, &coefs);739            let chk = box_row(&bits, mm, nn, delta, PAIRCAP).unwrap();740            assert_eq!(chk.r, row.r);741            assert_eq!(chk.e, row.e);742        }743    }744745    #[test]746    fn the_random_column_kills_the_unsigned_sum() {747        let (_, coefs) = coefficients(1024);748        let (q, digits, l, mm, nn) = (3u64, vec![0u64, 1], 12usize, 128u64, 128u64);749        let x = qpow(q, l);750        let vals = column(q, &digits, l);751        let g = vals.len() as u128;752        let bits = bits_of(&vals, x);753        let digit = signed_row(&bits, mm, nn, g, x, &coefs);754        let mut rng = Rng::new(0x7e57);755        let rv = random_column(x, vals.len(), &mut rng);756        let rbits = bits_of(&rv, x);757        let rand = signed_row(&rbits, mm, nn, g, x, &coefs);758        assert!(759            digit.num[0] > 20 * rand.num[0].abs(),760            "digit {} against random {}",761            digit.num[0],762            rand.num[0]763        );764    }765}