atoms.rs
7.2 kB · rust · 253 lines
1use crate::core::rng::Rng;2use crate::core::tensor::Tensor;34fn build(n: usize, rank: usize, mut rule: impl FnMut(&[usize]) -> bool) -> Tensor {5 let mut out = Tensor::new(vec![n; rank]);6 let mut at = vec![0usize; rank];7 for flat in 0..out.size() {8 let mut rest = flat;9 for axis in (0..rank).rev() {10 at[axis] = rest % n;11 rest /= n;12 }13 out.put(flat, i64::from(rule(&at)));14 }15 out16}1718fn odd(at: &[usize]) -> usize {19 at.iter().filter(|c| *c % 2 == 1).count()20}2122/// Builds a carpet of the given side at any rank, on where at most one coordinate is odd.23pub fn carpet_nd(n: usize, rank: usize) -> Tensor {24 build(n, rank, |at| odd(at) <= 1)25}2627/// Builds a net of the given side at any rank, on where the odd coordinates plus one reach the rank.28pub fn net_nd(n: usize, rank: usize) -> Tensor {29 build(n, rank, |at| odd(at) + 1 >= rank)30}3132/// Builds a tree of the given side at any rank, even on every axis but the free one; an axis past the rank frees none.33pub fn tree_nd(n: usize, rank: usize, axis: usize) -> Tensor {34 build(n, rank, |at| {35 at.iter().enumerate().all(|(i, c)| i == axis || c % 2 == 0)36 })37}3839/// Builds a void of the given side at any rank, on where every coordinate shares one parity.40pub fn void_nd(n: usize, rank: usize) -> Tensor {41 build(n, rank, |at| at.iter().all(|c| c % 2 == at[0] % 2))42}4344/// Builds a point of the given side at any rank, on where every coordinate is odd.45pub fn point_nd(n: usize, rank: usize) -> Tensor {46 build(n, rank, |at| odd(at) == rank)47}4849/// Builds a dust of the given side at any rank, on where every coordinate is even.50pub fn dust_nd(n: usize, rank: usize) -> Tensor {51 build(n, rank, |at| odd(at) == 0)52}5354/// Builds a line of the given side at any rank, odd on every axis but the free one; an axis past the rank frees none.55pub fn line_nd(n: usize, rank: usize, axis: usize) -> Tensor {56 build(n, rank, |at| {57 at.iter().enumerate().all(|(i, c)| i == axis || c % 2 == 1)58 })59}6061/// Builds a star of the given side at any rank, on where exactly one coordinate is odd.62pub fn star_nd(n: usize, rank: usize) -> Tensor {63 build(n, rank, |at| odd(at) == 1)64}6566/// Builds an n by n tensor of zeros.67pub fn zeros_2d(n: usize) -> Tensor {68 Tensor::new(vec![n, n])69}7071/// Builds an n by n by n tensor of zeros.72pub fn zeros_3d(n: usize) -> Tensor {73 Tensor::new(vec![n, n, n])74}7576/// Builds an n by n tensor of ones.77pub fn ones_2d(n: usize) -> Tensor {78 Tensor::full(vec![n, n], 1)79}8081/// Builds an n by n by n tensor of ones.82pub fn ones_3d(n: usize) -> Tensor {83 Tensor::full(vec![n, n, n], 1)84}8586/// Builds an n by n tensor where each cell turns on with probability density, drawn from the stream.87pub fn noise_2d(n: usize, density: f64, rng: &mut Rng) -> Tensor {88 build(n, 2, |_| rng.chance(density))89}9091/// Builds an n by n by n tensor where each cell turns on with probability density, drawn from the stream.92pub fn noise_3d(n: usize, density: f64, rng: &mut Rng) -> Tensor {93 build(n, 3, |_| rng.chance(density))94}9596/// Builds an n by n carpet, on where at most one coordinate is odd.97///98/// ```99/// let seed = mrlyrs::math::atoms::carpet_2d(3);100/// assert_eq!(seed.sum(), 8);101/// ```102pub fn carpet_2d(n: usize) -> Tensor {103 carpet_nd(n, 2)104}105106/// Builds an n by n by n carpet, on where at most one coordinate is odd.107pub fn carpet_3d(n: usize) -> Tensor {108 carpet_nd(n, 3)109}110111/// Builds an n by n net, on where at least one coordinate is odd.112pub fn net_2d(n: usize) -> Tensor {113 net_nd(n, 2)114}115116/// Builds an n by n by n net, on where at least two coordinates are odd.117pub fn net_3d(n: usize) -> Tensor {118 net_nd(n, 3)119}120121/// Builds an n by n tree, free on axis 1, on along the even rows.122pub fn htree_2d(n: usize) -> Tensor {123 tree_nd(n, 2, 1)124}125126/// Builds an n by n tree, free on axis 0, on along the even columns.127pub fn vtree_2d(n: usize) -> Tensor {128 tree_nd(n, 2, 0)129}130131/// Builds an n by n by n tree, free on axis 0, its beams running along x.132pub fn xtree_3d(n: usize) -> Tensor {133 tree_nd(n, 3, 0)134}135136/// Builds an n by n by n tree, free on axis 1, its beams running along y.137pub fn ytree_3d(n: usize) -> Tensor {138 tree_nd(n, 3, 1)139}140141/// Builds an n by n by n tree, free on axis 2, its beams running along z.142pub fn ztree_3d(n: usize) -> Tensor {143 tree_nd(n, 3, 2)144}145146/// Builds an n by n void, on where both coordinates share one parity.147pub fn void_2d(n: usize) -> Tensor {148 void_nd(n, 2)149}150151/// Builds an n by n by n void, on where all three coordinates share one parity.152pub fn void_3d(n: usize) -> Tensor {153 void_nd(n, 3)154}155156/// Builds an n by n point, on where both coordinates are odd.157pub fn point_2d(n: usize) -> Tensor {158 point_nd(n, 2)159}160161/// Builds an n by n by n point, on where all three coordinates are odd.162pub fn point_3d(n: usize) -> Tensor {163 point_nd(n, 3)164}165166/// Builds an n by n dust, on where both coordinates are even.167pub fn dust_2d(n: usize) -> Tensor {168 dust_nd(n, 2)169}170171/// Builds an n by n by n dust, on where all three coordinates are even.172pub fn dust_3d(n: usize) -> Tensor {173 dust_nd(n, 3)174}175176/// Builds an n by n line, free on axis 1, on along the odd rows.177pub fn hline_2d(n: usize) -> Tensor {178 line_nd(n, 2, 1)179}180181/// Builds an n by n line, free on axis 0, on along the odd columns.182pub fn vline_2d(n: usize) -> Tensor {183 line_nd(n, 2, 0)184}185186/// Builds an n by n by n line, free on axis 0, its rods running along x.187pub fn xline_3d(n: usize) -> Tensor {188 line_nd(n, 3, 0)189}190191/// Builds an n by n by n line, free on axis 1, its rods running along y.192pub fn yline_3d(n: usize) -> Tensor {193 line_nd(n, 3, 1)194}195196/// Builds an n by n by n line, free on axis 2, its rods running along z.197pub fn zline_3d(n: usize) -> Tensor {198 line_nd(n, 3, 2)199}200201/// Builds an n by n star, on where exactly one coordinate is odd.202pub fn star_2d(n: usize) -> Tensor {203 star_nd(n, 2)204}205206/// Builds an n by n by n star, on where exactly one coordinate is odd.207pub fn star_3d(n: usize) -> Tensor {208 star_nd(n, 3)209}210211#[cfg(test)]212mod tests {213 use super::*;214 #[test]215 fn noise_replays_from_its_seed_and_parts_on_another() {216 assert_eq!(217 noise_3d(3, 0.5, &mut Rng::new(11)),218 noise_3d(3, 0.5, &mut Rng::new(11))219 );220 assert_ne!(221 noise_2d(4, 0.5, &mut Rng::new(1)),222 noise_2d(4, 0.5, &mut Rng::new(2))223 );224 }225 #[test]226 fn the_antis_complement_the_classics() {227 for n in [3, 5] {228 for (classic, anti) in [229 (carpet_2d(n), point_2d(n)),230 (net_2d(n), dust_2d(n)),231 (htree_2d(n), hline_2d(n)),232 (vtree_2d(n), vline_2d(n)),233 (void_2d(n), star_2d(n)),234 ] {235 let both = classic.bytes().unwrap().iter().zip(anti.bytes().unwrap());236 assert!(both.map(|(a, b)| a + b).all(|v| v == 1));237 }238 }239 }240 #[test]241 fn the_sponge_is_dust_plus_star() {242 for n in [3, 5, 7] {243 let sum: Vec<u8> = dust_3d(n)244 .bytes()245 .unwrap()246 .iter()247 .zip(star_3d(n).bytes().unwrap())248 .map(|(a, b)| a + b)249 .collect();250 assert_eq!(sum, carpet_3d(n).bytes().unwrap());251 }252 }253}