six.rs

8.9 kB · rust · 253 lines

1use crate::bang::code_to_corners;2use crate::bang::universe::Code;3use crate::formulas::counting::positions;4use mrlycore::errors::{value_error, Result};5use std::collections::HashSet;67/// Returns the triangles of the full hexagon with side number to the level.8pub fn grid_triangles(number: usize, level: u32) -> u128 {9    6 * (number as u128).pow(2 * level)10}1112fn odd_k(number: usize) -> Result<u128> {13    if number.is_multiple_of(2) {14        return value_error("solid slice closed form is defined for odd number = 2k-1.");15    }16    Ok(number.div_ceil(2) as u128)17}1819/// Returns the core node count of the solid slice, defined for odd number.20pub fn solid_slice_core_nodes(number: usize) -> Result<u128> {21    let k = odd_k(number)? as i128;22    Ok((24 * k * k - 24 * k + 6) as u128)23}2425/// Returns the core edge count of the solid slice, defined for odd number.26pub fn solid_slice_core_edges(number: usize) -> Result<u128> {27    let k = odd_k(number)? as i128;28    Ok((36 * k * k - 42 * k + 12) as u128)29}3031/// Returns the triangle count of the solid slice, defined for odd number.32pub fn solid_slice_triangles(number: usize) -> Result<u128> {33    odd_k(number)?;34    Ok(6 * (number as u128).pow(2))35}3637/// Returns the boundary edge count of the solid slice, defined for odd number.38pub fn solid_slice_boundary(number: usize) -> Result<u128> {39    odd_k(number)?;40    Ok(6 * number as u128)41}4243/// Returns the vertex count of the solid slice, defined for odd number.44pub fn solid_slice_vertices(number: usize) -> Result<u128> {45    let k = odd_k(number)? as i128;46    Ok((12 * k * k - 6 * k + 1) as u128)47}4849/// Returns the interior edge count of the solid slice, defined for odd number.50pub fn solid_slice_interior(number: usize) -> Result<u128> {51    let k = odd_k(number)? as i128;52    Ok((36 * k * k - 42 * k + 12) as u128)53}5455/// Returns the centered hexagonal number at the index, the lattice points of a hexagon of side m-1.56pub fn centered_hexagonal(m: usize) -> u128 {57    let m = m as u128;58    3 * m * m - 3 * m + 159}6061/// Returns the distinct triangle-edge count of the solid slice, defined for odd number.62pub fn solid_slice_edges(number: usize) -> Result<u128> {63    let k = odd_k(number)? as i128;64    Ok((36 * k * k - 30 * k + 6) as u128)65}6667/// Returns the filled triangle count of the code's pro projection at the given level, without rendering it.68pub fn pro_fills(code: Code, number: usize, level: u32) -> Result<u128> {69    let filled = code_to_corners(code, 3, 2)?;70    let boundary = ((number - 1) % 2) as u8;71    let mut total: u128 = 0;72    for axis in 0..3 {73        let slab: u128 = filled74            .iter()75            .filter(|c| c[axis] == boundary)76            .map(|c| {77                (0..3)78                    .filter(|&j| j != axis)79                    .map(|j| positions(c[j] as usize, number, 2))80                    .product::<u128>()81            })82            .sum();83        total += slab.pow(level);84    }85    Ok(2 * total)86}8788/// Returns the empty triangle count of the code's pro projection at the given level.89pub fn pro_voids(code: Code, number: usize, level: u32) -> Result<u128> {90    Ok(grid_triangles(number, level) - pro_fills(code, number, level)?)91}9293/// Returns the filled triangle count of the code's cut section at the given level, without rendering it.94pub fn cut_fills(code: Code, number: usize, level: u32) -> Result<u128> {95    let filled: HashSet<Vec<u8>> = code_to_corners(code, 3, 2)?.into_iter().collect();96    let scaled = number.pow(level);97    let size = 4 * scaled;98    let k = (3 * (size - 1)) / 2;99    let mut total: u128 = 0;100    for z in (0..size).step_by(2) {101        let target = k - z;102        let min_x = target.saturating_sub(size - 1);103        let max_x = (size - 1).min(target);104        for x in min_x..=max_x {105            let y = target - x;106            let (mut a, mut b, mut c) = (x / 4, y / 4, z / 4);107            let mut inside = true;108            for _ in 0..level {109                let corner = vec![110                    (a % number % 2) as u8,111                    (b % number % 2) as u8,112                    (c % number % 2) as u8,113                ];114                if !filled.contains(&corner) {115                    inside = false;116                    break;117                }118                a /= number;119                b /= number;120                c /= number;121            }122            if inside {123                total += 1;124            }125        }126    }127    Ok(total)128}129130/// Returns the empty triangle count of the code's cut section at the given level.131pub fn cut_voids(code: Code, number: usize, level: u32) -> Result<u128> {132    Ok(grid_triangles(number, level) - cut_fills(code, number, level)?)133}134135#[cfg(test)]136mod tests {137    use super::*;138    #[test]139    fn pro_and_cut_match_census() {140        use crate::six::{cut, pro};141        use crate::three;142        use mrlynum::census::count;143        for code in [0u128, 8, 17, 23, 129, 232, 255] {144            for number in [1usize, 2, 3, 4, 5, 7] {145                for level in 1..3u32 {146                    if number.pow(level) > 9 {147                        continue;148                    }149                    let cell = three::create(code, number, level as usize, 2).unwrap();150                    let p = pro(&cell).unwrap();151                    assert_eq!(152                        pro_fills(code, number, level).unwrap(),153                        count(p.cell.types(), 1) as u128,154                        "pro code={code} n={number} l={level}"155                    );156                    assert_eq!(157                        pro_voids(code, number, level).unwrap(),158                        count(p.cell.types(), 0) as u128159                    );160                    let q = cut(&cell).unwrap();161                    assert_eq!(162                        cut_fills(code, number, level).unwrap(),163                        count(q.cell.types(), 1) as u128,164                        "cut code={code} n={number} l={level}"165                    );166                    assert_eq!(167                        cut_voids(code, number, level).unwrap(),168                        count(q.cell.types(), 0) as u128169                    );170                }171            }172        }173    }174    #[test]175    fn menger_projections() {176        assert_eq!(pro_fills(23, 3, 1).unwrap(), 48);177        assert_eq!(pro_fills(23, 3, 2).unwrap(), 384);178        assert_eq!(cut_fills(23, 3, 1).unwrap(), 42);179        assert_eq!(cut_fills(23, 3, 2).unwrap(), 306);180        assert_eq!(cut_fills(255, 3, 1).unwrap(), 54);181    }182    #[test]183    fn closed_forms_at_small_numbers() {184        assert_eq!(grid_triangles(3, 1), 54);185        assert_eq!(solid_slice_triangles(3).unwrap(), 54);186        assert_eq!(solid_slice_boundary(3).unwrap(), 18);187        assert!(solid_slice_vertices(4).is_err());188        assert_eq!(solid_slice_core_nodes(1).unwrap(), 6);189        assert_eq!(solid_slice_core_edges(1).unwrap(), 6);190        assert_eq!(solid_slice_core_nodes(3).unwrap(), 54);191        assert_eq!(solid_slice_core_edges(3).unwrap(), 72);192        assert_eq!(solid_slice_vertices(3).unwrap(), 37);193        assert_eq!(solid_slice_edges(1).unwrap(), 12);194        assert_eq!(solid_slice_edges(3).unwrap(), 90);195        assert!(solid_slice_edges(4).is_err());196    }197}198199#[cfg(test)]200mod theorems {201    use super::*;202    use mrlynum::prime::is_prime;203204    fn slice_vertices(k: usize) -> u128 {205        solid_slice_vertices(2 * k - 1).unwrap()206    }207208    #[test]209    fn the_slice_vertex_count_is_centered_hexagonal_at_even_index() {210        let opening: Vec<u128> = (1..6).map(centered_hexagonal).collect();211        assert_eq!(opening, [1, 7, 19, 37, 61]);212        for k in 1..41usize {213            let m = 2 * k as u128;214            assert_eq!(slice_vertices(k), centered_hexagonal(2 * k), "k={k}");215            assert_eq!(slice_vertices(k) % 3, 1, "k={k}");216            assert_eq!(217                slice_vertices(k),218                m * m + m * (m - 1) + (m - 1) * (m - 1),219                "k={k}"220            );221        }222    }223224    #[test]225    fn the_prime_vertex_counts_are_cuban_with_norm_witnesses() {226        let mut prime_at = Vec::new();227        let mut primes = Vec::new();228        let mut composites = Vec::new();229        for k in 1..21usize {230            if is_prime(slice_vertices(k) as usize) {231                prime_at.push(k);232                primes.push(slice_vertices(k));233            } else {234                composites.push(slice_vertices(k));235            }236        }237        assert_eq!(prime_at, [1, 2, 5, 6, 7, 9, 12, 13, 14, 19]);238        assert_eq!(primes, [7, 37, 271, 397, 547, 919, 1657, 1951, 2269, 4219]);239        assert_eq!(240            composites,241            [91, 169, 721, 1141, 1387, 2611, 2977, 3367, 3781, 4681]242        );243        let far: Vec<u128> = (21..41usize)244            .map(slice_vertices)245            .filter(|&v| is_prime(v as usize))246            .collect();247        assert_eq!(far, [5167, 6211, 7351, 9241, 12097, 13669]);248        for value in primes.iter().chain(far.iter()) {249            assert_eq!(value % 3, 1, "value={value}");250        }251        assert_eq!(4219u128, 37 * 37 + 37 * 38 + 38 * 38);252    }253}