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}