press.rs
25.5 kB · rust · 765 lines
1use crate::core::error::{overflow_error, value_error, Result};2use crate::math::bang::factory::{code_to_corners, MagicLayer};3use crate::math::bang::Code;4use serde::{Deserialize, Serialize};56/// The largest corner count the tally press accepts, keeping its table a million rows.7pub const CORNERS: usize = 20;89fn corner_count(dimension: usize, base: usize) -> Result<usize> {10 let count = base.pow(dimension as u32);11 if count >= 128 {12 return overflow_error(format!(13 "dimension {dimension} base {base} has {count} corners, past the 127 a u128 code holds."14 ));15 }16 Ok(count)17}1819/// Returns the corner-usage mask of a number, one bit per digit vector its expansion uses.20///21/// A number is read in base `base` to the power of the dimension, so each digit is one22/// residue corner of the design cube, and zero uses exactly the zero corner.23///24/// ```25/// assert_eq!(mrlyrs::math::press::usage(0, 2, 2).unwrap().get(), 1);26/// assert_eq!(mrlyrs::math::press::usage(6, 2, 2).unwrap().get(), 0b0110);27/// ```28///29/// # Errors30///31/// Errors when the dimension and base reach a hundred and twenty-eight corners.32pub fn usage(number: u128, dimension: usize, base: usize) -> Result<Code> {33 Ok(mask(number, corner_count(dimension, base)? as u128))34}3536fn mask(number: u128, radix: u128) -> Code {37 if number == 0 {38 return Code(1);39 }40 let mut out: u128 = 0;41 let mut rest = number;42 while rest > 0 {43 out |= 1 << (rest % radix);44 rest /= radix;45 }46 Code(out)47}4849/// Returns whether every digit vector of the number lies in the design.50///51/// This is the scalar membership rule of the sequence press: the number's base52/// `base` to the dimension digits, read as residue corners, must all be filled.53/// At dimension one it is the classic restricted-digit set.54///55/// ```56/// use mrlyrs::math::bang::Code;57/// let members: Vec<u128> = (0..30).filter(|&n| mrlyrs::math::press::member(Code::from(0b0111u64), n, 2, 2).unwrap()).collect();58/// assert_eq!(members, vec![0, 1, 2, 4, 5, 6, 8, 9, 10, 16, 17, 18, 20, 21, 22, 24, 25, 26]);59/// ```60///61/// # Errors62///63/// Errors when the dimension and base reach a hundred and twenty-eight corners.64pub fn member(code: Code, number: u128, dimension: usize, base: usize) -> Result<bool> {65 Ok(usage(number, dimension, base)?.get() & !code.get() == 0)66}6768/// Returns the count of distinct digit vectors the number uses.69///70/// # Errors71///72/// Errors when the dimension and base reach a hundred and twenty-eight corners.73pub fn distinct(number: u128, dimension: usize, base: usize) -> Result<u32> {74 Ok(usage(number, dimension, base)?.get().count_ones())75}7677/// Returns the number of designs of the dimension and base that contain the number.78///79/// A design contains the number exactly when it fills every used corner, so the count80/// is two to the free corners, and the average membership over all designs is one over81/// two to the distinct-vector count.82///83/// ```84/// assert_eq!(mrlyrs::math::press::containing(6, 2, 2).unwrap(), 4);85/// ```86///87/// # Errors88///89/// Errors when the dimension and base reach a hundred and twenty-eight corners.90pub fn containing(number: u128, dimension: usize, base: usize) -> Result<u128> {91 Ok(1 << (corner_count(dimension, base)? as u32 - distinct(number, dimension, base)?))92}9394/// Splits a number into its dimension coordinates, one base digit peeled per axis in parallel.95///96/// ```97/// assert_eq!(mrlyrs::math::press::coordinates(6, 2, 2).unwrap(), vec![1, 2]);98/// ```99///100/// # Errors101///102/// Errors when the dimension and base reach a hundred and twenty-eight corners.103pub fn coordinates(number: u128, dimension: usize, base: usize) -> Result<Vec<u128>> {104 let radix = corner_count(dimension, base)? as u128;105 let mut out = vec![0u128; dimension];106 let mut rest = number;107 let mut place: u128 = 1;108 while rest > 0 {109 let mut corner = rest % radix;110 for axis in (0..dimension).rev() {111 out[axis] += (corner % base as u128) * place;112 corner /= base as u128;113 }114 rest /= radix;115 place *= base as u128;116 }117 Ok(out)118}119120/// Weaves dimension coordinates back into their single interleaved number.121///122/// # Errors123///124/// Errors on an empty coordinate list, past a hundred and twenty-seven corners, or when the woven number passes a u128.125pub fn interleave(coords: &[u128], base: usize) -> Result<u128> {126 if coords.is_empty() {127 return value_error("interleave needs at least one coordinate.");128 }129 let dimension = coords.len();130 let radix = corner_count(dimension, base)? as u128;131 let mut digits = Vec::new();132 let mut rest: Vec<u128> = coords.to_vec();133 while rest.iter().any(|&c| c > 0) {134 let mut corner: u128 = 0;135 for value in rest.iter_mut() {136 corner = corner * base as u128 + *value % base as u128;137 *value /= base as u128;138 }139 digits.push(corner);140 }141 let mut out: u128 = 0;142 for &corner in digits.iter().rev() {143 out = match out.checked_mul(radix).and_then(|v| v.checked_add(corner)) {144 Some(value) => value,145 None => {146 return overflow_error("the woven number passes a hundred and twenty-eight bits.")147 }148 };149 }150 Ok(out)151}152153/// Returns the first members of a design in ascending order.154///155/// Stops early where the next member would pass a hundred and twenty-eight bits.156///157/// ```158/// use mrlyrs::math::bang::Code;159/// assert_eq!(mrlyrs::math::press::members(Code::from(0b10u64), 1, 2, 5).unwrap(), vec![1, 3, 7, 15, 31]);160/// ```161///162/// # Errors163///164/// Errors when the dimension and base reach a hundred and twenty-eight corners.165pub fn members(code: Code, dimension: usize, base: usize, count: usize) -> Result<Vec<u128>> {166 let radix = corner_count(dimension, base)? as u128;167 let allowed: Vec<u128> = (0..radix).filter(|&i| (code.get() >> i) & 1 == 1).collect();168 let mut out = Vec::with_capacity(count);169 if count == 0 || allowed.is_empty() {170 return Ok(out);171 }172 if allowed[0] == 0 {173 out.push(0);174 }175 let mut length = 1usize;176 while out.len() < count {177 let mut slots = vec![0usize; length];178 if allowed[0] == 0 {179 slots[0] = 1;180 if allowed.len() == 1 {181 return Ok(out);182 }183 }184 'level: loop {185 let mut value: u128 = 0;186 let mut fits = true;187 for &slot in &slots {188 match value189 .checked_mul(radix)190 .and_then(|v| v.checked_add(allowed[slot]))191 {192 Some(next) => value = next,193 None => {194 fits = false;195 break;196 }197 }198 }199 if !fits {200 return Ok(out);201 }202 out.push(value);203 if out.len() == count {204 return Ok(out);205 }206 for place in (0..length).rev() {207 slots[place] += 1;208 if slots[place] < allowed.len() {209 continue 'level;210 }211 slots[place] = usize::from(place == 0 && allowed[0] == 0);212 }213 break;214 }215 length += 1;216 if radix.checked_pow(length as u32 - 1).is_none() {217 return Ok(out);218 }219 }220 Ok(out)221}222223/// Counts the members of a design below the limit.224///225/// ```226/// use mrlyrs::math::bang::Code;227/// assert_eq!(mrlyrs::math::press::count_below(Code::from(0b0111u64), 2, 2, 27).unwrap(), 18);228/// ```229///230/// # Errors231///232/// Errors when the dimension and base reach a hundred and twenty-eight corners.233pub fn count_below(code: Code, dimension: usize, base: usize, limit: u128) -> Result<u128> {234 let radix = corner_count(dimension, base)? as u128;235 let allowed: Vec<u128> = (0..radix).filter(|&i| (code.get() >> i) & 1 == 1).collect();236 if limit == 0 || allowed.is_empty() {237 return Ok(0);238 }239 let mut digits = Vec::new();240 let mut rest = limit;241 while rest > 0 {242 digits.push(rest % radix);243 rest /= radix;244 }245 digits.reverse();246 let k = allowed.len() as u128;247 let lead = allowed.iter().filter(|&&v| v != 0).count() as u128;248 let mut total: u128 = if allowed[0] == 0 { 1 } else { 0 };249 let mut power: u128 = 1;250 for _ in 1..digits.len() {251 total += lead * power;252 power *= k;253 }254 for (place, &digit) in digits.iter().enumerate() {255 let below = allowed256 .iter()257 .filter(|&&v| v < digit && (place > 0 || v != 0))258 .count() as u128;259 let tail = digits.len() - place - 1;260 total += below * k.pow(tail as u32);261 if !allowed.contains(&digit) {262 break;263 }264 }265 Ok(total)266}267268/// The tally press: one pass over the integers weighs every design of a universe at once.269///270/// Each added number lands its weight in the bucket of its corner-usage mask, and a271/// design's total is the sum over the submasks of its code, so a single sweep prices272/// a Mertens sum, a member count or a prime count for all two to the corners designs.273#[derive(Serialize, Deserialize)]274pub struct Press {275 /// The design dimension of the universe.276 pub dimension: usize,277 /// The numeral base of the universe.278 pub base: usize,279 corners: usize,280 tallies: Vec<i128>,281}282283impl Press {284 /// Builds an empty press over every design of the dimension and base.285 ///286 /// ```287 /// use mrlyrs::math::bang::Code;288 /// let mut press = mrlyrs::math::press::Press::new(2, 2).unwrap();289 /// press.add(6, 1);290 /// assert_eq!((press.total(Code::from(6u64)), press.total(Code::from(1u64))), (1, 0));291 /// ```292 ///293 /// # Errors294 ///295 /// Errors past twenty corners, where the bucket table would leave a million rows.296 pub fn new(dimension: usize, base: usize) -> Result<Press> {297 let corners = corner_count(dimension, base)?;298 if corners > CORNERS {299 return value_error(format!(300 "the tally press holds at most {CORNERS} corners, not {corners}."301 ));302 }303 Ok(Press {304 dimension,305 base,306 corners,307 tallies: vec![0; 1 << corners],308 })309 }310 /// Adds a weighted number to its usage bucket.311 pub fn add(&mut self, number: u128, weight: i128) {312 self.tallies[mask(number, self.corners as u128).get() as usize] += weight;313 }314 /// Returns the total weight the design at a code has collected.315 pub fn total(&self, code: Code) -> i128 {316 let code = code.get();317 let mut sum = self.tallies[0];318 let mut sub = code;319 while sub != 0 {320 sum += self.tallies[sub as usize];321 sub = (sub - 1) & code;322 }323 sum324 }325 /// Returns every design's total in code order by one subset-sum transform.326 pub fn totals(&self) -> Vec<i128> {327 let mut out = self.tallies.clone();328 for bit in 0..self.corners {329 for mask in 0..out.len() {330 if mask >> bit & 1 == 1 {331 out[mask] += out[mask ^ (1 << bit)];332 }333 }334 }335 out336 }337}338339fn layer_radix(layer: &MagicLayer) -> u128 {340 (layer.number as u128).pow(layer.design.dim as u32)341}342343/// Returns the allowed digit table of one magic layer, one flag per cell of its tile.344///345/// A cell is allowed when its coordinate residues form a filled corner, which is the346/// tile the layer renders read as a digit alphabet.347///348/// # Errors349///350/// Errors when a layer's code is out of range.351pub fn layer_table(layer: &MagicLayer) -> Result<Vec<bool>> {352 let corners = code_to_corners(353 Code::from(layer.design.code),354 layer.design.dim,355 layer.design.base,356 )?;357 let dimension = layer.design.dim;358 let base = layer.design.base;359 let side = layer.number;360 let mut out = Vec::with_capacity(side.pow(dimension as u32));361 for cell in 0..side.pow(dimension as u32) {362 let mut rest = cell;363 let mut residue = vec![0u8; dimension];364 for axis in (0..dimension).rev() {365 residue[axis] = ((rest % side) % base) as u8;366 rest /= side;367 }368 out.push(corners.contains(&residue));369 }370 Ok(out)371}372373fn word_tables(layers: &[MagicLayer]) -> Result<Vec<Vec<bool>>> {374 if layers.is_empty() {375 return value_error("a word needs at least one layer.");376 }377 let dimension = layers[0].design.dim;378 if layers.iter().any(|l| l.design.dim != dimension) {379 return value_error("all word layers must have the same dimension.");380 }381 layers.iter().map(layer_table).collect()382}383384/// Counts the members of a magic word from its layer fills, without enumeration.385///386/// # Errors387///388/// Errors when a layer's code is out of range.389pub fn word_count(layers: &[MagicLayer]) -> Result<u128> {390 let tables = word_tables(layers)?;391 Ok(tables392 .iter()393 .map(|t| t.iter().filter(|&&b| b).count() as u128)394 .product())395}396397/// Returns whether the number lies in the magic word's composed design.398///399/// The number is read in the word's mixed radix, one digit per layer with the first400/// layer most significant, and every digit must land on an allowed cell of its tile.401/// A number past the word's domain is an error.402///403/// # Errors404///405/// Errors on a code out of range, or a number past the word's domain.406pub fn word_member(layers: &[MagicLayer], number: u128) -> Result<bool> {407 let tables = word_tables(layers)?;408 let mut rest = number;409 let mut ok = true;410 for (layer, table) in layers.iter().zip(&tables).rev() {411 let radix = layer_radix(layer);412 ok &= table[(rest % radix) as usize];413 rest /= radix;414 }415 if rest > 0 {416 return value_error(format!("number {number} lies past the word's domain."));417 }418 Ok(ok)419}420421/// Enumerates every member of the magic word in ascending order.422///423/// The member count is the product of the layer fills, so measure with `word_count`424/// before pressing a word too rich to hold.425///426/// # Errors427///428/// Errors when a layer's code is out of range.429pub fn word_members(layers: &[MagicLayer]) -> Result<Vec<u128>> {430 let tables = word_tables(layers)?;431 let alphabets: Vec<Vec<u128>> = tables432 .iter()433 .map(|t| {434 t.iter()435 .enumerate()436 .filter(|(_, &b)| b)437 .map(|(i, _)| i as u128)438 .collect()439 })440 .collect();441 if alphabets.iter().any(|a| a.is_empty()) {442 return Ok(Vec::new());443 }444 let radixes: Vec<u128> = layers.iter().map(layer_radix).collect();445 let mut out = Vec::new();446 let mut slots = vec![0usize; layers.len()];447 loop {448 let mut value: u128 = 0;449 for (place, &slot) in slots.iter().enumerate() {450 value = value * radixes[place] + alphabets[place][slot];451 }452 out.push(value);453 let mut place = layers.len();454 loop {455 if place == 0 {456 return Ok(out);457 }458 place -= 1;459 slots[place] += 1;460 if slots[place] < alphabets[place].len() {461 break;462 }463 slots[place] = 0;464 }465 }466}467468/// Returns the diagonal slice profile of a magic word by the substitution product.469///470/// The profile of a tile lists, per coordinate sum, its filled cells, and the profile471/// of a Kronecker word is the product of its layer profiles with strides, so no cell472/// of the composed design is ever enumerated.473///474/// # Errors475///476/// Errors when a layer's code is out of range.477pub fn word_profile(layers: &[MagicLayer]) -> Result<Vec<u128>> {478 let tables = word_tables(layers)?;479 let dimension = layers[0].design.dim;480 let mut out = vec![1u128];481 let mut stride: usize = 1;482 for (layer, table) in layers.iter().zip(&tables).rev() {483 let side = layer.number;484 let mut profile = vec![0u128; dimension * (side - 1) + 1];485 for (cell, &filled) in table.iter().enumerate() {486 if filled {487 let mut rest = cell;488 let mut total = 0usize;489 for _ in 0..dimension {490 total += rest % side;491 rest /= side;492 }493 profile[total] += 1;494 }495 }496 let mut next = vec![0u128; (profile.len() - 1) * stride + out.len()];497 for (i, &a) in profile.iter().enumerate() {498 if a == 0 {499 continue;500 }501 for (j, &b) in out.iter().enumerate() {502 next[i * stride + j] += a * b;503 }504 }505 out = next;506 stride *= side;507 }508 Ok(out)509}510511/// Returns the diagonal slice profile of one design pressed to a fractal level.512///513/// # Errors514///515/// Errors below level one, or on a code out of range.516pub fn profile(code: Code, dimension: usize, base: usize, level: usize) -> Result<Vec<u128>> {517 if level < 1 {518 return value_error("level must be at least 1.");519 }520 let layer = MagicLayer::new(521 crate::math::name::Bang::new(code.get(), dimension, base),522 base,523 );524 word_profile(&vec![layer; level])525}526527#[cfg(test)]528mod tests {529 use super::*;530 use crate::math::bang::factory::create;531 use crate::math::name::Bang;532533 #[test]534 fn usage_of_zero_is_the_zero_corner() {535 assert_eq!(usage(0, 2, 2).unwrap().get(), 1);536 assert_eq!(usage(0, 1, 10).unwrap().get(), 1);537 assert_eq!(distinct(0, 2, 2).unwrap(), 1);538 }539540 #[test]541 fn membership_matches_a_digit_check_at_base_ten() {542 let no_seven = Code(!(1u128 << 7) & ((1u128 << 10) - 1));543 for n in 0..10_000u128 {544 let digits_clean = !n.to_string().contains('7');545 assert_eq!(member(no_seven, n, 1, 10).unwrap(), digits_clean, "{n}");546 }547 }548549 #[test]550 fn members_of_the_repunit_design_are_the_mersenne_numbers() {551 assert_eq!(552 members(Code(0b10), 1, 2, 6).unwrap(),553 vec![1, 3, 7, 15, 31, 63]554 );555 }556557 #[test]558 fn members_walk_ascending_and_agree_with_membership() {559 for code in [Code(0b0111), Code(0b0110), Code(0b1001), Code(0b1111)] {560 let list = members(code, 2, 2, 40).unwrap();561 for pair in list.windows(2) {562 assert!(pair[0] < pair[1]);563 }564 let scanned: Vec<u128> = (0..200)565 .filter(|&n| member(code, n, 2, 2).unwrap())566 .collect();567 let shared = list.len().min(scanned.len());568 assert_eq!(list[..shared], scanned[..shared], "{code}");569 }570 }571572 #[test]573 fn count_below_agrees_with_the_member_walk() {574 for code in [575 Code(0b0111),576 Code(0b0110),577 Code(0b1011),578 Code(0b0001),579 Code(0b0000),580 ] {581 let list = members(code, 2, 2, 60).unwrap();582 for limit in 0..300u128 {583 let walked = list.iter().filter(|&&m| m < limit).count() as u128;584 if list.len() < 60 || walked < 60 {585 assert_eq!(586 count_below(code, 2, 2, limit).unwrap(),587 walked,588 "{code} {limit}"589 );590 }591 }592 }593 }594595 #[test]596 fn the_member_count_at_a_level_boundary_is_the_geometric_sum() {597 let code = Code(0b0111);598 let k: u128 = 3;599 for level in 1..6u32 {600 let boundary = 4u128.pow(level);601 let full: u128 = 1 + (k - 1) * (k.pow(level) - 1) / (k - 1);602 assert_eq!(count_below(code, 2, 2, boundary).unwrap(), full);603 }604 }605606 #[test]607 fn membership_matches_the_rendered_fractal() {608 for code in [Code(7), Code(6), Code(9), Code(11)] {609 let level = 3;610 let tile = create(code, 2, 2, 2, level).unwrap();611 let side = 1u128 << level;612 for n in 0..4u128.pow(level as u32) {613 let coords = coordinates(n, 2, 2).unwrap();614 let flat = (coords[0] * side + coords[1]) as usize;615 let filled = tile.bytes().unwrap()[flat] == 1;616 let padded = member(code, n, 2, 2).unwrap()617 && (code.get() & 1 == 1 || n >= 4u128.pow(level as u32 - 1));618 assert_eq!(padded, filled, "{code} {n}");619 }620 }621 }622623 #[test]624 fn coordinates_and_interleave_round_trip() {625 for n in 0..5_000u128 {626 assert_eq!(interleave(&coordinates(n, 2, 2).unwrap(), 2).unwrap(), n);627 assert_eq!(interleave(&coordinates(n, 3, 2).unwrap(), 2).unwrap(), n);628 assert_eq!(interleave(&coordinates(n, 2, 3).unwrap(), 3).unwrap(), n);629 }630 }631632 #[test]633 fn containing_counts_the_designs_that_hold_the_number() {634 for n in 0..500u128 {635 let direct = (0..16u128)636 .filter(|&code| member(Code(code), n, 2, 2).unwrap())637 .count();638 assert_eq!(containing(n, 2, 2).unwrap(), direct as u128, "{n}");639 }640 }641642 #[test]643 fn the_membership_average_over_all_designs_is_two_to_minus_distinct() {644 for n in 0..2_000u128 {645 assert_eq!(646 containing(n, 2, 2).unwrap(),647 1 << (4 - distinct(n, 2, 2).unwrap())648 );649 assert_eq!(650 containing(n, 3, 2).unwrap(),651 1 << (8 - distinct(n, 3, 2).unwrap())652 );653 }654 }655656 #[test]657 fn the_press_totals_agree_with_direct_member_sums() {658 let mut press = Press::new(2, 2).unwrap();659 let weights: Vec<i128> = (0..600).map(|n| (n as i128 % 7) - 3).collect();660 for (n, &w) in weights.iter().enumerate() {661 press.add(n as u128, w);662 }663 let totals = press.totals();664 for code in 0..16u128 {665 let direct: i128 = weights666 .iter()667 .enumerate()668 .filter(|(n, _)| member(Code(code), *n as u128, 2, 2).unwrap())669 .map(|(_, &w)| w)670 .sum();671 assert_eq!(press.total(Code(code)), direct, "{code}");672 assert_eq!(totals[code as usize], direct, "{code}");673 }674 }675676 #[test]677 fn a_native_word_is_the_stationary_press() {678 let layer = MagicLayer::new(Bang::new(7, 2, 2), 2);679 let word = vec![layer; 3];680 for n in 0..64u128 {681 let padded = member(Code(7), n, 2, 2).unwrap();682 assert_eq!(word_member(&word, n).unwrap(), padded, "{n}");683 }684 assert_eq!(word_count(&word).unwrap(), 27);685 }686687 #[test]688 fn word_members_match_the_magic_tensor() {689 let word = [690 MagicLayer::new(Bang::new(7, 2, 2), 3),691 MagicLayer::new(Bang::new(14, 2, 2), 5),692 ];693 let tensor = crate::math::bang::factory::magic(&word).unwrap();694 let side = 15u128;695 let list = word_members(&word).unwrap();696 assert_eq!(list.len() as u128, word_count(&word).unwrap());697 for n in 0..word.iter().map(layer_radix).product::<u128>() {698 let mut rest = n;699 let mut x = 0u128;700 let mut y = 0u128;701 let mut place = 1u128;702 for layer in word.iter().rev() {703 let cell = rest % layer_radix(layer);704 rest /= layer_radix(layer);705 let s = layer.number as u128;706 x += (cell / s) * place;707 y += (cell % s) * place;708 place *= s;709 }710 let filled = tensor.bytes().unwrap()[(x * side + y) as usize] == 1;711 assert_eq!(word_member(&word, n).unwrap(), filled, "{n}");712 assert_eq!(list.contains(&n), filled, "{n}");713 }714 }715716 #[test]717 fn word_profiles_match_the_rendered_diagonal_sums() {718 let word = [719 MagicLayer::new(Bang::new(7, 2, 2), 3),720 MagicLayer::new(Bang::new(14, 2, 2), 5),721 ];722 let tensor = crate::math::bang::factory::magic(&word).unwrap();723 let side = 15usize;724 let mut direct = vec![0u128; 2 * side - 1];725 for (flat, &b) in tensor.bytes().unwrap().iter().enumerate() {726 if b == 1 {727 direct[flat / side + flat % side] += 1;728 }729 }730 assert_eq!(word_profile(&word).unwrap(), direct);731 }732733 #[test]734 fn profile_totals_are_the_fill_powers() {735 let native = profile(Code(7), 2, 2, 4).unwrap();736 assert_eq!(native.iter().sum::<u128>(), 3u128.pow(4));737 let sponge = vec![MagicLayer::new(Bang::new(23, 3, 2), 3); 3];738 let classic = word_profile(&sponge).unwrap();739 assert_eq!(classic.iter().sum::<u128>(), 20u128.pow(3));740 }741742 #[test]743 fn refuses_a_universe_past_its_corners_and_an_empty_weave() {744 assert!(Press::new(5, 2).is_err());745 assert!(Press::new(7, 2).is_err());746 assert!(usage(1, 7, 2).is_err());747 assert!(member(Code(1), 1, 7, 2).is_err());748 assert!(distinct(1, 7, 2).is_err());749 assert!(containing(1, 7, 2).is_err());750 assert!(coordinates(1, 7, 2).is_err());751 assert!(members(Code(1), 7, 2, 1).is_err());752 assert!(count_below(Code(1), 7, 2, 4).is_err());753 assert!(interleave(&[], 2).is_err());754 assert!(interleave(&[u128::MAX, u128::MAX], 2).is_err());755 }756757 #[test]758 fn refuses_a_word_of_mismatched_dimensions_or_a_number_past_its_domain() {759 let plane = MagicLayer::new(Bang::new(7, 2, 2), 3);760 let cube = MagicLayer::new(Bang::new(23, 3, 2), 3);761 assert!(word_member(&[plane.clone(), cube], 0).is_err());762 assert!(word_member(&[plane], 9).is_err());763 assert!(word_member(&[], 0).is_err());764 }765}