spiral.rs
24.0 kB · rust · 682 lines
1use crate::factor::mobius_sieve;2use crate::prime::{is_prime, Sieve};34const HEX: [(i64, i64); 6] = [(1, 0), (1, -1), (0, -1), (-1, 0), (-1, 1), (0, 1)];56/// The two lattices a spiral of the whole numbers is wound on, one at the centre and two to its right.7#[derive(Clone, Copy, Debug, PartialEq, Eq)]8pub enum Lattice {9 /// Unit squares turning anticlockwise with y up: ring k holds 8k cells and ends at the odd square (2k + 1)^2 on the diagonal below right.10 Square,11 /// Hexagons in axial coordinates q and r, r growing downward: ring r holds 6r cells and ends at the centered hexagonal number 3r^2 + 3r + 1 below right of the centre.12 Hex,13}1415impl Lattice {16 /// Reads a lattice from its name.17 pub fn named(name: &str) -> Option<Lattice> {18 match name {19 "square" => Some(Lattice::Square),20 "hex" => Some(Lattice::Hex),21 _ => None,22 }23 }24 /// Returns the outermost ring of a sheet the odd side wide, half the side rounded down.25 pub fn radius(self, side: usize) -> usize {26 side.saturating_sub(1) / 227 }28 /// Returns the count of numbers a sheet the odd side wide holds: the side squared, or the hexagon of that many cells across.29 pub fn count(self, side: usize) -> usize {30 let r = self.radius(side);31 match self {32 Lattice::Square => (2 * r + 1) * (2 * r + 1),33 Lattice::Hex => 3 * r * r + 3 * r + 1,34 }35 }36 /// Returns the ring a number sits on, zero for one.37 pub fn ring(self, n: u64) -> u64 {38 if n < 2 {39 return 0;40 }41 match self {42 Lattice::Square => (n - 1).isqrt().div_ceil(2),43 Lattice::Hex => {44 let mut r = ((12 * n - 3).isqrt() - 3) / 6;45 while 3 * r * r + 3 * r + 1 < n {46 r += 1;47 }48 r49 }50 }51 }52 /// Returns the ring of a cell: the larger of the coordinates on the square, the hex distance on the hexagon.53 pub fn ring_of(self, x: i64, y: i64) -> u64 {54 match self {55 Lattice::Square => x.abs().max(y.abs()) as u64,56 Lattice::Hex => x.abs().max(y.abs()).max((x + y).abs()) as u64,57 }58 }59 /// Returns the cell of a number: x right and y up on the square, axial q and r on the hexagon.60 ///61 /// ```62 /// use mrlynum::spiral::Lattice;63 /// assert_eq!(Lattice::Square.xy(10), (2, -1));64 /// assert_eq!(Lattice::Hex.xy(8), (1, 1));65 /// ```66 pub fn xy(self, n: u64) -> (i64, i64) {67 let k = self.ring(n) as i64;68 if k == 0 {69 return (0, 0);70 }71 let n = n as i64;72 match self {73 Lattice::Square => {74 let m = (2 * k + 1) * (2 * k + 1);75 if n >= m - 2 * k {76 (k - (m - n), -k)77 } else if n >= m - 4 * k {78 (-k, -k + (m - 2 * k - n))79 } else if n >= m - 6 * k {80 (-k + (m - 4 * k - n), k)81 } else {82 (k, k - (m - 6 * k - n))83 }84 }85 Lattice::Hex => {86 let i = n - (3 * k * k - 3 * k + 1) - 1;87 let (side, step) = ((i / k) as usize, i % k + 1);88 let (cq, cr) = HEX[(side + 5) % 6];89 let (dq, dr) = HEX[(side + 1) % 6];90 (k * cq + step * dq, k * cr + step * dr)91 }92 }93 }94 /// Returns the number at a cell, one at the origin.95 ///96 /// ```97 /// use mrlynum::spiral::Lattice;98 /// assert_eq!(Lattice::Square.n(2, -2), 25);99 /// assert_eq!(Lattice::Hex.n(0, 2), 19);100 /// ```101 pub fn n(self, x: i64, y: i64) -> u64 {102 let k = self.ring_of(x, y) as i64;103 if k == 0 {104 return 1;105 }106 let n = match self {107 Lattice::Square => {108 let m = (2 * k + 1) * (2 * k + 1);109 if y == -k {110 m - k + x111 } else if x == -k {112 m - 3 * k - y113 } else if y == k {114 m - 5 * k - x115 } else {116 m - 7 * k + y117 }118 }119 Lattice::Hex => {120 let base = 3 * k * k - 3 * k + 1;121 let (side, step) = if x > 0 && y >= 0 && x + y == k {122 (0, x)123 } else if x == k {124 (1, -y)125 } else if y == -k && x >= 0 {126 (2, k - x)127 } else if x + y == -k && x < 0 {128 (3, -x)129 } else if x == -k {130 (4, y)131 } else {132 (5, x + k)133 };134 base + side * k + step135 }136 };137 n as u64138 }139}140141/// What a cell is painted for.142#[derive(Clone, Copy, Debug, PartialEq, Eq)]143pub enum Mark {144 /// The primes.145 Prime,146 /// The primes with a prime two away.147 Twin,148 /// The numbers no prime squares into.149 Squarefree,150 /// The Mobius value: one, minus one, or zero for a squared factor.151 Mobius,152}153154impl Mark {155 /// Reads a mark from its name.156 pub fn named(name: &str) -> Option<Mark> {157 match name {158 "prime" => Some(Mark::Prime),159 "twin" => Some(Mark::Twin),160 "squarefree" => Some(Mark::Squarefree),161 "mobius" => Some(Mark::Mobius),162 _ => None,163 }164 }165}166167/// Returns whether every number from zero through the limit is prime, by one sieve.168pub fn flags(limit: usize) -> Vec<bool> {169 let mut sieve = Sieve::new(limit);170 sieve.finish();171 sieve.types().iter().map(|&t| t == 1).collect()172}173174/// Marks every number from zero through the limit: one when marked, minus one for a Mobius value of minus one, else zero.175///176/// ```177/// assert_eq!(mrlynum::spiral::marks(mrlynum::spiral::Mark::Mobius, 6), vec![0, 1, -1, -1, 0, -1, 1]);178/// ```179pub fn marks(mark: Mark, limit: usize) -> Vec<i8> {180 match mark {181 Mark::Prime => flags(limit).iter().map(|&p| i8::from(p)).collect(),182 Mark::Twin => {183 let prime = flags(limit);184 (0..=limit)185 .map(|n| {186 let twin = (n >= 2 && prime[n - 2]) || is_prime(n + 2);187 i8::from(prime[n] && twin)188 })189 .collect()190 }191 Mark::Squarefree => mobius_sieve(limit)192 .iter()193 .map(|&m| i8::from(m != 0))194 .collect(),195 Mark::Mobius => mobius_sieve(limit),196 }197}198199/// The readout of one quadratic a k^2 + b k + c across a sheet: where it lands and how often on a prime.200#[derive(Clone, Debug, PartialEq)]201pub struct Diagonal {202 /// The count of numbers the sheet holds.203 pub top: usize,204 /// The count of primes among them.205 pub primes: usize,206 /// The primes as a share of the numbers.207 pub density: f64,208 /// The values of the quadratic inside the sheet, k counting up from zero.209 pub values: Vec<u64>,210 /// The cell of each value.211 pub cells: Vec<(i64, i64)>,212 /// Whether each value is prime.213 pub hit: Vec<bool>,214 /// The count of values that are prime.215 pub hits: usize,216 /// The count of primes before the first composite.217 pub streak: usize,218 /// The hits as a share of the values, zero when the quadratic misses the sheet.219 pub share: f64,220}221222/// Reads the quadratic a k^2 + b k + c, a at least one, over the sheet the odd side wide: every value from one through the top, its cell, the prime hits and the opening streak.223///224/// ```225/// let read = mrlynum::spiral::diagonal(mrlynum::spiral::Lattice::Square, 201, 4, -2, 41);226/// assert_eq!((read.top, read.streak), (40401, 21));227/// ```228pub fn diagonal(lattice: Lattice, side: usize, a: i64, b: i64, c: i64) -> Diagonal {229 let top = lattice.count(side);230 let prime = flags(top);231 let mut values = Vec::new();232 let mut k = 0i64;233 while k <= b.abs() + side as i64 + 2 {234 let v = a * k * k + b * k + c;235 if v >= 1 && v <= top as i64 {236 values.push(v as u64);237 }238 if v > top as i64 && 2 * a * k + b >= 0 {239 break;240 }241 k += 1;242 }243 let cells = values.iter().map(|&v| lattice.xy(v)).collect();244 let hit: Vec<bool> = values.iter().map(|&v| prime[v as usize]).collect();245 let primes = prime.iter().filter(|&&p| p).count();246 let hits = hit.iter().filter(|&&h| h).count();247 Diagonal {248 top,249 primes,250 density: primes as f64 / top.max(1) as f64,251 share: if hit.is_empty() {252 0.0253 } else {254 hits as f64 / hit.len() as f64255 },256 hits,257 streak: hit.iter().take_while(|&&h| h).count(),258 values,259 cells,260 hit,261 }262}263264/// Which cells of the square winding grow into a tile.265#[derive(Clone, Copy, Debug, PartialEq, Eq)]266pub enum Growth {267 /// Only the primes grow; one and every composite stay unit cells.268 Prime,269 /// Every number grows.270 Every,271}272273impl Growth {274 /// Reads a growth from its name.275 pub fn named(name: &str) -> Option<Growth> {276 match name {277 "prime" => Some(Growth::Prime),278 "every" => Some(Growth::Every),279 _ => None,280 }281 }282}283284/// One tile of the snail: the number it stands for, its level, the side of its square, whether the number is prime, and the lower-left corner it is laid at.285#[derive(Clone, Copy, Debug, PartialEq, Eq)]286pub struct Tile {287 /// The number the tile stands for.288 pub n: u64,289 /// The level the design is grown to.290 pub level: u32,291 /// The side of the tile, the base raised to the level.292 pub side: u64,293 /// Whether the number is prime.294 pub prime: bool,295 /// The x of the lower-left corner.296 pub x: i64,297 /// The y of the lower-left corner.298 pub y: i64,299}300301/// The snail: every tile of the winding, the tallies, the area drawn and the box filled.302#[derive(Clone, Debug, PartialEq)]303pub struct Snail {304 /// The base every tile side is a power of.305 pub base: u64,306 /// Every tile, in the order one, two, three and on.307 pub tiles: Vec<Tile>,308 /// The count of primes at or below the top.309 pub primes: usize,310 /// The count of tiles at each level, from zero up.311 pub levels: Vec<usize>,312 /// The sum of the tile areas, a tile counted once wherever it overlaps another.313 pub area: u128,314 /// The lower-left corner of the box the tiles fill.315 pub low: (i64, i64),316 /// The upper-right corner of the box the tiles fill.317 pub high: (i64, i64),318}319320/// Returns the level of a number in a base, the count of its digits less one, so zero below the base and one at the base itself.321///322/// ```323/// use mrlynum::spiral::level_of;324/// assert_eq!((level_of(1, 3), level_of(2, 3), level_of(3, 3), level_of(8, 3), level_of(9, 3)), (0, 0, 1, 1, 2));325/// ```326pub fn level_of(n: u64, base: u64) -> u32 {327 let base = base.max(2);328 let (mut level, mut reach) = (0, base);329 while reach <= n {330 reach *= base;331 level += 1;332 }333 level334}335336/// Winds one to the top on the square spiral and lays a square tile on every cell, the snail.337///338/// The tile of n has side base to the level of n when n grows and side one when it does not, and its lower-left corner is the corner of the tile before it plus one unit step of the winding scaled by the side of that earlier tile. Tiles overlap wherever the growth outruns the winding; a base below two is read as two and a top below one as one.339///340/// ```341/// use mrlynum::spiral::{snail, Growth};342/// let shell = snail(3, 9, Growth::Every);343/// assert_eq!(shell.tiles[0].side, 1);344/// assert_eq!(shell.tiles[8].side, 9);345/// ```346pub fn snail(base: u64, top: u64, growth: Growth) -> Snail {347 let base = base.max(2);348 let top = top.max(1);349 let prime = flags(top as usize);350 let mut tiles = Vec::with_capacity(top as usize);351 let mut levels = vec![0usize; level_of(top, base) as usize + 1];352 let (mut x, mut y) = (0i64, 0i64);353 let (mut low, mut high) = ((0i64, 0i64), (0i64, 0i64));354 let mut area = 0u128;355 let mut cell = (0i64, 0i64);356 for n in 1..=top {357 let is_prime = prime[n as usize];358 let level = if growth == Growth::Every || is_prime {359 level_of(n, base)360 } else {361 0362 };363 let side = base.pow(level);364 levels[level as usize] += 1;365 area += u128::from(side) * u128::from(side);366 low = (low.0.min(x), low.1.min(y));367 high = (high.0.max(x + side as i64), high.1.max(y + side as i64));368 tiles.push(Tile {369 n,370 level,371 side,372 prime: is_prime,373 x,374 y,375 });376 let next = Lattice::Square.xy(n + 1);377 x += (next.0 - cell.0) * side as i64;378 y += (next.1 - cell.1) * side as i64;379 cell = next;380 }381 Snail {382 base,383 tiles,384 primes: prime.iter().filter(|&&p| p).count(),385 levels,386 area,387 low,388 high,389 }390}391392#[cfg(test)]393mod tests {394 use super::*;395 use crate::classics::primes;396 use crate::factor::{mobius, squarefree};397398 #[test]399 fn the_square_spiral_pins_the_first_rings() {400 let first: Vec<(i64, i64)> = (1..=10).map(|n| Lattice::Square.xy(n)).collect();401 assert_eq!(402 first,403 vec![404 (0, 0),405 (1, 0),406 (1, 1),407 (0, 1),408 (-1, 1),409 (-1, 0),410 (-1, -1),411 (0, -1),412 (1, -1),413 (2, -1)414 ]415 );416 assert_eq!(Lattice::Square.xy(25), (2, -2));417 assert_eq!(Lattice::Square.xy(0), (0, 0));418 for k in 1..=30u64 {419 let odd = (2 * k + 1) * (2 * k + 1);420 assert_eq!(Lattice::Square.xy(odd), (k as i64, -(k as i64)));421 assert_eq!(Lattice::Square.ring(odd), k);422 assert_eq!(Lattice::Square.ring(odd + 1), k + 1);423 }424 }425426 #[test]427 fn the_hex_spiral_pins_the_first_rings() {428 let first: Vec<(i64, i64)> = (1..=8).map(|n| Lattice::Hex.xy(n)).collect();429 assert_eq!(430 first,431 vec![432 (0, 0),433 (1, 0),434 (1, -1),435 (0, -1),436 (-1, 0),437 (-1, 1),438 (0, 1),439 (1, 1)440 ]441 );442 assert_eq!(Lattice::Hex.ring(8), 2);443 assert_eq!((Lattice::Hex.xy(19), Lattice::Hex.ring(19)), ((0, 2), 2));444 assert_eq!((Lattice::Hex.xy(20), Lattice::Hex.ring(20)), ((1, 2), 3));445 for r in 1..=30u64 {446 let last = 3 * r * r + 3 * r + 1;447 assert_eq!(Lattice::Hex.xy(last), (0, r as i64));448 assert_eq!(Lattice::Hex.ring(last), r);449 assert_eq!(Lattice::Hex.ring(last + 1), r + 1);450 }451 }452453 #[test]454 fn both_spirals_walk_neighbours_and_map_back() {455 for lattice in [Lattice::Square, Lattice::Hex] {456 let mut last = (0, 0);457 let mut on_ring = vec![0u64; 200];458 for n in 1..=100_000u64 {459 let (x, y) = lattice.xy(n);460 assert_eq!(lattice.n(x, y), n, "{lattice:?} {n}");461 let ring = lattice.ring(n);462 assert_eq!(lattice.ring_of(x, y), ring, "{lattice:?} {n}");463 on_ring[ring as usize] += 1;464 if n > 1 {465 let step = (x - last.0, y - last.1);466 let near = match lattice {467 Lattice::Square => step.0.abs() + step.1.abs() == 1,468 Lattice::Hex => HEX.contains(&step),469 };470 assert!(near, "{lattice:?} {n}");471 }472 last = (x, y);473 }474 let per = match lattice {475 Lattice::Square => 8,476 Lattice::Hex => 6,477 };478 for (r, &count) in on_ring.iter().enumerate().take(51).skip(1) {479 assert_eq!(count, per * r as u64, "{lattice:?} ring {r}");480 }481 }482 }483484 #[test]485 fn the_sheet_counts_agree_with_the_rings() {486 assert_eq!(Lattice::Square.count(201), 40401);487 assert_eq!(Lattice::Square.count(401), 160801);488 assert_eq!(Lattice::Hex.count(401), 120601);489 assert_eq!(Lattice::Hex.radius(401), 200);490 assert_eq!((Lattice::Hex.count(1), Lattice::Hex.count(0)), (1, 1));491 for side in (1..=101).step_by(2) {492 for lattice in [Lattice::Square, Lattice::Hex] {493 let top = lattice.count(side) as u64;494 assert_eq!(lattice.ring(top), lattice.radius(side) as u64);495 assert_eq!(lattice.ring(top + 1), lattice.radius(side) as u64 + 1);496 }497 }498 assert_eq!(Lattice::named("hex"), Some(Lattice::Hex));499 assert_eq!(Lattice::named("cube"), None);500 assert_eq!(Mark::named("twin"), Some(Mark::Twin));501 assert_eq!(Mark::named("odd"), None);502 }503504 #[test]505 fn the_marks_agree_with_the_single_tests() {506 let limit = 3_000;507 let prime = marks(Mark::Prime, limit);508 let twin = marks(Mark::Twin, limit);509 let free = marks(Mark::Squarefree, limit);510 let mu = marks(Mark::Mobius, limit);511 for n in 0..=limit {512 assert_eq!(prime[n] == 1, is_prime(n), "{n}");513 let pair = is_prime(n) && (is_prime(n + 2) || (n >= 2 && is_prime(n - 2)));514 assert_eq!(twin[n] == 1, pair, "{n}");515 assert_eq!(free[n] == 1, squarefree(n), "{n}");516 assert_eq!(mu[n], mobius(n), "{n}");517 }518 assert_eq!(519 marks(Mark::Prime, 40_000)520 .iter()521 .filter(|&&m| m == 1)522 .count(),523 4203524 );525 assert_eq!(526 marks(Mark::Prime, 40_401)527 .iter()528 .filter(|&&m| m == 1)529 .count(),530 primes(40_401).len()531 );532 assert_eq!(marks(Mark::Twin, 30)[19], 1);533 assert_eq!(marks(Mark::Twin, 30)[23], 0);534 }535536 #[test]537 fn eulers_quadratic_opens_with_twenty_one_primes_on_one_line() {538 let read = diagonal(Lattice::Square, 201, 4, -2, 41);539 assert_eq!((read.top, read.primes), (40401, primes(40401).len()));540 assert_eq!(read.values.len(), 101);541 assert_eq!(read.streak, 21);542 for (k, &v) in read.values.iter().enumerate() {543 let m = 2 * k as u64;544 assert_eq!(v, m * m - m + 41);545 }546 assert_eq!(read.values[21], 1763);547 assert!(!is_prime(1763));548 let direct = read549 .values550 .iter()551 .filter(|&&v| is_prime(v as usize))552 .count();553 assert_eq!(read.hits, direct);554 assert_eq!(read.hits, 80);555 assert_eq!(read.hit.iter().filter(|&&h| h).count(), 80);556 assert!(!read.hit[21]);557 assert!((read.density - read.primes as f64 / 40401.0).abs() < 1e-12);558 assert!((read.share - 80.0 / 101.0).abs() < 1e-12);559 assert_eq!(diagonal(Lattice::Square, 21, 1, 0, 500).share, 0.0);560 for k in 20..=100 {561 assert_eq!(read.cells[k], (k as i64 - 40, k as i64), "{k}");562 }563 let spoke = diagonal(Lattice::Hex, 41, 3, 3, 1);564 assert_eq!(spoke.values.len(), 21);565 for (k, &cell) in spoke.cells.iter().enumerate() {566 assert_eq!(cell, (0, k as i64));567 }568 let dip = diagonal(Lattice::Square, 21, 1, -30, 2);569 assert_eq!(570 dip.values,571 vec![2, 2, 33, 66, 101, 138, 177, 218, 261, 306, 353, 402]572 );573 assert!(diagonal(Lattice::Square, 21, 1, 0, 500).values.is_empty());574 }575 #[test]576 fn the_snail_lays_its_tiles_along_the_winding() {577 let placed = |shell: &Snail| -> Vec<(u64, u32, u64, bool, i64, i64)> {578 shell579 .tiles580 .iter()581 .take(12)582 .map(|t| (t.n, t.level, t.side, t.prime, t.x, t.y))583 .collect()584 };585 let every = snail(3, 100, Growth::Every);586 assert_eq!(587 placed(&every),588 vec![589 (1, 0, 1, false, 0, 0),590 (2, 0, 1, true, 1, 0),591 (3, 1, 3, true, 1, 1),592 (4, 1, 3, false, -2, 1),593 (5, 1, 3, true, -5, 1),594 (6, 1, 3, false, -5, -2),595 (7, 1, 3, true, -5, -5),596 (8, 1, 3, false, -2, -5),597 (9, 2, 9, false, 1, -5),598 (10, 2, 9, false, 10, -5),599 (11, 2, 9, true, 10, 4),600 (12, 2, 9, false, 10, 13),601 ]602 );603 let prime = snail(3, 100, Growth::Prime);604 assert_eq!(605 placed(&prime),606 vec![607 (1, 0, 1, false, 0, 0),608 (2, 0, 1, true, 1, 0),609 (3, 1, 3, true, 1, 1),610 (4, 0, 1, false, -2, 1),611 (5, 1, 3, true, -3, 1),612 (6, 0, 1, false, -3, -2),613 (7, 1, 3, true, -3, -3),614 (8, 0, 1, false, 0, -3),615 (9, 0, 1, false, 1, -3),616 (10, 0, 1, false, 2, -3),617 (11, 2, 9, true, 2, -2),618 (12, 0, 1, false, 2, 7),619 ]620 );621 assert_eq!((every.area, prime.area), (172_100, 29_668));622 assert_eq!(every.levels, vec![2, 6, 18, 54, 20]);623 assert_eq!(prime.levels, vec![76, 3, 5, 13, 3]);624 assert_eq!((every.primes, prime.primes), (25, 25));625 assert_eq!((every.low, every.high), ((-602, -86), (208, 724)));626 assert_eq!((prime.low, prime.high), ((-58, -66), (112, 184)));627 }628629 #[test]630 fn the_snail_grows_by_the_digit_law_and_never_leaves_its_box() {631 for base in [2u64, 3, 5, 7] {632 for growth in [Growth::Every, Growth::Prime] {633 let shell = snail(base, 400, growth);634 assert_eq!(shell.base, base);635 assert_eq!(shell.tiles.len(), 400);636 assert_eq!(shell.levels.iter().sum::<usize>(), 400);637 assert_eq!(shell.levels.len(), level_of(400, base) as usize + 1);638 let mut area = 0u128;639 for (at, tile) in shell.tiles.iter().enumerate() {640 let n = at as u64 + 1;641 assert_eq!(tile.n, n);642 assert_eq!(tile.prime, is_prime(n as usize), "{base} {n}");643 let level = if growth == Growth::Every || tile.prime {644 level_of(n, base)645 } else {646 0647 };648 assert_eq!(649 (tile.level, tile.side),650 (level, base.pow(level)),651 "{base} {n}"652 );653 assert!(tile.x >= shell.low.0 && tile.y >= shell.low.1);654 assert!(tile.x + tile.side as i64 <= shell.high.0);655 assert!(tile.y + tile.side as i64 <= shell.high.1);656 area += u128::from(tile.side) * u128::from(tile.side);657 if at == 0 {658 assert_eq!((tile.x, tile.y), (0, 0));659 continue;660 }661 let last = shell.tiles[at - 1];662 let step = (663 Lattice::Square.xy(n).0 - Lattice::Square.xy(n - 1).0,664 Lattice::Square.xy(n).1 - Lattice::Square.xy(n - 1).1,665 );666 assert_eq!(step.0.abs() + step.1.abs(), 1, "{base} {n}");667 assert_eq!(tile.x, last.x + step.0 * last.side as i64, "{base} {n}");668 assert_eq!(tile.y, last.y + step.1 * last.side as i64, "{base} {n}");669 }670 assert_eq!(shell.area, area);671 }672 }673 assert_eq!(level_of(1, 10), 0);674 assert_eq!(level_of(999, 10), 2);675 assert_eq!(level_of(1000, 10), 3);676 assert_eq!(level_of(5, 1), level_of(5, 2));677 assert_eq!(snail(1, 0, Growth::Every).tiles.len(), 1);678 assert_eq!(Growth::named("prime"), Some(Growth::Prime));679 assert_eq!(Growth::named("every"), Some(Growth::Every));680 assert_eq!(Growth::named("some"), None);681 }682}