rows.rs

5.9 kB · rust · 214 lines

1use mrlylab::ledger::{closed, keys, terms, Closed, Cost, Key, Tier, TERMS};2use std::thread;34pub const CEILING: i128 = 100_000;5pub const CAP: usize = 48;6pub const DEEP: usize = 96;7pub const SHALLOW: usize = 32;8pub const CELLS: u128 = 100_000;9pub const BLOCK: usize = 8;10pub const THREADS: usize = 4;1112#[derive(Clone, Copy, PartialEq, Eq)]13pub enum Stop {14    Ceiling,15    Cap,16    Budget,17}1819impl Stop {20    pub fn slug(self) -> &'static str {21        match self {22            Stop::Ceiling => "ceiling",23            Stop::Cap => "cap",24            Stop::Budget => "budget",25        }26    }27}2829pub struct Row {30    pub name: String,31    pub tier: Tier,32    pub form: Option<Closed>,33    pub head: Vec<i128>,34    pub written: Vec<i128>,35    pub shallow: Vec<i128>,36    pub tail: Vec<i128>,37    pub repeats: usize,38    pub low: usize,39    pub stop: Stop,40}4142fn footprint(key: &Key, index: usize) -> Option<u128> {43    let (number, level) = key.axis.place(index, key.number());44    let number = number as u128;45    let dimension = key.dimension as u32;46    match key.measure.cost() {47        Cost::Closed => Some(1),48        Cost::Convolved => {49            let tile = number.checked_pow(dimension)?;50            let side = number.checked_pow(level)?;51            let span = key.dimension as u128 * (side - 1) + 1;52            tile.checked_add(span.checked_mul(level as u128)?)53        }54        Cost::Grid => number.checked_pow(dimension.checked_mul(level)?),55    }56}5758fn allowance(key: &Key) -> usize {59    (0..CAP)60        .take_while(|&index| footprint(key, index).is_some_and(|cells| cells <= CELLS))61        .count()62}6364fn ceiling_stop(read: &[i128]) -> Option<usize> {65    let mut previous: Option<i128> = None;66    for (index, &term) in read.iter().enumerate() {67        if previous.is_some_and(|last| term <= last) {68            return None;69        }70        if term > CEILING {71            return Some(index);72        }73        previous = Some(term);74    }75    None76}7778fn gather(window: &[i128]) -> (Vec<i128>, usize, usize) {79    let low = window.iter().filter(|&&term| term < 1).count();80    let mut inside: Vec<i128> = window81        .iter()82        .copied()83        .filter(|&term| (1..=CEILING).contains(&term))84        .collect();85    let all = inside.len();86    inside.sort_unstable();87    inside.dedup();88    let repeats = all - inside.len();89    (inside, repeats, low)90}9192fn render(key: &Key, tier: Tier) -> Option<Row> {93    let allowed = allowance(key);94    let mut count = BLOCK.min(allowed);95    let mut head = Vec::new();96    let window;97    let stop;98    loop {99        let (read, capped) = terms(key, count, CELLS).ok()?;100        let short = capped || read.len() < count;101        if head.len() < TERMS.min(read.len()) {102            head = read[..TERMS.min(read.len())].to_vec();103        }104        if let Some(edge) = ceiling_stop(&read) {105            window = read[..=edge].to_vec();106            stop = Stop::Ceiling;107            break;108        }109        if short {110            window = read;111            stop = Stop::Budget;112            break;113        }114        if count >= allowed {115            window = read;116            stop = if allowed == CAP {117                Stop::Cap118            } else {119                Stop::Budget120            };121            break;122        }123        count = (count * 2).min(allowed);124    }125    let (written, repeats, low) = gather(&window);126    let (shallow, _, _) = gather(&window[..SHALLOW.min(window.len())]);127    let (tail, _, _) = gather(&window[1.min(window.len())..]);128    Some(Row {129        name: key.name(),130        tier,131        form: closed(key).ok().flatten(),132        head,133        written,134        shallow,135        tail,136        repeats,137        low,138        stop,139    })140}141142pub fn predict(form: &Closed, index: usize) -> Option<i128> {143    match form {144        Closed::Power(fill) => i128::try_from(*fill).ok()?.checked_pow(index as u32 + 1),145        Closed::Difference(all, fill) => {146            let level = index as u32 + 1;147            let whole = i128::try_from(*all).ok()?.checked_pow(level)?;148            whole.checked_sub(i128::try_from(*fill).ok()?.checked_pow(level)?)149        }150        Closed::Polynomial(coefficients) => {151            let side = index as i128 + 2;152            coefficients153                .iter()154                .enumerate()155                .try_fold(0i128, |sum, (power, &c)| {156                    sum.checked_add(c.checked_mul(side.checked_pow(power as u32)?)?)157                })158        }159        Closed::Recurrence(_) => None,160    }161}162163pub fn replay(coefficients: &[i128], head: &[i128], index: usize) -> Option<i128> {164    coefficients165        .iter()166        .enumerate()167        .try_fold(0i128, |sum, (back, &c)| {168            sum.checked_add(c.checked_mul(*head.get(index.checked_sub(back + 1)?)?)?)169        })170}171172pub struct Sheet {173    pub rows: Vec<Row>,174    pub tiers: Vec<(Tier, usize)>,175    pub unread: usize,176}177178pub fn read() -> Sheet {179    let mut tiers = Vec::new();180    let mut listed: Vec<(Key, Tier)> = Vec::new();181    for tier in Tier::ALL {182        let batch = keys(tier);183        tiers.push((tier, batch.len()));184        listed.extend(batch.into_iter().map(|key| (key, tier)));185    }186    let chunk = listed.len().div_ceil(THREADS);187    let parts: Vec<Vec<Option<Row>>> = thread::scope(|scope| {188        let handles: Vec<_> = listed189            .chunks(chunk)190            .map(|slice| {191                scope.spawn(move || slice.iter().map(|(key, tier)| render(key, *tier)).collect())192            })193            .collect();194        handles195            .into_iter()196            .map(|handle| handle.join().expect("the row walk lands"))197            .collect()198    });199    let mut rows = Vec::with_capacity(listed.len());200    let mut unread = 0;201    for part in parts {202        for slot in part {203            match slot {204                Some(row) => rows.push(row),205                None => unread += 1,206            }207        }208    }209    Sheet {210        rows,211        tiers,212        unread,213    }214}