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}