records.rs

18.6 kB · rust · 249 lines

1use super::{Axis, Key, Measure, Tag};2use std::sync::OnceLock;34/// One OEIS entry the tree cites, with the design sequence it names when it names one.5#[derive(Clone, Copy, Debug, PartialEq, Eq)]6pub struct Record {7    /// The OEIS id.8    pub id: &'static str,9    /// The entry's name.10    pub name: &'static str,11    /// The index of the first listed term.12    pub offset: i32,13    /// The record's index less the ledger's, where a key names the sequence.14    pub shift: i32,15    /// The first terms, as text.16    pub terms: &'static str,17    /// The status of the identification.18    pub status: Tag,19    /// The design sequence the entry names, when it names one.20    pub key: Option<Key>,21    /// The formula, or none.22    pub formula: &'static str,23    /// The generator or page that witnesses the entry.24    pub witness: &'static str,25}2627const fn record(28    id: &'static str,29    name: &'static str,30    offset: i32,31    terms: &'static str,32    status: Tag,33    formula: &'static str,34    witness: &'static str,35) -> Record {36    Record {37        id,38        name,39        offset,40        shift: 0,41        terms,42        status,43        key: None,44        formula,45        witness,46    }47}4849impl Record {50    const fn keyed(51        self,52        code: u128,53        dimension: usize,54        measure: Measure,55        axis: Axis,56        shift: i32,57    ) -> Record {58        Record {59            shift,60            key: Some(Key::new(code, dimension, 2, measure, axis)),61            ..self62        }63    }64}6566const FILLS: &str = "mrlymath::formulas::fill";67const SIDES: &str = "mrlylab::ledger::terms, the odd-side law";68const EXPOSURE: &str = "mrlymath::formulas::exposure";6970/// Every OEIS entry the tree cites, by id.71pub static RECORDS: &[Record] = &[72    record("A000029", "Number of necklaces with n beads of 2 colors, allowing turning over (bracelets)", 0, "1, 2, 3, 4, 6, 8, 13, 18, 30, 46, 78, 126", Tag::Verified, "none", "mrlymath::bang::baseq::bracelets, the base line at dim 1"),73    record("A000070", "a(n) = Sum_{k=0..n} p(k) where p(k) = number of partitions of k", 0, "1, 2, 4, 7, 12, 19, 30, 45, 67, 97, 139, 195", Tag::Verified, "none", "REFS.md"),74    record("A000244", "Powers of 3: a(n) = 3^n", 0, "1, 3, 9, 27, 81, 243, 729, 2187, 6561, 19683, 59049, 177147", Tag::Proved, "3^level", "mrlymath::three::diagonal, every admissible cut of bang dim 3, code 126 at side 2"),75    record("A000290", "The squares: a(n) = n^2", 0, "0, 1, 4, 9, 16, 25, 36, 49, 64, 81, 100, 121", Tag::Proved, "k^2", SIDES).keyed(1, 2, Measure::Fills, Axis::Side, 0),76    record("A000351", "Powers of 5: a(n) = 5^n", 0, "1, 5, 25, 125, 625, 3125, 15625, 78125, 390625, 1953125, 9765625, 48828125", Tag::Proved, "5^level", FILLS).keyed(9, 2, Measure::Fills, Axis::Level, 0),77    record("A000370", "Number of NPN-equivalence classes of Boolean functions of n or fewer variables", 0, "1, 2, 4, 14, 222, 616126, 200253952527184", Tag::Verified, "none", "bijection.md, the NPN sibling at dim 1..4"),78    record("A000384", "Hexagonal numbers: a(n) = n*(2*n-1)", 0, "0, 1, 6, 15, 28, 45, 66, 91, 120, 153, 190, 231", Tag::Proved, "k(2k - 1)", SIDES).keyed(3, 2, Measure::Fills, Axis::Side, 0),79    record("A000420", "Powers of 7: a(n) = 7^n", 0, "1, 7, 49, 343, 2401, 16807, 117649, 823543, 5764801, 40353607, 282475249, 1977326743", Tag::Proved, "7^level", FILLS).keyed(11, 2, Measure::Fills, Axis::Level, 0),80    record("A000567", "Octagonal numbers: n*(3*n-2)", 0, "0, 1, 8, 21, 40, 65, 96, 133, 176, 225, 280, 341", Tag::Proved, "k(3k - 2)", SIDES).keyed(7, 2, Measure::Fills, Axis::Side, 0),81    record("A000578", "The cubes: a(n) = n^3", 0, "0, 1, 8, 27, 64, 125, 216, 343, 512, 729, 1000, 1331", Tag::Proved, "k^3", SIDES).keyed(1, 3, Measure::Fills, Axis::Side, 0),82    record("A000616", "a(-1)=1 by convention; for n >= 0, a(n) = number of irreducible Boolean functions of n variables", -1, "1, 2, 3, 6, 22, 402, 1228158, 400507806843728", Tag::Proved, "none", "mrlymath::bang::counting::sequence, bijection.md"),83    record("A001018", "Powers of 8: a(n) = 8^n", 0, "1, 8, 64, 512, 4096, 32768, 262144, 2097152, 16777216, 134217728, 1073741824, 8589934592", Tag::Proved, "8^level", FILLS).keyed(7, 2, Measure::Fills, Axis::Level, 0),84    record("A001024", "Powers of 15: a(n) = 15^n", 0, "1, 15, 225, 3375, 50625, 759375, 11390625, 170859375, 2562890625, 38443359375", Tag::Verified, "15^n", "REFS.md"),85    record("A001316", "Gould's sequence: number of odd entries in row n of Pascal's triangle", 0, "1, 2, 2, 4, 2, 4, 4, 8, 2, 4, 4, 8", Tag::Verified, "2^wt(n)", "REFS.md"),86    record("A001481", "Numbers that are the sum of 2 squares", 1, "0, 1, 2, 4, 5, 8, 9, 10, 13, 16, 17, 18", Tag::Verified, "none", "spin.md, the ring radii of a spun square lattice"),87    record("A001844", "Centered square numbers: a(n) = 2*n*(n+1)+1", 0, "1, 5, 13, 25, 41, 61, 85, 113, 145, 181, 221, 265", Tag::Proved, "2k^2 - 2k + 1", SIDES).keyed(9, 2, Measure::Fills, Axis::Side, -1),88    record("A002407", "Cuban primes: primes which are the difference of two consecutive cubes", 1, "7, 19, 37, 61, 127, 271, 331, 397, 547, 631, 919, 1657", Tag::Verified, "none", "mrlymath::formulas::six theorems, slices.md"),89    record("A003136", "Loeschian numbers: numbers of the form x^2 + xy + y^2", 1, "0, 1, 3, 4, 7, 9, 12, 13, 16, 19, 21, 25", Tag::Verified, "none", "spin.md, the ring radii of a spun hexagonal lattice"),90    record("A003180", "Number of equivalence classes of Boolean functions of n variables under action of symmetric group", 0, "2, 4, 12, 80, 3984, 37333248, 25626412338274304", Tag::Verified, "none", "bijection.md, the axis-permutation orbits at a one-term shift"),91    record("A003215", "Hex (or centered hexagonal) numbers: 3*n*(n+1)+1", 0, "1, 7, 19, 37, 61, 91, 127, 169, 217, 271, 331, 397", Tag::Proved, "3k^2 - 3k + 1", SIDES).keyed(11, 2, Measure::Fills, Axis::Side, -1),92    record("A003463", "a(n) = (5^n - 1)/4", 0, "0, 1, 6, 31, 156, 781, 3906, 19531, 97656, 488281, 2441406, 12207031", Tag::Verified, "(5^n - 1)/4", "REFS.md"),93    record("A004016", "Theta series of planar hexagonal lattice A_2", 0, "1, 6, 0, 6, 6, 0, 0, 12, 0, 6, 0, 0", Tag::Verified, "none", "mrlydemo::ring_weights, spin.md"),94    record("A004018", "Theta series of square lattice: number of ways of writing n as a sum of 2 squares", 0, "1, 4, 4, 0, 4, 8, 0, 0, 4, 4, 8, 0", Tag::Verified, "4(d_1(n) - d_3(n))", "mrlydemo::ring_weights, spin.md"),95    record("A004662", "Powers of 3 written in base 8", 0, "1, 3, 11, 33, 121, 363, 1331, 4213, 14641, 46343, 163251, 531773", Tag::Verified, "none", "this page, a near miss of A396934 - 1"),96    record("A005418", "Number of (n-1)-bead black-white reversible strings", 1, "1, 2, 3, 6, 10, 20, 36, 72, 136, 272, 528, 1056", Tag::Verified, "none", "REFS.md"),97    record("A005728", "Number of fractions in Farey series of order n", 0, "1, 2, 3, 5, 7, 11, 13, 19, 23, 29, 33, 43", Tag::Verified, "1 + sum of phi(k) for k <= n", "mrlynum::lattice::farey, the lit nodes of the stack in farey.md"),98    record("A005898", "Centered cube numbers: n^3 + (n+1)^3", 0, "1, 9, 35, 91, 189, 341, 559, 855, 1241, 1729, 2331, 3059", Tag::Proved, "k^3 + (k - 1)^3", SIDES).keyed(129, 3, Measure::Fills, Axis::Side, -1),99    record("A009964", "Powers of 20", 0, "1, 20, 400, 8000, 160000, 3200000, 64000000, 1280000000, 25600000000, 512000000000", Tag::Proved, "20^level", FILLS).keyed(23, 3, Measure::Fills, Axis::Level, 0),100    record("A009971", "Powers of 27", 0, "1, 27, 729, 19683, 531441, 14348907, 387420489, 10460353203, 282429536481, 7625597484987", Tag::Proved, "27^level", FILLS).keyed(255, 3, Measure::Fills, Axis::Level, 0),101    record("A011934", "a(n) = abs(1^3 - 2^3 + 3^3 - 4^3 + ... + (-1)^(n+1)*n^3)", 0, "0, 1, 7, 20, 44, 81, 135, 208, 304, 425, 575, 756", Tag::Verified, "none", "this page, the parent of the bisections A103532 and A395241"),102    record("A016185", "a(n) = 9^n - 8^n", 0, "0, 1, 17, 217, 2465, 26281, 269297, 2685817, 26269505, 253202761, 2413042577, 22791125017", Tag::Proved, "9^level - 8^level", "mrlymath::formulas::void").keyed(7, 2, Measure::Voids, Axis::Level, 0),103    record("A016754", "Odd squares: a(n) = (2n+1)^2, also centered octagonal numbers", 0, "1, 9, 25, 49, 81, 121, 169, 225, 289, 361, 441, 529", Tag::Proved, "(2k - 1)^2", SIDES).keyed(15, 2, Measure::Fills, Axis::Side, -1),104    record("A016755", "Odd cubes: a(n) = (2*n + 1)^3", 0, "1, 27, 125, 343, 729, 1331, 2197, 3375, 4913, 6859, 9261, 12167", Tag::Proved, "(2k - 1)^3", SIDES).keyed(255, 3, Measure::Fills, Axis::Side, -1),105    record("A018413", "Divisors of 363", 1, "1, 3, 11, 33, 121, 363", Tag::Verified, "none", "this page, a near miss of A396934 - 1"),106    record("A034474", "a(n) = 5^n + 1", 0, "2, 6, 26, 126, 626, 3126, 15626, 78126, 390626, 1953126, 9765626, 48828126", Tag::Verified, "5^n + 1", "REFS.md"),107    record("A047999", "Sierpinski's triangle (or gasket): Pascal's triangle read by rows mod 2", 0, "1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0", Tag::Verified, "none", "coprime.md, the points i AND j = 0"),108    record("A048883", "a(n) = 3^wt(n), where wt(n) = A000120(n)", 0, "1, 3, 3, 9, 3, 9, 9, 27, 3, 9, 9, 27", Tag::Verified, "3^wt(n)", "REFS.md"),109    record("A054247", "Number of n X n binary matrices under action of dihedral group of the square D_4", 0, "1, 2, 6, 102, 8548, 4211744, 8590557312, 70368882591744, 2305843028004192256", Tag::Verified, "none", "README.md, the rigid hypercube census at dim 2"),110    record("A065473", "Decimal expansion of the strongly carefree constant: Product_{p prime} (1 - (3*p-2)/(p^3))", 0, "2, 8, 6, 7, 4, 7, 4, 2, 8, 4, 3, 4", Tag::Verified, "none", "coprime.md"),111    record("A069403", "a(n) = 2*Fibonacci(2*n+1) - 1", 0, "1, 3, 9, 25, 67, 177, 465, 1219, 3193, 8361, 21891, 57313", Tag::Verified, "2 F(2n + 1) - 1", "REFS.md"),112    record("A103532", "Number of divisors of 240^n", 0, "1, 20, 81, 208, 425, 756, 1225, 1856, 2673, 3700, 4961, 6480", Tag::Proved, "(4k - 3)k^2", SIDES).keyed(23, 3, Measure::Fills, Axis::Side, -1),113    record("A125833", "Numbers whose base-5 representation is 333333.......3", 0, "0, 3, 18, 93, 468, 2343, 11718, 58593, 292968, 1464843, 7324218, 36621093", Tag::Verified, "3(5^n - 1)/4", "REFS.md"),114    record("A128625", "Expansion of (1+3*x)/(1-5*x)", 0, "1, 8, 40, 200, 1000, 5000, 25000, 125000, 625000, 3125000, 15625000, 78125000", Tag::Verified, "8 5^(n-1) for n >= 1", "REFS.md"),115    record("A129824", "a(n) = Product_{k=0..n} (1 + binomial(n,k))", 0, "2, 4, 12, 64, 700, 17424, 1053696, 160579584, 62856336636, 63812936890000, 168895157342195152, 1169048914836855865344", Tag::Proved, "Prod_{k=0}^{n} (1 + C(n,k))", "lab/rs/design-census, the fill classes of base 2"),116    record("A141148", "Number of aperiodic ternary necklaces with n beads of each color and no adjacent beads of the same color", 1, "2, 3, 14, 65, 346, 1929, 11442, 70310, 445928, 2896239, 19186738, 129184583", Tag::Verified, "none", "REFS.md"),117    record("A154105", "a(n) = 12*n^2 + 18*n + 7", 0, "7, 37, 91, 169, 271, 397, 547, 721, 919, 1141, 1387, 1657", Tag::Verified, "12n^2 + 18n + 7", "slices.md, the centered hexagonal vertices at n = k - 1"),118    record("A192908", "Constant term in the reduction by (x^2 -> x + 1) of a polynomial family; a(n) = 2*Fibonacci(2n-2) + 1", 0, "1, 1, 3, 7, 17, 43, 111, 289, 755, 1975, 5169, 13531", Tag::Verified, "2 F(2n - 2) + 1", "REFS.md"),119    record("A229896", "Sizes of logical groups of the same integer in A229895", 1, "1, 1, 4, 1, 5, 27, 1, 7, 37, 256, 1, 9, 61, 369, 3125, 1, 11, 91, 671, 4651, 46656, 1, 13, 127, 1105, 9031, 70993, 823543, 1, 15, 169, 1695, 15961, 144495, 1273609, 16777216, 1, 17, 217, 2465, 26281, 269297, 2685817, 26269505, 387420489", Tag::Verified, "none", "this page, an interior window holding the carpet voids"),120    record("A255016", "Number of toroidal n X n binary arrays, allowing rotation and/or reflection of rows and/or columns as well as matrix transposition", 0, "1, 2, 6, 26, 805, 172112, 239123150, 1436120190288, 36028817512382026", Tag::Verified, "none", "mrlymath::bang::baseq::sequence at dim 2, bijection.md"),121    record("A268240", "Pascal's tetrahedron of trinomial coefficients read mod 2", 0, "1, 1, 1, 1, 1, 0, 0, 1, 0, 1, 1, 1", Tag::Verified, "none", "REFS.md"),122    record("A299916", "a(n) = A299914(2n+1); the six-pointed-star holes of the Menger slice, by a comment", 0, "1, 6, 42, 306, 2250, 16578, 122202, 900882, 6641514, 48963042, 360969210, 2661166386", Tag::Verified, "a(n) = 9a(n-1) - 12a(n-2)", "mrlymath::formulas::cut_fills, slices.md").keyed(23, 3, Measure::Triangles, Axis::Level, 1),123    record("A332705", "Number of unit square faces (or surface area) of a stage-n Menger sponge", 0, "6, 72, 1056, 18048, 336384, 6531072, 129048576, 2568388608, 51267108864, 1024536870912", Tag::Proved, "2*20^level + 4*8^level", EXPOSURE).keyed(23, 3, Measure::Surface, Axis::Level, 0),124    record("A347825", "Number of ways to cut a 2 X n rectangle into rectangles with integer sides up to symmetries of the rectangle", 0, "1, 2, 6, 17, 61, 220, 883, 3597, 15232, 65130, 282294, 1229729", Tag::Verified, "none", "this page, a near miss of A396934/2"),125    record("A361870", "Array read by downward antidiagonals: nonequivalent 2-colorings of the cells of an n-dimensional hypercube with edges k cells long", 0, "2, 2, 1, 2, 2, 1, 2, 3, 2, 1, 2, 6", Tag::Verified, "none", "README.md, the rigid hypercube census"),126    record("A381517", "Perimeter of the Sierpinski carpet at iteration n", 0, "4, 16, 80, 496, 3536, 26992, 212048, 1684720, 13442768, 107437168, 859182416, 6872514544", Tag::Proved, "(4*8^level + 16*3^level)/5", EXPOSURE).keyed(7, 2, Measure::Surface, Axis::Level, 0),127    record("A395134", "Decimal expansion of the probability that the line that passes through two points selected independently and uniformly at random in a half-disk intersects the arc at two points.", 0, "4, 5, 9, 6, 2, 0, 3, 5, 3, 9, 0, 7", Tag::Verified, "1 - 16/(3 Pi^2)", "coprime.md, the complement of the A396934 density"),128    record("A395241", "a(n) = n^2*(4*n + 3)", 0, "0, 7, 44, 135, 304, 575, 972, 1519, 2240, 3159, 4300, 5687", Tag::Verified, "a(n) = n^2*(4*n + 3)", "lab/rs/oeis-terms, the b-file to n = 10000").keyed(23, 3, Measure::Voids, Axis::Side, -1),129    record("A396922", "E.g.f. A(x) satisfies A( x / A(log(A(log(A(log(A(x))))))) ) = exp(x)", 0, "1, 1, 3, 40, 1421, 87896, 7921207, 951512332, 144407735033, 26715045346048", Tag::Verified, "none", "REFS.md"),130    record("A396934", "Number of pairs (i,j) with 0 <= i,j < 2^n, i AND j = 0, and gcd(i,j) = 1", 0, "0, 2, 4, 12, 34, 122, 362, 1130, 3406, 10506, 31550, 95260", Tag::Verified, "none", "lab/rs/oeis-terms, the b-file to n = 20"),131    record("A398348", "Number of toroidal n X n X n binary arrays, allowing rotation and/or reflection of the layers along each axis as well as all permutations of the axes", 1, "2, 22, 111618, 6005363762644688, 7089215977519836239803174210135872, 10157435539019790383692007859901914095646506996125324171134976", Tag::Verified, "none", "lab/rs/oeis-terms, the b-file to n = 14"),132];133134/// Finds a record by id.135pub fn record_by_id(id: &str) -> Option<&'static Record> {136    RECORDS.iter().find(|record| record.id == id)137}138139fn parsed() -> &'static [Vec<i128>] {140    static PARSED: OnceLock<Vec<Vec<i128>>> = OnceLock::new();141    PARSED.get_or_init(|| {142        RECORDS143            .iter()144            .map(|record| {145                record146                    .terms147                    .split(',')148                    .map_while(|term| term.trim().parse().ok())149                    .collect()150            })151            .collect()152    })153}154155impl Record {156    /// Returns the listed terms that fit an i128, in order.157    pub fn parsed(&self) -> &'static [i128] {158        let at = RECORDS159            .iter()160            .position(|record| record.id == self.id)161            .expect("every record is listed");162        &parsed()[at]163    }164}165166/// Finds every record holding the terms as a window, with the record's index of the first term.167///168/// ```169/// let found = mrlylab::ledger::identify(&[6, 42, 306, 2250]);170/// assert_eq!(found.iter().map(|(r, s)| (r.id, *s)).collect::<Vec<_>>(), [("A299916", 1)]);171/// ```172pub fn identify(terms: &[i128]) -> Vec<(&'static Record, i32)> {173    if terms.is_empty() {174        return Vec::new();175    }176    let mut found: Vec<(&'static Record, i32)> = RECORDS177        .iter()178        .zip(parsed())179        .filter_map(|(record, known)| {180            known181                .windows(terms.len())182                .position(|window| window == terms)183                .map(|at| (record, record.offset + at as i32))184        })185        .collect();186    found.sort_by_key(|(record, shift)| (record.key.is_none(), shift.abs(), record.id));187    found188}189190#[cfg(test)]191mod tests {192    use super::super::{terms, BUDGET, TERMS};193    use super::*;194195    #[test]196    fn the_records_are_sorted_distinct_and_parse() {197        for pair in RECORDS.windows(2) {198            assert!(199                pair[0].id < pair[1].id,200                "{} before {}",201                pair[0].id,202                pair[1].id203            );204        }205        for record in RECORDS {206            assert!(record.parsed().len() >= 5, "{}", record.id);207            assert!(!record.name.contains('|'), "{}", record.id);208        }209        assert_eq!(RECORDS.len(), 60);210        assert_eq!(record_by_id("A398348").unwrap().parsed().len(), 5);211    }212213    #[test]214    fn every_keyed_record_reads_its_generator_at_its_shift() {215        let mut keyed = 0;216        for record in RECORDS.iter().filter(|record| record.key.is_some()) {217            let key = record.key.unwrap();218            let (got, _) = terms(&key, TERMS, BUDGET).unwrap();219            let known = record.parsed();220            let mut compared = 0;221            for (index, &term) in got.iter().enumerate() {222                let at = key.axis.start() + index as i32 + record.shift - record.offset;223                if let Some(&expected) = usize::try_from(at).ok().and_then(|at| known.get(at)) {224                    assert_eq!(term, expected, "{} at {index}", record.id);225                    compared += 1;226                }227            }228            assert!(compared >= 3, "{} compared {compared}", record.id);229            keyed += 1;230        }231        assert_eq!(keyed, 20);232    }233234    #[test]235    fn identify_returns_the_shift() {236        let ids = |terms: &[i128]| -> Vec<(&str, i32)> {237            identify(terms).iter().map(|(r, s)| (r.id, *s)).collect()238        };239        assert_eq!(ids(&[8, 21, 40, 65]), [("A000567", 2)]);240        assert_eq!(ids(&[6, 15, 28]), [("A000384", 2)]);241        assert_eq!(ids(&[72, 1056, 18048]), [("A332705", 1)]);242        assert_eq!(ids(&[1, 17, 217]), [("A016185", 1), ("A229896", 37)]);243        assert_eq!(ids(&[3, 6, 22, 402]), [("A000616", 1)]);244        assert_eq!(ids(&[4, 12, 80, 3984]), [("A003180", 1)]);245        assert_eq!(ids(&[5, 7, 11, 13]), [("A005728", 3)]);246        assert!(ids(&[5, 7, 11, 14]).is_empty());247        assert!(ids(&[]).is_empty());248    }249}