memory.rs

3.9 kB · rust · 118 lines

1use crate::{Fault, Grid};2use mrlycore::json;3use mrlynum::memory::{self, Rule};4use wasm_bindgen::prelude::*;56/// The sheet budget: the most sites one drawing may carry.7pub const SITES: usize = 1 << 16;89fn sites(dimension: usize, level: usize) -> u64 {10    let side = 1u64 << level;11    if dimension == 1 {12        side * level as u6413    } else {14        side.pow(dimension as u32)15    }16}1718/// Returns the span `k D` a rule code is held inside, the crate's own bound.19#[wasm_bindgen]20pub fn memory_span() -> usize {21    memory::SPAN22}2324/// Returns the deepest level a sheet is drawn at in a dimension: the largest `L` whose sites are inside the sheet budget.25#[wasm_bindgen]26pub fn memory_cap(dimension: usize) -> usize {27    let mut level = 1;28    while level < 16 && sites(dimension, level + 1) <= SITES as u64 {29        level += 1;30    }31    level32}3334fn rule(dimension: usize, width: usize, code: &str) -> Result<Rule, Fault> {35    let code: u64 = code36        .trim()37        .parse()38        .map_err(|_| Fault::new(format!("code {code:?} is not a whole number.")))?;39    Ok(Rule::new(dimension, width, code)?)40}4142/// Reads a memory rule: its shape, its alphabet, its allowed windows, the accepted word counts to the level, the Perron root, the growth exponent and the memory number `kappa = log_2(card W) / k - log_2 rho`, as JSON.43#[wasm_bindgen]44pub fn memory_read(45    dimension: usize,46    width: usize,47    code: &str,48    levels: usize,49) -> Result<String, Fault> {50    let rule = rule(dimension, width, code)?;51    let rho = memory::perron(&rule);52    let kappa = memory::kappa(&rule);53    Ok(json!({54        "dimension": rule.dimension,55        "width": rule.width,56        "code": rule.code.to_string(),57        "codes": rule.codes().to_string(),58        "letters": rule.letters(),59        "windows": rule.windows(),60        "states": rule.states(),61        "alphabet": rule.alphabet(),62        "allowed": (0..rule.windows()).map(|w| rule.allowed(w)).collect::<Vec<bool>>(),63        "window_count": memory::allowed_windows(&rule),64        "counts": memory::counts(&rule, levels),65        "perron": rho,66        "exponent": if rho > 0.0 { rho.log2() } else { f64::NEG_INFINITY },67        "kappa": if kappa.is_finite() { kappa } else { f64::INFINITY },68    })69    .to_string())70}7172/// Draws the accepted words of a memory rule as a byte grid, one byte a site.73///74/// At dimension one the sheet is the Cantor staircase: one row a level, the row of level `j` filled on the intervals its accepted words hold.75/// At dimension two the sheet is the `2^L` by `2^L` grid of the level's accepted cells, which at width one is the design of the same code cell for cell.76#[wasm_bindgen]77pub fn memory_sheet(78    dimension: usize,79    width: usize,80    code: &str,81    level: usize,82) -> Result<Grid, Fault> {83    let rule = rule(dimension, width, code)?;84    if !(1..=16).contains(&level) {85        return Err(Fault::new(format!("level {level} is out of range.")));86    }87    let side = 1usize << level;88    let count = sites(dimension, level);89    if count > SITES as u64 {90        return Err(Fault::new(format!(91            "level {level} at dimension {dimension} asks for {count} sites, over the sheet budget of {SITES}."92        )));93    }94    if dimension == 1 {95        let mut types = vec![0u8; side * level];96        for depth in 1..=level {97            let span = 1usize << (level - depth);98            for cell in memory::cells(&rule, depth) {99                let start = cell as usize * span;100                types[(depth - 1) * side + start..(depth - 1) * side + start + span].fill(1);101            }102        }103        return Ok(Grid {104            width: side as u32,105            height: level as u32,106            types,107        });108    }109    let mut types = vec![0u8; side.pow(dimension as u32)];110    for cell in memory::cells(&rule, level) {111        types[cell as usize] = 1;112    }113    Ok(Grid {114        width: side as u32,115        height: (types.len() / side) as u32,116        types,117    })118}