designs.rs

6.7 kB · rust · 197 lines

1use super::Cell2d;2use crate::core::atoms;3use crate::core::errors::{value_error, Result};4use crate::core::tensor::Tensor;5use crate::core::tile::Design;6use crate::math::bang::factory;7use crate::math::bang::universe::Code;89pub use crate::math::bang::factory::levels_code;1011fn build(pattern: Tensor, level: usize, rotation: usize) -> Result<Cell2d> {12    let mut cell = crate::math::dim::grow::<2>(pattern, level)?;13    if rotation != 0 {14        cell = cell.rotate(rotation);15    }16    Ok(cell)17}1819/// Builds the design a universe code names, deepened to the level and rotated by quarter-turns.20pub fn create(21    code: Code,22    number: usize,23    level: usize,24    rotation: usize,25    base: usize,26) -> Result<Cell2d> {27    build(factory::create(code, number, 2, base, 1)?, level, rotation)28}2930/// Builds the design straight from its filled residue corners, deepened to the level and rotated by quarter-turns.31pub fn from_corners(32    corners: &[Vec<u8>],33    number: usize,34    level: usize,35    rotation: usize,36    base: usize,37) -> Result<Cell2d> {38    build(39        factory::create_from_corners(corners, number, 2, base, 1)?,40        level,41        rotation,42    )43}4445/// Builds the level-set design, filling every residue corner whose digits sum to a named level.46///47/// ```48/// let n = 5;49/// assert_eq!(50///     mrlyrs::math::two::level_set(n, &[0, 1], 1, 0, 2).unwrap(),51///     mrlyrs::math::two::carpet(n, 1).unwrap()52/// );53/// ```54pub fn level_set(55    number: usize,56    levels: &[usize],57    level: usize,58    rotation: usize,59    base: usize,60) -> Result<Cell2d> {61    create(levels_code(2, base, levels), number, level, rotation, base)62}6364/// Builds the design the name picks, deepened to the level and rotated by quarter-turns.65pub fn named(design: Design, number: usize, level: usize, rotation: usize) -> Result<Cell2d> {66    let pattern = match design {67        Design::Carpet => atoms::carpet_2d(number),68        Design::Net => atoms::net_2d(number),69        Design::Htree => atoms::htree_2d(number),70        Design::Vtree => atoms::vtree_2d(number),71        Design::Void => atoms::void_2d(number),72        Design::Point => atoms::point_2d(number),73        Design::Dust => atoms::dust_2d(number),74        Design::Hline => atoms::hline_2d(number),75        Design::Vline => atoms::vline_2d(number),76        Design::Star => atoms::star_2d(number),77        other => return value_error(format!("design {} is not 2d.", other.name())),78    };79    build(pattern, level, rotation)80}8182/// Builds an all-empty cell of the given size and level.83pub fn zeros(number: usize, level: usize) -> Result<Cell2d> {84    build(atoms::zeros_2d(number), level, 0)85}8687/// Builds an all-filled cell of the given size and level.88pub fn ones(number: usize, level: usize) -> Result<Cell2d> {89    build(atoms::ones_2d(number), level, 0)90}9192/// Builds the carpet fractal, its seed pierced at every odd-odd site, deepened to the level.93pub fn carpet(number: usize, level: usize) -> Result<Cell2d> {94    build(atoms::carpet_2d(number), level, 0)95}9697/// Builds the net fractal, its seed on wherever a coordinate is odd, deepened to the level.98pub fn net(number: usize, level: usize) -> Result<Cell2d> {99    build(atoms::net_2d(number), level, 0)100}101102/// Builds the htree fractal, its seed striped along even rows, deepened to the level.103pub fn htree(number: usize, level: usize) -> Result<Cell2d> {104    build(atoms::htree_2d(number), level, 0)105}106107/// Builds the vtree fractal, its seed striped along even columns, deepened to the level.108pub fn vtree(number: usize, level: usize) -> Result<Cell2d> {109    build(atoms::vtree_2d(number), level, 0)110}111112/// Builds the void fractal, its seed a checkerboard on even parity, deepened to the level.113pub fn void(number: usize, level: usize) -> Result<Cell2d> {114    build(atoms::void_2d(number), level, 0)115}116117/// Builds the point fractal, its seed on at every odd-odd site, deepened to the level.118pub fn point(number: usize, level: usize) -> Result<Cell2d> {119    build(atoms::point_2d(number), level, 0)120}121122/// Builds the dust fractal, its seed on at every even-even site, deepened to the level.123pub fn dust(number: usize, level: usize) -> Result<Cell2d> {124    build(atoms::dust_2d(number), level, 0)125}126127/// Builds the hline fractal, its seed striped along odd rows, deepened to the level.128pub fn hline(number: usize, level: usize) -> Result<Cell2d> {129    build(atoms::hline_2d(number), level, 0)130}131132/// Builds the vline fractal, its seed striped along odd columns, deepened to the level.133pub fn vline(number: usize, level: usize) -> Result<Cell2d> {134    build(atoms::vline_2d(number), level, 0)135}136137/// Builds the star fractal, its seed on where exactly one coordinate is odd, deepened to the level.138pub fn star(number: usize, level: usize) -> Result<Cell2d> {139    build(atoms::star_2d(number), level, 0)140}141142#[cfg(test)]143mod tests {144    use super::*;145    #[test]146    fn carpet_fractal_growth() {147        let c = carpet(3, 3).unwrap();148        assert_eq!(c.width(), 27);149        assert_eq!(c.types().sum(), carpet(3, 1).unwrap().types().sum().pow(3));150    }151    #[test]152    fn create_matches_carpet() {153        let by_name = carpet(5, 2).unwrap();154        let by_code = create(7, 5, 2, 0, 2).unwrap();155        assert_eq!(by_name, by_code);156    }157    #[test]158    fn level_sets_reproduce_the_symmetric_designs() {159        for n in 1..8 {160            assert_eq!(161                level_set(n, &[0, 1], 1, 0, 2).unwrap(),162                carpet(n, 1).unwrap()163            );164            assert_eq!(level_set(n, &[1, 2], 1, 0, 2).unwrap(), net(n, 1).unwrap());165            assert_eq!(level_set(n, &[0, 2], 1, 0, 2).unwrap(), void(n, 1).unwrap());166        }167        assert_eq!(level_set(4, &[], 1, 0, 2).unwrap(), zeros(4, 1).unwrap());168        assert_eq!(169            level_set(4, &[0, 1, 2], 1, 0, 2).unwrap(),170            ones(4, 1).unwrap()171        );172    }173    #[test]174    fn level_sets_carry_level_and_rotation() {175        let deep = level_set(3, &[0, 1], 2, 0, 2).unwrap();176        assert_eq!(deep, carpet(3, 2).unwrap());177        let turned = level_set(5, &[1, 2], 1, 1, 2).unwrap();178        assert_eq!(turned, net(5, 1).unwrap().rotate(1));179    }180    #[test]181    fn named_builders_take_a_rotation() {182        for (design, plain) in [183            (Design::Carpet, carpet(5, 1).unwrap()),184            (Design::Net, net(5, 1).unwrap()),185            (Design::Htree, htree(5, 1).unwrap()),186            (Design::Vtree, vtree(5, 1).unwrap()),187            (Design::Void, void(5, 1).unwrap()),188        ] {189            assert_eq!(named(design, 5, 1, 0).unwrap(), plain);190            for k in 1..4 {191                assert_eq!(named(design, 5, 1, k).unwrap(), plain.clone().rotate(k));192            }193        }194        assert_eq!(named(Design::Vtree, 5, 1, 1).unwrap(), htree(5, 1).unwrap());195        assert!(named(Design::Ztree, 5, 1, 0).is_err());196    }197}