"""dualrs.py -- the chain law's depth side through a class the chain's step keeps: does a hidden window always hold a k with q g_k = 0? QUESTION. dualn.py's setting: f monic of degree n, f(0) = +/-q, O = Z[x]/(f), G = O/I, g_k = beta^k mod I, D = {0, ..., q - 1}, T_W the sums over k in W of D g_k. The class RS: a finite abelian G with a sequence g_0, g_1, ... generating it and satisfying sum_m a_m g_(k+m) = 0 for every k >= 0 (a_m f's coefficients) and g_k = 0 for k >= some t. O/I read at depth t is in RS, and so is G/ with the images. GC: in RS, if T_W is uniform on G != 0, then q g_k = 0 for some k in W. HAND (frozen before the runs). H1 If q g_k = 0, D g_k is q/r copies of , r its order, so T_W is uniform on G iff T_(W - k) is on G/, and a chain step in the quotient is one in G; GC therefore gives the depth side by induction on |G| + |W|. Uniformity is monotone in W, so GC iff W* = {k : q g_k != 0} never hides G != 0. R1 q = l^e. U = O/beta^t O is an l-group, so U = O0/beta^t O0 with O0 = Z_l[x]/(f0), f0 the factor of f over Z_l with f0 = x^r mod l (Hensel; beta is a unit on the other factor). So a G in RS(f) carries a sequence obeying f0's recurrence, f0 = x^r + a_(r-1) x^(r-1) + ... + a_0, l | a_i, v_l(a_0) = e, read mod exp(G); and every such f0 mod exp(G) is the factor, mod exp(G), of an integer f with f(0) = +/-q, f = f0 (x + c) with c a unit and the constant term set to +/-q. One sweep over f0 of degree r covers every integer base whose local factor has degree r, and only those. In an l-group each f0-sequence reaches 0 (g_(k+r) lies in l ), and G has rank <= r. R2 A cyclic G never hides: a faithful chi has q chi(g_k) != 0 at every k in W*. Skipped, with every G of exponent <= q (W* empty). R3 g_k -> v^k g_k, v a unit of Z_l, keeps every order, so W* and hiding, and maps f0 to a_i v^(r-i). At l = 2, r = 3 cubing is onto the units: a_0 = q. At l = 3, r = 3: a_0 = 9u, u in {1, 4, 7}. R4 chi in B_k iff chi in (q g_k)^perp - g_k^perp; W* hides iff the B_k, q g_k != 0, cover every chi != 0. One bitmask per element. R7 On (Z/l^m)^d, GL_d(Z/l^m) is transitive on the elements of each order and commutes with the recurrence, so g_0 runs over 0 and (l^j, 0, ..., 0) only. PREDICTIONS (frozen). Every initial r-tuple, run until it reaches 0. K integer cubics f = x^3 + a2 x^2 + a1 x + c0, c0 = +/-q, a1, a2 in -2..2, G every product of cyclic l-groups of order <= 16 (q = 2, 4) or 27 (q = 3), and q = 4 at order 32 with a1, a2 even, every triple of G^3 run to 64 terms, kept iff it reaches 0: 0 hiding. A q = 4, r = 3, G of order 64, rank <= 3, exp >= 8, every a_1, a_2 even mod exp(G), a_0 = 4; B q = 8, r = 3, G of order 64, exp >= 16, a_1, a_2 even, a_0 = 8; C q = 9, r = 3, G of order 81, exp >= 27, a_1, a_2 in 3Z mod exp, a_0 = 9u, u in {1, 4, 7}; D q = 4, r = 4, G of order <= 32, exp >= 8, a_1..a_3 even mod exp, a_0 = 4u, u odd; E the groups every invariant factor of which exceeds q, past order 64: q = 4 at (16, 8), (16, 16), (8, 8, 8), (32, 32); q = 8 at (16, 16); q = 9 at (27, 27), a_0 = 9. Predicted 0 hiding everywhere. KILL: any hiding sequence, printed with G, f0 and its r-tuple; GC then dies. L2 (frozen with T2 below, before its code) every noncyclic rank-2 l-group of order <= 256 at q = 2, 4, 8 and <= 243 at q = 3, 9, f0 = x^2 + a_1 x + q u (u over the units mod squares, a_1 in lZ mod exp G), and (added after the first run, whose q = 9 arm held no group with both factors above q) (32, 32) at q = 4, 8 and (27, 27) at q = 9; every (g_0, g_1) run to 0: at most 2 distinct lines with ord q g_k = l. KILL: a sequence with 3. Its own print: the sequences at 2, which must be > 0 for the bound to be tested. S2 r = 2 with no nilpotence: q = 2, 4 at order 16, 32, 64, q = 3 at 27, 81, every group, every a_0 = q u and every a_1 mod exp G, W* cut to [0, 8) and [0, 12): 0 hiding (T2 reads any window). L3 (frozen with R12, before its code) every initial triple under R7's cut, run to 0, f0 = x^3 + a2 x^2 + a1 x + a0, a1, a2 in lZ mod exp G: (4, 4, 4) q 2, a0 = 2; (8, 8, 8) q 2, a0 = 2; (8, 8, 8) q 4, a0 = 4 (R3); (9, 9, 9) q 3, a0 in {3, 6}. KILL: a sequence hitting more than B(l, 3) lines, 4 at l = 2 (of 7), 5 at l = 3 (of 13). Its own print: each arm's histogram. L4 (frozen with R13, after L3's run, before its code) at rank 2 inside cubic f0, case B, every triple under R7's cut: q 2 at (4, 4), (8, 8); q 4 at (8, 8), (16, 16) and at (8, 8) with x^3 + 4 alone; q 3 at (9, 9), a0 in {3, 6}, and (27, 27), a0 = 3, a1, a2 in {0, 3, 6}. R13 read by brute span at every sequence hitting all l + 1 lines, 2000 drawn per arm when more. KILL: one with g_i off V_(i+1). TRANSPLANT from l = 2, predicted: some q 3 sequence hits all 4 lines. BN (frozen with T4, before its engine) f0 = x^3 + a0, a0 = q u at every unit u mod exp G, every rank-2 l-group of exponent above q: every initial triple at order <= 32 at q = 2, 4 and <= 27 at q = 3, and (--full) 3000 drawn per (G, a0) at the others of order <= 256 at q = 2, 4, 8 and <= 243 at q = 3, 9: T4's K is closed. KILL: one sequence where it is not. G (frozen with R16-T5 by hand, before the gate engine) e = 1, rank 2, a1, a2 in lZ mod exp G, generating sequences only: q 2 at (4, 4), (8, 4), (8, 8), every triple under R7's cut, a0 = 2, and (16, 8), (16, 16), 2000 drawn; q 3 at (9, 9) every triple under R7's cut, a0 = 3, (27, 27) 2000 drawn at each a0 in {3, 6, 12} (R3) and (27, 9) 2000 drawn, a0 = 3; q 5 at (25, 25), 2000 drawn, a0 = 5. G1 R's gates come from at most one non-D class, at most one per depth. KILL: both non-D classes in R, or two X gates at one depth. G2 at most one non-degenerate D gate per depth in R, at its level's X depth when both lie in R. KILL: two at one depth, or one off its level's X depth (this clause, and C12's reach to every of order l^N2, added after the freeze, before the run). G3 g_d <= l at every depth leaves a closed in R. KILL: one sequence without. T5 proves it, so its print checks the engine. G4 (census) a closed in R at every sequence read; the depths with g_d > l counted, with their degenerate D gates, and (added after the first run) the sequences where some |A_d|, d >= 1, falls to 1; (added with this section's engine, before its run) the sequences at each D, R16's three cases. CONTROLS (read first). C1 "reaches 0" dropped, W* cut to [0, 8), q = 2, order 16, integer cubics: hiding sequences exist. C2 O/I at every ideal read at some depth, cubic bases of dualn.py at q^J <= 128, W* over [0, t): no hiding. C3 R7's cut at (4, 4), C1's only hiding group: one g_0 per order, and each hides iff its order class does. CB the nil arm, which no hiding reaches: the engine's witness count (characters no B_k covers) against a brute-force count over every character and every k in W*, at sampled eventually-zero sequences of (8, 8), (16, 8) at q = 4 and (27, 9) at q = 9, and at r = 2 of (8, 8) at q = 4 and (9, 9) at q = 3; equal at every one. C4 L2's code at r = 3: (8, 8), q = 4, x^3 + 4, every triple: some sequence puts q g_k on all 3 lines (the example closing DERIVED). Below 3, L2 is void. C5 the line counter itself: q = 1, f = x^7 on (Z/2)^3, seven free terms: some sequence hits all 7 lines (a counter reading only the first l + 1 line bits stops at 3). C6 R12 with l | f0(0) dropped: q = 1, f0 = x^3 + x + 1 on (2, 2, 2), beta a unit of period 7, 7 terms: some sequence hits all 7 lines, above B(2, 3) = 4. C7 (added with L4's code, after its freeze) R13's reader on (8, 8), q 4, x^3 + 4, g = (1, 0), (0, 1), 0, where V_1 misses (1, 0): no. C11 T4's K at x^3 + 2x + 2 (a1 = 2) on (8, 8), q 2, every triple: open at some sequence, so BN's reader can print a fail and K leans on a1 = 0 (dualpw.py reads a closed at every generating sequence there). C12 G's bitmask closure reader agrees with a brute character reader (the character with kernel a witness, read off character values, R15) at every , h not in lG, of order l^N2, on C4's sequence and one generating sequence of each default q 2 arm. C13 G's no: a bare list in (8, 8), q 2, with no closed among all twelve, found by search, printed with its largest g_d (above l, by T5's count with l + 1 children at the root). C14 G1's reader fires with R widened to every of both sides of e, x^3 + 2 on (8, 8). C15, C16 each a planted break in G2's own reader: C15 counts the degenerate D gates with the rest, C16 reads the level clause one level off. Each fires. FINDINGS (entered after the run, from its printed output). C1 6144 hiding sequences without nilpotence. C2 0 of 1948 ideals read at some depth hidden by their W*. C3 12 hiding (pair, order) cells, 0 off, every order held. CB 1080 sequences, 0 off, 31 distinct witness counts, the least 12. C4 24576 triples of (8, 8) hit all 3 lines. C5 most 7 lines. C6 {0: 1, 1: 49, 3: 294, 7: 168}: 168 sequences hit all 7. C7 says no. L2 most 2 lines, 3095568 sequences at 2 under R7's cut: q 2, 861 (G, f0) pairs, 2047632 at 2; q 4, 849, 640640; q 8, 689, 13312; q 3, 103, 385236; q 9, 115, 8748. S2 26392 runs, 0 hiding. L3 most 4 at l = 2, 3 at l = 3; the kill misses. Sequences by lines hit: (4, 4, 4) q 2, 4 f0, {0: 512, 1: 11776, 2: 29184, 3: 7680}; (8, 8, 8) q 2, 16 f0, {0: 2048, 1: 1624064, 2: 8699904, 3: 6057984, 4: 393216}; (8, 8, 8) q 4, 16 f0, {0: 196608, 1: 4390912, 2: 10223616, 3: 1966080}; (9, 9, 9) q 3, 18 f0, {0: 26244, 1: 2847474, 2: 18895680, 3: 6928416}. B(2, 3) = 4 is reached at (8, 8, 8) q 2; B(3, 3) = 5 is not reached. L4 R13 0 off, read at 8640 sequences hitting all l + 1 lines (every one at (8, 8) q 4 x^3 + 4, 512, and (4, 4) q 2, 128; 2000 drawn of 39936 at (8, 8) q 2, of 8192 at (8, 8) q 4, of 458752 at (16, 16) q 4, of 314928 at (27, 27) q 3). (9, 9) q 3, 18 f0: most 3 lines, {0: 2916, 1: 106434, 2: 209952, 3: 34992}; (27, 27) q 3, 9 f0: {0: 1458, 1: 3209058, 2: 9430344, 3: 6176088, 4: 314928}, so the TRANSPLANT held: q 3 reaches all 4 lines, at (27, 27) only. (9, 9) cannot (by hand): a generating sequence reads its factors l^(e+1), so M_C = C (a non-generating one spans a group whose qH is cyclic, one line), and beta^k lies in lO0 for k >= 3 (f0 = x^3 mod l), so hits fall at k = 0, 1, 2 only, at most 3 lines. The same count caps L3's (4, 4, 4) q 2, (8, 8, 8) q 4 and (9, 9, 9) q 3 at 3, which is why B(3, 3) = 5 is not reached; B(2, 3) = 4 is, above l^(e+1). BN C11: open at 84096 sequences. 0 open: default 351174 sequences over 16 (G, a0) pairs; --full 1014174 over 237. G C12 passes (15 closed in all), C13 prints a bare list of eight with no closed , largest g_d 5; C14 fires at 7680 of 7680, C15 at 6511, C16 at 20662: each reader can say no. G1, G2, G3 0 fails over 604952 generating sequences: 1536 (4, 4), 344064 (8, 4), 122880 (8, 8) q 2, 122472 (9, 9) q 3, and 2000 drawn at each of the seven drawn arms. D = 0, 1, 2 at 410548, 131362, 63042, each class at every arm. G4: a closed in R at every one. g_d > l at 3174, all at q 2 (3072 (8, 8), 13 (16, 8), 89 (16, 16)), each over-full depth holding a degenerate D gate (by G1 and G2's zero fails; the print sums 3072, 13, 90 such terms there); some |A_d| falls to 1 at 3072, 13 and 38 of them, never to 0. A degenerate D gate lies in R at q 3 only in the (27, 27) draws (96, 93, 111), never over-full, and at none of q 5's. K 0 hiding: kept 419112 (q 2, order <= 16), 144012 (q 3, <= 27), 419112 (q 4, <= 16), 4128768 (q 4, order 32, a1, a2 even); each count holds every initial triple reaching 0, the zero sequence, the non-generating ones (which cannot hide) and automorphic copies among them. A 0 hiding: 416 (G, f0) pairs, 105119744 sequences under R7's cut. B 0 hiding: 384 pairs, 100663296 sequences. C 0 hiding: 81 pairs, 43046721 sequences (at exp 27, a_0 = 9u reads u mod 3 only, so the three u are one). D (--full) 0 hiding: 1216 pairs, 1212153856 sequences. E (--full) 0 hiding: q = 4, 400 pairs, 1782579200 sequences under R7's cut; q = 8, 64 pairs, 20971520; q = 9, 81 pairs, 172186884. The kill misses at every family: GC holds at this scale, a pattern at r >= 3; at r <= 2 it is T2 below, at x^3 + a0 T4. DERIVED (by hand: GC at r <= 2, T2; not at full rank, T3; at x^3 + a0, T4; toward r >= 3). D1 RS is the quotients of U = O/beta^t O by its subgroups H, g_k the class of beta^k: U is generated by 1, ..., beta^(t-1) under f's relations and beta^t = 0. T_t is a complete residue system of U (O/beta O = Z/q), so with Z = [0, t) - W*, T_(W*) + T_Z = U once each, and W* hides U/H iff T_(W*) + H covers U m = |H|/q^|Z| times. D2 V_k = has V_k/V_(k+1) cyclic on g_k of order n_k | q, as in the ring. A character built down from V_(t-1) meets a constraint only at k in W* with n_k < q: there q chi(g_k) = (q/n_k) chi(n_k g_k) is fixed before chi(g_k) is chosen. D3 The filtration alone does not carry GC: a no-depth miss's g_0, ..., g_5 with elements z, q z = 0, appended to span the q g_k satisfies q y_i in for every i, and its window still hides. A proof must use f's recurrence past u = max W*. D4 In a least counterexample every nonzero subgroup K has a chain over W* started at K that reaches G (the quotient G/K is smaller), so every subgroup of order l is for some k in W*. R5 S <= G is CLOSED when k in W*, q g_k in S imply g_k in S. A nonzero proper closed S reduces GC at G to GC at G/S (in RS): a witness chi of G/S for W*(G/S) lifts, since at k in W* with q g_k in S, g_k is in S and chi(g_k) = 0. So a least counterexample has none (D4 is |S| = l). R6 (case A) If an invariant factor of G has order <= q, (qG)[l] is not G[l], and a line of G[l] outside qG is closed (no q g_k lies in it). So a least counterexample is CASE B: every invariant factor exceeds q, every line of G[l] is with o_k = e + 1 (ord g_k = l^(o_k)). R8 The closure of qG (the least closed subgroup over it) is qG + : every k in W* enters at once. So in a least counterexample the g_k, k in W*, generate G. R9 T_t = T_(W*) + T_Z is a complete residue system of U (D1), so in G, mu_(W*) * mu_Z = |H| u_G (mu_S the image of T_S counted with multiplicity, u_G uniform). For k in Z, D g_k covers q/ord(g_k) times, and a sum of uniform measures on subgroups is uniform on their sum: mu_Z is a multiple of u_(G_Z), G_Z = . So W* hides G iff mu_(W*) is invariant under translation by G_Z, and a witness is nonzero on G_Z. R10 (the dual) U^ is the f0-sequences c in Q_l/Z_l with c_k = 0 for k >= t, G^ a subgroup of it, c_k = chi(g_k). q c_k is fixed by c_(k+1), ..., c_(k+r) (a_0 = q times a unit), so the last nonzero term of every c is killed by q, and a witness's last nonzero term sits off W*. R12 For a full lattice M in O0 (x) Q_l, the beta^k (k >= 0) in M - lM put their images on at most B(l, r) = 1 + (l^(r-1) - 1)/ (l - 1) lines of M/lM. With i the least such k, every later one lies in N = beta^(i+1) O0 cap M, whose image in M/lM is proper: else N + lM = M, so N = M (Nakayama), beta^i lies in beta^(i+1) O0 and, f0(0) != 0 (R1) letting beta^i cancel, beta is a unit of O0, but l | f0(0). So the later lines lie in a hyperplane. No window and no nilpotence is read. L2 prints the bound at r = 2, L3 at r = 3, where C6 shows the hypothesis l | f0(0) bites. T2 (GC at r <= 2) q = l^e, f0 monic of degree <= 2 over Z_l, l | f0(0), G a finite l-group, g_k obeying f0's recurrence, W finite: W* never hides G != 0; no nilpotence is used (S2 sweeps it). If the g_k span a proper subgroup, a chi != 0 vanishing on it is a witness; else G = O0/L, L the kernel of x^k -> g_k (a Z_l-lattice, not always an ideal), rank <= 2. R5 and R6 read only G, the g_k and W*, and a quotient keeps f0 and W, so a least counterexample is case B of rank 2 (R2), each of the l + 1 >= 3 lines of G[l] some . Both invariant factors above q put L in l^(e+1) O0; with M = l^-(e+1) L, x -> l^e x maps M/lM onto G[l] = l^e M / l^(e+1) M, and is a line iff beta^k lies in M - lM, the line of beta^k mod lM. R12 allows two. No invertibility of lattices enters, so a double root of f0 costs nothing. With H1, the depth side holds wherever f's local factor has degree <= 2. T3 (no least counterexample at full rank) q = l^e, f0 monic of degree r over Z_l, l | f0(0): a least counterexample has 2 <= rank G <= r - 1. At rank r it is case B (R6), L lies in l^(e+1) O0 and T2's map carries M/lM onto G[l], whose (l^r - 1)/(l - 1) lines are each some (D4); R12 reaches l^(r-1) - 1 fewer. Rank 1 is R2; at r = 2, T3 is T2. R13 (rank 2 <= s < r, case B) A Smith basis puts L = P + L_C, P spanned by r - s basis vectors, L_C inside l^(e+1) C, C spanned by the rest; pi: O0 -> C along P. Then M cap O0 = P + M_C and lM cap O0 = P + l M_C (e >= 1), M_C = l^-(e+1) L_C, so q g_k spans a line iff pi(beta^k) lies in M_C - l M_C, read in M_C/l M_C. With i the least such k, later hits lie in N_C = pi(beta^(i+1) O0) cap M_C; if its image is proper they lie in a hyperplane, too few lines; else N_C = M_C (Nakayama) and beta^i lies in beta^(i+1) O0 + P: P, inside L, holds beta^i - beta^(i+1) y, so g_i lies in V_(i+1). A least counterexample of rank s < r has V_i = V_(i+1). Where l^(s-1) >= 3 the next hit i' must pass the same test (else at most 2 + (l^(s-1) - 1)/(l - 1) lines, l^(s-1) - 2 too few), so at s = r - 1, P a line, beta^(i' - i) = l^m eta, eta a unit of O0; at e = 1 (f0 Eisenstein) beta^3 is l times a unit, so this alone kills nothing. L4 reads R13. The rank-2 case is open: at r = 3 beta^m mod l ranges over , and G = Z/8 x Z/8, f0 = x^3 + 4, g = (1,0), (0,1), (1,1) puts q g_0, q g_1, q g_2 on all three lines (C4). R14 (the closure reduction) Every nonzero closed S holds a line of G[l] and that line's closure (S <- S + , to a fixed point), so by R5 a least counterexample is CLOSURE-FREE: every line's closure is G, l + 1 of them at rank 2. That puts every line hit (an unhit line is closed) and the g_k, k in W*, generating G, so it subsumes D4, R6, R8 and R13. W* read over the whole sequence is the hardest case: a window's closures are smaller. In R13's lattices at s = 2, P = Z_l p, c_k = pi(beta^k), G = C/L_C: W* = {k : c_k not in lM_C}, the hits are the c_k in M_C - lM_C, and a lattice X, L_C <= X <= C, is closed iff no k in W* has c_k in (l^-e X cap C) - X. With R2 and T3, GC at every cubic local factor follows from: no rank-2 case-B sequence is closure-free (dualpw.py reads PW, which implies it, at q = 2, 4, 8, exponent <= 32). At G = (Z/l^(e+1))^2 none is: g_k lies in lG for k >= 3 (l | a_i), so W* lies in {0, 1, 2}; where a line is unhit (always at l >= 3), any , h not in lG, through it is closed (each q g_k, k in W*, has order l off that line); at l = 2 with three lines hit is closed, q g_1 and q g_2 lying off its line, and g_0 is not in lG. R15 (the primitive witness) If G/K is cyclic, the character chi with kernel K is a witness iff K is closed: at k in W*, chi(g_k) = 0 iff g_k is in K, and q chi(g_k) = 0 iff q g_k is. At rank 2, is such a K, K != G, whenever h is not in lG. In R14's lattices h lifts to a primitive d, Z_l d = ker rho with rho a primitive functional and n = v(rho(L_C)) >= e + 1; g_k lies in iff v(rho(c_k)) >= n and q g_k does iff v(rho(c_k)) >= n - e. So PW (some such closed, read by dualpw.py) says: some scalar f0-sequence rho(c_k) avoids the valuations n - e, ..., n - 1 on W*. T4 (the binomial factor) At f0 = x^3 + a0 mod exp G, GC holds. Here g_(3a+i) = (-a0)^a g_i, so every term lies in , or , and a chi != 0 that is 0 or injective on each of the three is a witness: at k in W*, q g_k != 0 lies in some , so q chi(g_k) != 0 unless chi kills . At rank 2 take chi with kernel K = , h not in lG (R15). Every line of G[l] is some [l] (on Z/l^m1 x Z/l^m2, m1 >= m2: h = (1, 0) gives (l^(m1-1), 0), and h = (l^(m1-m2) t, 1) gives (l^(m1-1) t, l^(m2-1))), and K meets trivially iff K[l] is not the line L_i of . If some line is no L_i, K goes through it; else l = 2 and L_0, L_1, L_2 are the three lines, and any K holding g_0 (some does: g_0 = l^a h) kills and meets the others trivially. The step reads only that the terms lie in at most l + 1 cyclic subgroups: no invariant factor, generation or nilpotence. Rank 1 is R2, rank 3 T3, and a quotient keeps a1 = a2 = 0, so GC holds wherever f's l-adic factor is x^3 + a0 (among integer cubics f = x^3 +/- q); with H1 so does the depth side. BN reads K. R16 (the edge) Let q = l (e = 1), so f0 is Eisenstein, O0 = Z_l[beta] a DVR with l O0 = beta^3 O0; G = O0/L of rank 2 with invariant factors l^N1 >= l^N2 >= l^2; p in L spans L mod l, p = beta^D eps (D <= 2, eps a unit). C = (O0 (x) Q_l)/Q_l p, pi the projection, c_k = pi(beta^k), O_C = pi(O0), L_C = pi(L), G = O_C/L_C (p primitive, so Q_l p cap O0 = Z_l p). Omega_k = pi(beta^k O0) = , Omega_(k+3) = l Omega_k, each step of index <= l, and pi(l^a p) = 0 gives xi_0 c_(D+3a) + xi_1 c_(D+3a+1) + xi_2 c_(D+3a+2) = 0, xi = w^a eps (w = l/beta^3), xi_0 a unit: the step at D+3a is trivial, the other two have index l. So every Omega_k is l^a Omega or l^a Omega' (Omega = Omega_D, Omega' = Omega_(D+2)), the two ends of one edge e of the Bruhat-Tits tree of C, and o = [O_C] is [Omega] at D = 0, 2, [Omega'] at D = 1. R17 (the sides) c_(D+3a+1) lies in l^a Omega - l^a Omega', c_(D+3a+2) in l^a Omega' - l^(a+1) Omega: the end [c_k] of the D+1 class lies on Omega's side of e, of the D+2 class on Omega''s side. A D-class c_(D+3a) = gamma_1 c_(D+3a+1) + gamma_2 c_(D+3a+2), gamma_i = -xi_i/xi_0, lies on Omega's side iff l does not divide gamma_1, else on Omega''s side or, where l divides both (DEGENERATE; then g_k lies in V_(k+3)), in l^(a+1) Omega, a level up. R18 (the gates) The subgroups of G are the lattices L_C <= M <= O_C, the cyclic ones of order l^d the vertices at distance d from v0 = [L_C], and the , h not in lG, of order l^N2 those at distance N2 with v0 on the geodesic from o (the CONE; at N1 = N2, v0 = o and every vertex at distance N2). Such an is closed (R5) iff its chain l^j never passes a GATE, the vertex at depth n_k - 1 (k in W*, l^(n_k) = ord g_k), without taking its direction . R19 (the region) R is the cone, or at N1 = N2 the on o's side (h not in H', H' the one V_k of index l in G). R lies on one side of e, and only ends on that side put gates on R's chains, so one non-D class X gives gates, the other none. An end l^j x0 in the cone, x0 primitive in O_C, has order l^(N2 - j), and the X term at level a has j = a + const: one X gate per depth. A non-degenerate D term sits at its level's X depth. So a depth holds at most 2 gates unless a degenerate D term LANDS there from a deeper level: it rises m(a) >= 1 levels, w^(-a) eps^(-1) in Z_l + l^m O0. T5 (survival) R's root has l children in R (the cone: all but the one toward o; at v0 = o, all but o'), every later vertex l. With A_d the depth-d vertices some chain of R reaches past no broken gate, a gate removes at most l - 1 children and two at one vertex all l <= 2(l - 1), so |A_(d+1)| >= l |A_d| - (l - 1) g_d, g_d the distinct gates at depth d, none at depth 0. If g_d <= l at every depth, |A_d| >= l throughout: some in R is closed, a witness (R15). With R19 that holds at every sequence with no degenerate D gate in R, and wherever at most l - 1 D gates share a depth. R20 (the landers; derived after G's run, never run) g_(D+3a) = l^a pi(beta^D w^(-a)), so a D term rises m(a) = delta(w^(-a) eps^(-1)) levels, delta(u) = max{m : u in Z_l + l^m O0}, which is an ultrametric closeness on O0^x/Z_l^x. The degenerate levels are one class mod P or none, P the order of w in (O0/l)^x/F_l^x (P | l at l odd, P | 4 at l = 2), all or none at P = 1. Two D terms land on one level a < a' only if t = a' - a has P | t and m(a) = t + m(a'), m(a') = delta(w^(-t)) (at l odd mu + v_l(t/P), mu = delta(w^P)). At l = 3 a depth over-fills (X, its level's D and two landers, or three landers) only at exponent >= 3^6 (P = 3, mu = 1, t = 3, m(a) = 4); at l = 2 one lander beside its level's X and D already does, and there no count of gates alone decides. Case B stays open at 2 <= rank G <= r - 1, r >= 3, past T4 and, at e = 1, past T5's hypothesis. The aim, seen and not printed here: at r = 3, over the cubic local factors (a_0 = q, a_1, a_2 even), every generating eventually-zero sequence of (8, 8), (16, 8), (16, 16), (8, 8, 8) at q = 4 and (16, 16) at q = 8, under R7's cut, had a witness chi with chi(g_s) != 0, s the sequence's last k with g_k != 0, and one of order exp G, each found apart. The sequences with every line of G[l] some have q^|W*| = |G| at (8, 8), where Hajos's theorem kills a hiding, and q^|W*| > |G| at (16, 8) at q = 4 and (16, 16) at q = 4, 8, where it does not reach. RUN RECORD. G alone: 24.1 s, 37.4 MB. Default 26/26, 133.4 s, 86.3 MB; D 288.3 s, 67.6 MB, under a memory guard. E (--full), its three family() calls run alone: 400, 64, 81 (G, f0) pairs, hiding 0 at each, 1789.5 s, peak 249.4 MB, nearly all of it q = 4. """ import os import random import sys import time from itertools import product os.environ.setdefault("OPENBLAS_NUM_THREADS", "1") import numpy as np # noqa: E402 CHECKS = [] CHUNK = 1 << 18 def check(name, ok, detail=""): CHECKS.append(bool(ok)) print(f" {'PASS' if ok else 'FAIL'} {name}" + (f" ({detail})" if detail else ""), flush=True) def groups(l, top, exact=False): """Every product of cyclic l-groups of order <= top (== top if exact), as moduli lists, largest first.""" out = [] def rec(rest, cap, cur): if cur and (not exact or rest == 0): out.append(tuple(l ** x for x in cur)) for e in range(min(cap, rest), 0, -1): rec(rest - e, e, cur + [e]) e = 0 while l ** (e + 1) <= top: e += 1 rec(e, e, []) return out class Group: """G = prod Z/m_i, elements as indices 0..N-1 (0 the identity).""" def __init__(self, ms): self.ms = ms self.E = max(ms) self.els = np.array(list(product(*[range(m) for m in ms])), dtype=np.int64) self.N = N = len(self.els) st = np.cumprod([1] + [m for m in ms[::-1]])[:-1][::-1] self.st = np.array(st, dtype=np.int64) self.add = self.index(self.els[:, None, :] + self.els[None, :, :]).ravel() R = self.els * np.array([self.E // m for m in ms], dtype=np.int64) zero = (self.els @ R.T) % self.E == 0 # [x, chi] self.W = (N + 63) // 64 bits = np.zeros((N, self.W * 64), dtype=bool) bits[:, :N] = zero self.perp = np.packbits(bits.reshape(N, self.W, 64)[:, :, ::-1], axis=2, bitorder="big") \ .view(">u8").astype(np.uint64).reshape(N, self.W) full = np.ones(self.W * 64, dtype=bool) full[N:] = False full[0] = False # chi = 0 self.full = np.packbits(full.reshape(self.W, 64)[:, ::-1], axis=1, bitorder="big") \ .view(">u8").astype(np.uint64).reshape(self.W) def index(self, v): return ((v % np.array(self.ms, dtype=np.int64)) @ self.st) def mul(self, c): return self.index(c * self.els) def homocyclic_firsts(G): """R7: on (Z/l^m)^d, g_0 in {0, (l^j, 0, ..., 0)} up to Aut.""" m, d = G.ms[0], len(G.ms) if any(x != m for x in G.ms): return None out, c = [0], 1 while c < m: out.append(int(G.index(np.array([c] + [0] * (d - 1))))) c *= [p for p in range(2, m + 1) if m % p == 0][0] return out def block(G, q, a, ids, nil=True, window=None, terms=64): """Run the sequences whose initial r-tuples are the base-N digits of ids, g_(k+r) = -(a_0 g_k + ... + a_(r-1) g_(k+r-1)). Returns (cover, keep): cover the B_k's union as bitmasks over chi, keep whether the sequence reaches 0 (the last r of `terms` zero; run until all reach 0 when nil); window: cover only k < window.""" r, N = len(a), G.N mula = [G.mul(-c) for c in a] qm = G.mul(q) seq = [ids // N ** (r - 1 - j) % N for j in range(r)] cover = np.zeros((len(ids), G.W), dtype=np.uint64) k = 0 while True: g = seq[k] if window is None or k < window: qg = qm[g] m = G.perp[qg] & ~G.perp[g] m[qg == 0] = 0 cover |= m nxt = mula[0][seq[k]] for j in range(1, r): nxt = G.add[nxt * N + mula[j][seq[k + j]]] seq.append(nxt) k += 1 if nil and window is None and k >= r and \ not any(np.any(s) for s in seq[k:k + r]): break if k + r >= terms: break if nil: keep = np.all(np.stack([seq[j] == 0 for j in range(len(seq) - r, len(seq))]), axis=0) else: keep = np.ones(len(ids), dtype=bool) return cover, keep def sweep(G, q, a, nil=True, window=None, terms=64, firsts=None): """Every r-tuple of G (g_0 in firsts if given). Returns (kept, hiding, first hiding tuple).""" r, N = len(a), G.N rest = N ** (r - 1) blocks = [(f * rest, (f + 1) * rest) for f in firsts] if firsts \ else [(0, N ** r)] kept = hid = 0 first = None for b0, hi in blocks: for lo in range(b0, hi, CHUNK): ids = np.arange(lo, min(hi, lo + CHUNK), dtype=np.int64) cover, keep = block(G, q, a, ids, nil, window, terms) hides = np.all(cover == G.full, axis=1) & keep kept += int(keep.sum()) hid += int(hides.sum()) if first is None and hides.any(): i = int(ids[np.argmax(hides)]) first = tuple(tuple(G.els[i // N ** (r - 1 - j) % N]) for j in range(r)) return kept, hid, first def local_coeffs(l, E, n): """Every (a_1..a_n) with l | a_i, read mod E.""" return list(product(range(0, E, l), repeat=n)) def integer_cubics(q, even=False): rng = (-2, 0, 2) if even else range(-2, 3) for c0 in (q, -q): for a1 in rng: for a2 in rng: yield (c0, a1, a2) def popcount(x): """Bits set per row of a uint64 array.""" v = x.view(np.uint8) return np.unpackbits(v, axis=-1).reshape(x.shape[0], -1).sum(axis=1) def brute_witnesses(ms, q, a, tup): """Characters chi != 0 with chi(g_k) = 0 or q chi(g_k) != 0 at every k with q g_k != 0, by direct arithmetic; the sequence run to 0.""" E, r = max(ms), len(a) s = [list(x) for x in tup] while any(any(x) for x in s[-r:]): s.append([(-sum(a[j] * s[-r + j][i] for j in range(r))) % m for i, m in enumerate(ms)]) W = [x for x in s if any((q * xi) % m for xi, m in zip(x, ms))] n = 0 for c in product(*[range(m) for m in ms]): if not any(c): continue vals = [sum(ci * xi * (E // m) for ci, xi, m in zip(c, x, ms)) % E for x in W] n += all(v == 0 or (q * v) % E for v in vals) return n def control(): print("C controls", flush=True) t0 = time.time() hid = 0 for ms in groups(2, 16, exact=True): G = Group(ms) for a in integer_cubics(2): hid += sweep(G, 2, a, nil=False, window=8, terms=11)[1] check("C1 no nilpotence, W* cut to [0, 8), q 2 order 16: hiding " "exists", hid > 0, f"{hid}, {time.time() - t0:.1f} s") G = Group((4, 4)) order = [int(np.lcm.reduce([m // np.gcd(int(x), m) for x, m in zip(e, G.ms)])) for e in G.els] cells = off = 0 for a in integer_cubics(2): for f in homocyclic_firsts(G): orbit = [x for x in range(G.N) if order[x] == order[f]] whole = sweep(G, 2, a, nil=False, window=8, terms=11, firsts=orbit)[1] rep = sweep(G, 2, a, nil=False, window=8, terms=11, firsts=[f])[1] cells += whole > 0 off += (whole > 0) != (rep > 0) span = {order[f] for f in homocyclic_firsts(G)} == set(order) check("C3 R7: one representative per order of g_0, and it hides iff " "its orbit does, (4, 4)", span and cells > 0 and off == 0, f"{cells} hiding (pair, order) cells, {off} off, every order " f"{span}") rnd = random.Random(7) pairs = [((8, 8), 4, (4, 0, 0)), ((8, 8), 4, (4, 2, 6)), ((16, 8), 4, (4, 6, 8)), ((16, 8), 4, (12, 2, 4)), ((27, 9), 9, (9, 3, 6)), ((8, 8), 4, (4, 2)), ((8, 8), 4, (12, 6)), ((9, 9), 3, (3, 3)), ((9, 9), 3, (6, 0))] seen = bad = 0 counts = set() for ms, q, a in pairs: G = Group(ms) r = len(a) ids = np.array(rnd.sample(range(G.N ** r), 3000), dtype=np.int64) cover, keep = block(G, q, a, ids, terms=10 ** 6) eng = popcount(G.full & ~cover) for i in np.where(keep)[0][:120]: tup = [tuple(int(x) for x in G.els[int(ids[i]) // G.N ** (r - 1 - j) % G.N]) for j in range(r)] b = brute_witnesses(ms, q, a, tup) seen += 1 bad += b != int(eng[i]) counts.add(b) check("CB the nil arm's witness count matches brute force", seen > 0 and bad == 0 and len(counts) > 3, f"{seen} sequences, {bad} off, {len(counts)} distinct counts, " f"least {min(counts)}, {time.time() - t0:.1f} s") return time.time() - t0 def section_c2(): from dualdeg import powers from dualn import Base, cubic_bases from dualmult import depth t0 = time.time() n_id = hid = 0 for a in cubic_bases(): B = Base(a, 128) q = B.q for L in B.Is: t = depth(L, a, B.pw[1]) if t is None or L.N == 1: continue n_id += 1 pw = powers(a, t + 1) gk = [pw[k] for k in range(t)] Ws = [k for k in range(t) if any(L.key(tuple(q * x for x in gk[k])))] chars = L.characters()[1:] N = L.N ok = True for c in chars: vals = [sum(ci * xi for ci, xi in zip(c, gk[k])) % N for k in Ws] if not any(v and (q * v) % N == 0 for v in vals): ok = False break hid += ok check("C2 no ring ideal read at some depth is hidden by its W*", n_id > 0 and hid == 0, f"{hid} of {n_id}, {time.time() - t0:.1f} s") def section_k(): print("K integer cubics, every triple to 64 terms", flush=True) t0 = time.time() total = 0 for q, l, top, even, exact in [(2, 2, 16, False, False), (3, 3, 27, False, False), (4, 2, 16, False, False), (4, 2, 32, True, True)]: kept = hid = 0 for ms in groups(l, top, exact=exact): G = Group(ms) for a in integer_cubics(q, even): k_, h_, _ = sweep(G, q, a) kept += k_ hid += h_ total += hid print(f" q {q}, order {'' if exact else '<= '}{top}" f"{', a1, a2 even' if even else ''}: kept {kept}, hiding " f"{hid}, {time.time() - t0:.1f} s", flush=True) check("K no eventually-zero sequence has W* hiding G", total == 0, f"{total}") def line_bits(G, l): """Element index -> the bit of its line of G[l] (0 off G[l] - 0), and the number of lines.""" lm, muls = G.mul(l), [G.mul(c) for c in range(1, l)] bit = np.zeros(G.N, dtype=np.int64) n = 0 for x in range(1, G.N): if lm[x] == 0 and bit[x] == 0: for m in muls: bit[m[x]] = 1 << n n += 1 return bit, n def lines_hit(G, q, a, l, firsts=None, terms=None, every=None): """Every r-tuple (g_0 in firsts if given), run to 0, or to `terms` terms if given: per sequence the number of distinct lines with ord q g_k = l, as a histogram {count: sequences}. every: a list collecting the ids of the sequences hitting all lines.""" r, N = len(a), G.N bit, n = line_bits(G, l) bit = bit[G.mul(q)] mula = [G.mul(-c) for c in a] rest = N ** (r - 1) blocks = [(f * rest, (f + 1) * rest) for f in firsts] if firsts \ else [(0, N ** r)] hist = {} for b0, hi in blocks: for lo in range(b0, hi, CHUNK): ids = np.arange(lo, min(hi, lo + CHUNK), dtype=np.int64) seq = [ids // N ** (r - 1 - j) % N for j in range(r)] acc = np.zeros(len(ids), dtype=np.int64) k = 0 while (k < terms) if terms else \ any(np.any(x) for x in seq[k:k + r]): acc |= bit[seq[k]] nxt = mula[0][seq[k]] for j in range(1, r): nxt = G.add[nxt * N + mula[j][seq[k + j]]] seq.append(nxt) k += 1 cnt = sum((acc >> b) & 1 for b in range(n)) if every is not None: every.extend(int(x) for x in ids[cnt == n]) for c, m in zip(*np.unique(cnt, return_counts=True)): hist[int(c)] = hist.get(int(c), 0) + int(m) return hist def span(G, gens): """The subgroup of G generated by gens, as a set of indices.""" out, frontier = {0}, [0] while frontier: nxt = [] for x in frontier: for g in gens: y = int(G.add[x * G.N + g]) if y not in out: out.add(y) nxt.append(y) frontier = nxt return out def run(G, a, i0): """The sequence of the initial tuple with id i0, run to 0.""" r, N = len(a), G.N mula = [G.mul(-c) for c in a] seq = [i0 // N ** (r - 1 - j) % N for j in range(r)] k = 0 while any(seq[k:k + r]): nxt = int(mula[0][seq[k]]) for j in range(1, r): nxt = int(G.add[nxt * N + mula[j][seq[k + j]]]) seq.append(nxt) k += 1 return seq def r13(G, q, a, l, i0): """Whether g_i lies in V_(i+1), i least with ord q g_k = l.""" seq = run(G, a, i0) qm, lm = G.mul(q), G.mul(l) i = next(k for k, g in enumerate(seq) if qm[g] != 0 and lm[qm[g]] == 0) return seq[i] in span(G, set(seq[i + 1:])) def section_l2(): print("L2 lines of order l, r = 2", flush=True) t0 = time.time() h7 = lines_hit(Group((2, 2, 2)), 1, (0,) * 7, 2, firsts=[1]) check("C5 the counter reads all 7 lines of (2, 2, 2): q = 1, f = x^7, " "seven free terms", max(h7) == 7, f"most {max(h7)}") h3 = lines_hit(Group((8, 8)), 4, (4, 0, 0), 2) check("C4 r = 3, (8, 8), q 4, x^3 + 4: some sequence hits all 3 " "lines", max(h3) == 3, f"histogram {h3}") top = two = 0 for l, q, order, us, extra in [(2, 2, 256, (1, 3, 5, 7), []), (2, 4, 256, (1, 3, 5, 7), [(32, 32)]), (2, 8, 256, (1, 3, 5, 7), [(32, 32)]), (3, 3, 243, (1, 2), []), (3, 9, 243, (1, 2), [(27, 27)])]: pairs, hist = 0, {} for ms in [x for x in groups(l, order) if len(x) == 2] + extra: G = Group(ms) firsts = homocyclic_firsts(G) for a0 in sorted({q * u % G.E for u in us}): for (a1,) in local_coeffs(l, G.E, 1): for c, n in lines_hit(G, q, (a0, a1), l, firsts).items(): hist[c] = hist.get(c, 0) + n pairs += 1 top = max(top, max(hist)) two += hist.get(2, 0) print(f" q {q}, rank 2, order <= {order}" f"{''.join(f', {x}' for x in extra)}: {pairs} (G, f0) pairs, " f"sequences by lines hit {dict(sorted(hist.items()))}, " f"{time.time() - t0:.1f} s", flush=True) check("L2 r = 2: no sequence puts q g_k on 3 lines", top <= 2 and two > 0, f"most {top}, {two} sequences at 2 under R7's cut") def section_l3(): print("L3 lines of order l, r = 3, full rank", flush=True) t0 = time.time() h = lines_hit(Group((2, 2, 2)), 1, (1, 1, 0), 2, terms=7) check("C6 l | f0(0) dropped: q 1, x^3 + x + 1 on (2, 2, 2), 7 terms, " "some sequence hits all 7 lines", max(h) == 7, f"histogram {h}") top = {} for ms, l, q, a0s in [((4, 4, 4), 2, 2, (2,)), ((8, 8, 8), 2, 2, (2,)), ((8, 8, 8), 2, 4, (4,)), ((9, 9, 9), 3, 3, (3, 6))]: G = Group(ms) firsts = homocyclic_firsts(G) hist, pairs = {}, 0 for a0 in a0s: for a1, a2 in local_coeffs(l, G.E, 2): for c, n in lines_hit(G, q, (a0, a1, a2), l, firsts).items(): hist[c] = hist.get(c, 0) + n pairs += 1 top[l] = max(top.get(l, 0), max(hist)) print(f" {ms} q {q}: {pairs} f0, sequences by lines hit " f"{dict(sorted(hist.items()))}, {time.time() - t0:.1f} s", flush=True) check("L3 full rank r = 3: at most B lines, 4 at l = 2, 5 at l = 3", top[2] <= 4 and top[3] <= 5, f"most {top}") def section_l4(rng): print("L4 rank 2 inside cubic f0, case B", flush=True) t0 = time.time() G = Group((8, 8)) g0, g1 = (int(G.index(np.array(v))) for v in ((1, 0), (0, 1))) check("C7 R13's reader says no: (8, 8) q 4 x^3 + 4, g = (1, 0), " "(0, 1), 0 has g_0 off V_1", not r13(G, 4, (4, 0, 0), 2, g0 * G.N ** 2 + g1 * G.N)) bad = top3 = 0 for ms, l, q, a0s, a12 in [ ((8, 8), 2, 4, (4,), [(0, 0)]), ((4, 4), 2, 2, (2,), None), ((8, 8), 2, 2, (2,), None), ((8, 8), 2, 4, (4,), None), ((16, 16), 2, 4, (4,), None), ((9, 9), 3, 3, (3, 6), None), ((27, 27), 3, 3, (3,), [(x, y) for x in (0, 3, 6) for y in (0, 3, 6)])]: G = Group(ms) firsts = homocyclic_firsts(G) hist, pairs, every, read = {}, 0, [], 0 for a0 in a0s: for a1, a2 in a12 or local_coeffs(l, G.E, 2): found = [] for c, n in lines_hit(G, q, (a0, a1, a2), l, firsts, every=found).items(): hist[c] = hist.get(c, 0) + n every.append(((a0, a1, a2), found)) pairs += 1 total = sum(len(f) for _, f in every) cells = [(a, x) for a, f in every for x in f] if total > 2000: cells = rng.sample(cells, 2000) for a, x in cells: read += 1 bad += not r13(G, q, a, l, x) if l == 3: top3 = max(top3, max(hist)) tag = " x^3 + 4" if a12 == [(0, 0)] else "" print(f" {ms} q {q}{tag}: {pairs} f0, sequences by lines hit " f"{dict(sorted(hist.items()))}, R13 read at {read} of " f"{total} hitting all, {time.time() - t0:.1f} s", flush=True) check("L4 R13: every sequence read hitting all l + 1 lines has g_i " "in V_(i+1)", bad == 0, f"{bad} off") print(f" q 3, rank 2: most {top3} lines of 4 (TRANSPLANT predicted " f"4)", flush=True) def primitive_cyclics(G, l): """R15: every with h not in lG, each once.""" lG = set(int(x) for x in G.mul(l)) out, seen = [], set() for h in range(G.N): if h not in lG: S = frozenset(span(G, [h])) if S not in seen: seen.add(S) out.append(S) return out def is_closed(qm, S, elems): """R5: k in W*, q g_k in S give g_k in S; elems the W* terms.""" return all(g in S or int(qm[g]) not in S for g in elems) def binomial_k(G, seq, cyc, lines): """T4's K: a cyclic , h not in lG, through a line no [l] (i < 3) is, else one holding g_0.""" taken = set() for g in seq[:3]: if g: taken.add(next(x for x in span(G, [g]) if lines[x])) free = [S for S in cyc if not any(x in taken for x in S if lines[x])] return free[0] if free else next(S for S in cyc if seq[0] in S) def section_w(rng_bn, full): print("W rank 2 inside cubic f0, x^3 + a0: T4's closed ", flush=True) t0 = time.time() def binomial(G, l, q, a, seqs): qm, lm = G.mul(q), G.mul(l) lines = [bool(x) and lm[x] == 0 for x in range(G.N)] cyc = primitive_cyclics(G, l) return sum(not is_closed(qm, binomial_k(G, s, cyc, lines), [g for g in s if qm[g]]) for s in seqs) G = Group((8, 8)) ctl = binomial(G, 2, 2, (2, 2, 0), (run(G, (2, 2, 0), i0) for i0 in range(G.N ** 3))) check("C11 T4's K at x^3 + 2x + 2 on (8, 8), q 2, is open somewhere", ctl > 0, f"{ctl} sequences") total = fails = pairs = 0 for l, q, small, big in [(2, 2, 32, 256), (2, 4, 32, 256), (2, 8, 0, 256), (3, 3, 27, 243), (3, 9, 0, 243)]: for ms in [x for x in groups(l, big if full else small) if len(x) == 2]: G = Group(ms) if G.E <= q: continue for a0 in sorted({q * u % G.E for u in range(1, G.E) if u % l}): a = (a0, 0, 0) if G.N <= small: ids = range(G.N ** 3) else: ids = [rng_bn.randrange(G.N ** 3) for _ in range(3000)] fails += binomial(G, l, q, a, (run(G, a, i0) for i0 in ids)) total += len(ids) pairs += 1 print(f" BN q {q}: {pairs} (G, a0) pairs so far, {total} " f"sequences, {fails} open, {time.time() - t0:.1f} s", flush=True) check("BN T4's K is closed at every binomial sequence read", fails == 0, f"{total} sequences, {pairs} (G, a0) pairs") def mask_of(idx): m = 0 for i in idx: m |= 1 << int(i) return m class Tree: """T5's engine: G's cyclic subgroups as bitmasks, the , h not in lG, of order l^N2, and a memo for the joins V_k = V_(k+1) + .""" def __init__(self, G, l): self.G, self.l, N, E = G, l, G.N, G.E self.A2 = G.add.reshape(N, N) self.M = np.array([G.mul(j) for j in range(E)]) # [j, x] self.ml = ml = G.mul(l) ordx = np.zeros(N, dtype=np.int64) for x in range(1, N): y, o = x, 0 while y: y, o = int(ml[y]), o + 1 ordx[x] = o self.ordx = ordx self.cyc = [mask_of(set(self.M[:, x])) for x in range(N)] ids = {} self.cid = [ids.setdefault(c, len(ids)) for c in self.cyc] lG = set(int(v) for v in self.ml) self.n1 = int(ordx.max()) self.n2 = int(min(ordx[G.index(np.eye(len(G.ms), dtype=np.int64) [i])] for i in range(len(G.ms)))) seen, self.P = set(), [] for h in range(N): if h in lG or self.cyc[h] in seen: continue seen.add(self.cyc[h]) if ordx[h] == self.n2: self.P.append((h, self.cyc[h])) self.memo = {} def join(self, V, g): key = (V, g) if key not in self.memo: els = [i for i in range(self.G.N) if V >> i & 1] mul = self.M[:, g] self.memo[key] = mask_of(np.unique(self.A2[np.ix_(els, mul)])) return self.memo[key] def suffixes(T, seq): """V_k as bitmasks, k = 0..len(seq) (V_len = 0).""" V = [0] * (len(seq) + 1) V[-1] = 1 for k in range(len(seq) - 1, -1, -1): V[k] = T.join(V[k + 1], seq[k]) return V def closed_ks(T, R, seq, q): """The in R (as (h, mask)) closed for W* = {k : q g_k != 0}.""" mq = T.G.mul(q) W = [(int(mq[g]), g) for g in seq if mq[g]] return [K for K in R if not any(K[1] >> x & 1 and not K[1] >> g & 1 for x, g in W)] def brute_closed(T, R, seq, q): """The in R whose character (a generator of ^perp) is a witness, by direct arithmetic on character values.""" G, E = T.G, T.G.E sc = np.array([E // m for m in G.ms], dtype=np.int64) vals = (G.els * sc) @ G.els.T % E # [chi, x] mq = G.mul(q) W = [g for g in seq if mq[g]] out = [] for h, Km in R: perp = np.flatnonzero(vals[:, h] == 0) chi = perp[np.argmax(T.ordx[perp])] if all(vals[chi, g] == 0 or (q * vals[chi, g]) % E for g in W): out.append((h, Km)) return out def gates(T, R, seq, V, D): """R18's gates in R: (depth, key, class, level, degenerate).""" out = [] for k, g in enumerate(seq): if T.ordx[g] < 2: continue x = int(T.ml[g]) if not any(K[1] >> x & 1 for K in R): continue c, a = (k - D) % 3, (k - D) // 3 deg = c == 0 and bool(V[min(k + 3, len(seq))] >> g & 1) out.append((int(T.ordx[g]) - 1, (T.cid[x], T.cid[g]), c, a, deg)) return out def g1_fails(gs): """G1's reader: gates of both non-D classes, or two X at one depth.""" xs = {} for d, key, c, a, deg in gs: if c: xs.setdefault(d, set()).add(key) return (len({c for d, key, c, a, deg in gs if c}) > 1 or any(len(v) > 1 for v in xs.values())) def g2_fails(gs, deg_as_d=False, shift=0): """G2's reader: two non-degenerate D gates at one depth, or one off its level's X depth. Its plants: deg_as_d counts the degenerate ones too (C15), shift reads the level clause that many levels off (C16).""" xdep = {a: d for d, key, c, a, deg in gs if c} per = {} for d, key, c, a, deg in gs: if c: continue if not deg or deg_as_d: per.setdefault(d, set()).add(key) if not deg and a + shift in xdep and xdep[a + shift] != d: return True return any(len(v) > 1 for v in per.values()) def reach(T, R, seq): """|A_d|, d = 0..N2: the depth-d vertices of R's chains no gate above depth d has broken.""" l, n2 = T.l, T.n2 W = [(int(T.ml[x]), x) for x in seq if T.ordx[x] >= 2] out = [set() for _ in range(n2 + 1)] for h, Km in R: kd = min((int(T.ordx[g]) for x, g in W if Km >> x & 1 and not Km >> g & 1), default=n2 + 1) for d in range(min(kd, n2 + 1)): out[d].add(T.cid[int(T.M[l ** (n2 - d) % T.G.E, h])]) return [len(a) for a in out] def gate_read(T, seq, tally): l, N = T.l, T.G.N V = suffixes(T, seq) if bin(V[0]).count("1") != N: return tally["seqs"] += 1 size = [bin(v).count("1") for v in V] D = next(k for k in range(3) if size[k] == size[k + 1]) tally[f"D{D}"] += 1 if T.n1 == T.n2: Hp = next(V[k] for k in (1, 2) if size[k] * l == N) R = [K for K in T.P if not Hp >> K[0] & 1] else: R = T.P gs = gates(T, R, seq, V, D) tally["g1"] += g1_fails(gs) tally["g2"] += g2_fails(gs) tally["c15"] += g2_fails(gs, deg_as_d=True) tally["c16"] += g2_fails(gs, shift=1) per = {} for d, key, c, a, deg in gs: per.setdefault(d, [set(), 0])[0].add(key) per[d][1] += deg gmax = max((len(p[0]) for p in per.values()), default=0) closed = closed_ks(T, R, seq, l) tally["g3"] += gmax <= l and not closed tally["g4"] += not closed tally["degseq"] += any(x[4] for x in gs) if gmax > l: tally["over"] += 1 tally["over_deg"] += sum(p[1] for p in per.values() if len(p[0]) > l) tally["over_open"] += not closed tally["over_thin"] += min(reach(T, R, seq)[1:]) == 1 def section_g(rng): print("G rank 2 at e = 1: the gate count (R16-T5)", flush=True) t0 = time.time() G = Group((8, 8)) T = Tree(G, 2) ix = lambda *v: int(G.index(np.array(v))) # noqa: E731 seq = run(G, (4, 0, 0), ix(1, 0) * G.N ** 2 + ix(0, 1) * G.N + ix(1, 1)) a, b = closed_ks(T, T.P, seq, 4), brute_closed(T, T.P, seq, 4) ok, n = a == b, len(a) for ms in ((4, 4), (8, 4), (8, 8)): Gm = Group(ms) Tm = Tree(Gm, 2) for i0 in range(1, Gm.N ** 3, 97): s = run(Gm, (2, 2, 0), i0) if bin(suffixes(Tm, s)[0]).count("1") == Gm.N: break ca, cb = closed_ks(Tm, Tm.P, s, 2), brute_closed(Tm, Tm.P, s, 2) ok &= ca == cb n += len(ca) check("C12 the closure reader agrees with the brute character reader " "on C4's sequence and one sequence per q 2 arm", ok, f"{n} closed in all, {len(T.P)} per (8, 8) sequence") crng, plant = random.Random(17241), None for _ in range(200000): lst = [crng.randrange(1, G.N) for _ in range(crng.randrange(3, 9))] if not closed_ks(T, T.P, lst, 2): plant = lst break gm = 0 if plant is not None: per = {} for g in plant: if T.ordx[g] >= 2: per.setdefault(int(T.ordx[g]) - 1, set()).add( (T.cid[int(T.ml[g])], T.cid[g])) gm = max(len(v) for v in per.values()) check("C13 the reader's no: a bare list in (8, 8) with no closed " "among all twelve, its largest g_d above l", gm > 2, f"{[tuple(int(c) for c in G.els[g]) for g in plant or []]}, " f"largest g_d {gm}") fired = read = 0 for f in homocyclic_firsts(G): for rest in range(G.N ** 2): s = run(G, (2, 0, 0), f * G.N ** 2 + rest) V = suffixes(T, s) if bin(V[0]).count("1") != G.N: continue read += 1 size = [bin(v).count("1") for v in V] D = next(k for k in range(3) if size[k] == size[k + 1]) fired += g1_fails(gates(T, T.P, s, V, D)) check("C14 G1's reader fires with R widened to both sides of e " "(x^3 + 2 on (8, 8))", fired > 0, f"{fired} of {read} sequences") arms = [((4, 4), 2, (2,), None), ((8, 4), 2, (2,), None), ((8, 8), 2, (2,), None), ((16, 8), 2, (2,), 2000), ((16, 16), 2, (2,), 2000), ((9, 9), 3, (3,), None), ((27, 27), 3, (3, 6, 12), 2000), ((27, 9), 3, (3,), 2000), ((25, 25), 5, (5,), 2000)] keys = ("seqs", "D0", "D1", "D2", "g1", "g2", "g3", "g4", "c15", "c16", "over", "over_deg", "over_open", "over_thin", "degseq") tot = dict.fromkeys(keys, 0) for ms, l, a0s, draw in arms: G = Group(ms) T = Tree(G, l) for a0 in a0s: fs = [(a0, a1, a2) for a1 in range(0, G.E, l) for a2 in range(0, G.E, l)] t = dict.fromkeys(keys, 0) if draw is None: firsts = homocyclic_firsts(G) or range(G.N) for a in fs: for f in firsts: for rest in range(G.N ** 2): gate_read(T, run(G, a, f * G.N ** 2 + rest), t) else: while t["seqs"] < draw: gate_read(T, run(G, rng.choice(fs), rng.randrange(G.N ** 3)), t) for k in keys: tot[k] += t[k] print(f" {ms} q {l} a0 {a0}: {t['seqs']} generating " f"sequences{' (drawn)' if draw else ''} (D = 0, 1, 2 at " f"{t['D0']}, {t['D1']}, {t['D2']}), |R| <= {len(T.P)}; " f"G1 fails {t['g1']}, G2 {t['g2']}, G3 {t['g3']}; no " f"closed in R at {t['g4']}; a degenerate D gate at " f"{t['degseq']}; g_d > l at {t['over']} ({t['over_deg']} " f"degenerate D terms there, {t['over_open']} with no closed " f", {t['over_thin']} with some |A_d| = 1); " f"{time.time() - t0:.1f} s", flush=True) check("C15 G2's count clause fires with degenerate D gates counted", tot["c15"] > 0, f"{tot['c15']} sequences") check("C16 G2's level clause fires read one level off", tot["c16"] > 0, f"{tot['c16']} sequences") check("G1 R's gates: at most one non-D class, one per depth", tot["g1"] == 0, f"{tot['g1']} sequences") check("G2 one non-degenerate D gate per depth, at its level's X depth", tot["g2"] == 0, f"{tot['g2']} sequences") check("G3 g_d <= l at every depth leaves a closed in R", tot["g3"] == 0, f"{tot['g3']} sequences") print(f" G4 (census) no closed in R at {tot['g4']} of " f"{tot['seqs']} (D = 0, 1, 2 at {tot['D0']}, {tot['D1']}, " f"{tot['D2']}); g_d > l at {tot['over']}, some |A_d| = 1 at " f"{tot['over_thin']}; {time.time() - t0:.1f} s", flush=True) def section_s2(): t0 = time.time() scan = runs = 0 for q, l, tops in [(2, 2, (16, 32, 64)), (4, 2, (16, 32, 64)), (3, 3, (27, 81))]: for top in tops: for ms in groups(l, top, exact=True): G = Group(ms) for u in range(1, G.E): if u % l == 0: continue for a1 in range(G.E): for win in (8, 12): scan += sweep(G, q, (q * u % G.E, a1), nil=False, window=win, terms=win + 3)[1] runs += 1 check("S2 r = 2 without nilpotence, every a_1, W* cut to [0, 8) and " "[0, 12): no hiding", runs > 0 and scan == 0, f"{runs} runs, {scan} hiding, {time.time() - t0:.1f} s") def family(name, l, q, r, orders, a0s, only=None): t0 = time.time() seqs = hid = pairs = 0 for top in orders: for ms in only or groups(l, top, exact=True): if len(ms) == 1 or len(ms) > r or max(ms) <= q: continue G = Group(ms) firsts = homocyclic_firsts(G) for a0 in sorted({a % G.E for a in a0s}): for rest in local_coeffs(l, G.E, r - 1): kept, h, first = sweep(G, q, (a0,) + rest, terms=10 ** 6, firsts=firsts) seqs += kept pairs += 1 if h: hid += h print(f" HIDES G {ms}, f0 coeffs " f"{(a0,) + rest}, {h} tuples, first {first}", flush=True) print(f" {name}: {pairs} (G, f0) pairs, {seqs} sequences, hiding " f"{hid}, {time.time() - t0:.1f} s", flush=True) check(f"{name.split()[0]} no hiding", hid == 0, f"{hid}") def main(): t0 = time.time() full = "--full" in sys.argv control() section_c2() section_l2() section_l3() section_l4(random.Random(4)) section_w(random.Random(6), full) section_g(random.Random(1724)) section_s2() section_k() family("A q 4 cubic, order 64", 2, 4, 3, [64], [4]) family("B q 8 cubic, order 64", 2, 8, 3, [64], [8]) family("C q 9 cubic, order 81", 3, 9, 3, [81], [9, 36, 63]) if full: family("D q 4 quartic, order <= 32", 2, 4, 4, [16, 32], [4 * u for u in range(1, 16, 2)]) family("E q 4, every invariant factor above q", 2, 4, 3, [0], [4], only=[(16, 8), (16, 16), (8, 8, 8), (32, 32)]) family("E q 8, (16, 16)", 2, 8, 3, [0], [8], only=[(16, 16)]) family("E q 9, (27, 27)", 3, 9, 3, [0], [9], only=[(27, 27)]) print(f"{sum(CHECKS)}/{len(CHECKS)} checks pass, " f"{time.time() - t0:.1f} s") return 0 if all(CHECKS) else 1 if __name__ == "__main__": sys.exit(main())