From a41789ca4881f0576f290fd7b8010f3dc7500a7d Mon Sep 17 00:00:00 2001 From: Ali Romman <226877337+aliromman@users.noreply.github.com> Date: Sun, 25 Oct 2026 22:22:29 -0500 Subject: [PATCH 1/3] Retain exact local-recognition and product-character sources --- .../vendor/PR5637.md | 270 +++++++++++++ .../vendor/PR5656.md | 350 +++++++++++++++++ .../vendor/local.py | 370 ++++++++++++++++++ 3 files changed, 990 insertions(+) create mode 100644 research/split-product-tensor-recognition/vendor/PR5637.md create mode 100644 research/split-product-tensor-recognition/vendor/PR5656.md create mode 100644 research/split-product-tensor-recognition/vendor/local.py diff --git a/research/split-product-tensor-recognition/vendor/PR5637.md b/research/split-product-tensor-recognition/vendor/PR5637.md new file mode 100644 index 0000000000..d0c74a3c49 --- /dev/null +++ b/research/split-product-tensor-recognition/vendor/PR5637.md @@ -0,0 +1,270 @@ +# Extension-field tensor recognition and special-linear orbit labels + +This package recognizes, from an arbitrary square tensor over an explicit +finite field K=F_q of characteristic p, the multiplication tensors of + + K[x_1,...,x_s]/(x_i^(p^h_i)), h_i >= 1. + +It returns the heights and three invertible maps U,V,W with +`t(Ua,Vb)=W mu(a,b)`. The empty height list gives K. The test is necessary +and sufficient. It uses deterministic polynomial time in the tensor dimension +for each fixed field. No algebra-class or common-basis promise is required. + +The result also removes the recognition promise from the determinant-character +formula of PR #5459. For each accepted tensor it returns the exact number of +special-linear orbits in its general-linear orbit and a complete orbit label. +Two accepted tensors over the same explicit field are equivalent under the +product of three special linear groups if and only if their height lists and +labels agree. This supplies an executable input test for that atlas interface. +It also constructs determinant-one factor maps between equivalent accepted +tensors. It supplies no physical tensor implementation, paid supplier or kappa increase. + +## Sources and scope + +Main is `6cf7a683f447b9f1e2333791907fd92be5009a63`, priority revision 7. +The [released handoff and claim](https://github.com/CrocSwap/integer-mult-bounds/discussions/1166#discussioncomment-19186074) +identify the extension-field gap. A complete cached open-PR and Discussion +search and a search of every tracked main research README/TASK file found no +active claim on this scope. These searches do not prove global novelty. + +The three proof inputs are pinned in `SOURCES.json`, authenticated on replay, +and preserved without changes. No predecessor executable is imported. + +- Ali Romman's [PR #5540](https://github.com/CrocSwap/integer-mult-bounds/pull/5540) + gives the prime-field tensor reconstruction, the regular-module criterion, + and this extension-field handoff. Its + [retained proof](https://github.com/CrocSwap/integer-mult-bounds/blob/6cf7a683f447b9f1e2333791907fd92be5009a63/research/nonreduced-tensor-recognition/README.md) + credits Nick Petalas's [PR #5252](https://github.com/CrocSwap/integer-mult-bounds/pull/5252) + for the nucleus method and Ali Romman's + [PR #5525](https://github.com/CrocSwap/integer-mult-bounds/pull/5525) for its implementation. +- apoursh's [PR #5502](https://github.com/CrocSwap/integer-mult-bounds/pull/5502) + gives the prime-field height flag and dimension criterion. Its + [retained proof](https://github.com/CrocSwap/integer-mult-bounds/blob/6cf7a683f447b9f1e2333791907fd92be5009a63/research/frobenius-algebra-recognition/PROOF.md) + explicitly leaves extension fields open. +- Ali Romman's [PR #5459](https://github.com/CrocSwap/integer-mult-bounds/pull/5459) + gives the finite-field stabilizer determinant image under an algebra-class + promise. Its + [retained proof](https://github.com/CrocSwap/integer-mult-bounds/blob/6cf7a683f447b9f1e2333791907fd92be5009a63/research/frobenius-tensor-characters/README.md) + supplies the character theorem used below. David Ganz and the atlas lineage + retain credit for the orbit and character framework. + +The new work supplies the finite-field contract, semilinear kernel correction, +composed recognition and orbit label, proof below, and a separate implementation. +It extends the stated local truncated-polynomial class. It does not extend +PR #5540's general commutative-algebra recovery to all residue fields or products. + +## Input and output contract + +`Field(p, modulus)` uses a monic polynomial over F_p, with coefficients in +constant-first order. An element is the integer whose base-p digits are its +polynomial coefficients of degrees less than the modulus degree e. All entries +must be canonical integers from 0 through q-1, where q=p^e. The constructor +checks primality by trial division, builds quotient-ring addition and +multiplication tables, and checks that each nonzero element has an inverse. +A finite commutative unital ring with this property is a field. Thus this test +rejects every reducible modulus, including repeated factors. + +`recognize(t, field)` uses `t[i][j][k]` for the output coefficient k of basis +inputs i,j. All three dimensions must equal n>0. Invalid shapes or entries +raise `ValueError`. A well-formed tensor outside the class returns +`(None, reason)`. Acceptance returns `(certificate, None)`. The certificate +contains `heights`, `U`, `V`, `W`, `sl_orbit_count` and `sl_orbit_label`. +`sl_transporter(first, second, field)` returns determinant-one matrices F,G,H +with `second(Fu,Gv)=H first(u,v)`, or a rejection reason. +Matrix columns are basis images. The field object must retain its constructed +operation tables. Different presentations of the same field require an +explicit field isomorphism before labels can be compared. + +## Reconstruct the local algebra and its factor maps + +Solve the linear nucleus equations + + B = {(X,Y): t(Xu,v)=Y t(u,v) for all u,v}. + +Require dimension n, injective projections to both matrix algebras, +commutativity, and zero right kernel for t. The nucleus is automatically a +unital algebra under componentwise composition: composing two identities gives +the product identity. The faithful Y projection gives coordinates for its +multiplication table and identity. + +Let Q=q^a be the least q-power at least n. The map b -> b^Q is K-linear, +because each coefficient in K is fixed by q-power Frobenius. Its kernel J is +the nilradical. Indeed, in a finite-dimensional commutative unital algebra the +nilradical is nilpotent and J^n=0. A proof uses a finite nilpotent generating +set and the strictly decreasing power chain until zero. Thus this power kills +every nilpotent and kills no other element. Require `dim J=n-1`. Then B is +local with residue field K: every element outside J is a nonzero scalar plus +a nilpotent and has an inverse by the finite geometric series. + +For each nucleus module M=U or W, form JM from the columns of the radical +matrices and require `dim(M/JM)=1`. Choose a coordinate vector m outside JM. +It generates the quotient. For C=Bm, the quotient M/C satisfies M/C=J(M/C). +Iteration through J^n=0 gives M=C. Its dimension equals dim B, so b -> bm is +an isomorphism. Obtain cyclic vectors u0,w0 and matrices + + alpha(b)=X_b u0, gamma(b)=Y_b w0, Phi(v)=t(u0,v). + +If Phi(v)=0, cyclicity of u0 and the nucleus identity give t(U,v)=0. The zero +right kernel makes Phi invertible. Set beta=Phi^-1 gamma. Then + + t(alpha(a),beta(b)) = Y_a gamma(b) = gamma(ab). + +This constructs the three factor maps to B without a search over vectors or +invertible slices. Necessity follows from ordinary multiplication: evaluating +the nucleus identity at 1 in each input shows that both X and Y are +multiplication by the same algebra element. Both modules are regular. +The argument is valid over K; it does not require a prime field. + +## The semilinear height flag + +For h>=0, form C_h by raising each algebra basis element to p^h. With +sigma(c)=c^p on coefficients, the actual map on coordinate vectors is + + F^h(v) = C_h sigma^h(v). + +Consequently a basis of its kernel is obtained by applying sigma^(-h) to a +basis of the ordinary K-linear kernel of C_h. The inverse twist on F_q is +`c -> c^(p^((-h) mod e))`. This is a semilinear change of coordinates, so it +preserves independence and spans the full kernel. An ordinary kernel basis +without this twist need not contain nilpotent elements. Likewise, C_1^h is +not the matrix of F^h: composition twists the next matrix's coefficients. +The implementation computes the actual basis powers separately at each h. + +Let H be the least integer with p^H>=n. Set K_h=ker F^h and + + V_h=(K_h+J^2)/J^2, d_h=dim V_h-dim V_(h-1), + N=p^(sum_h h d_h). + +Choose representatives of each newly independent tangent class directly in +K_h, assign them height h, and call them g_i. Accept exactly when N=n. + +For necessity, in the target algebra J/J^2 has basis the variables. A nonzero +coefficient of x_i with h_i>h survives F^h as a nonzero coefficient of +x_i^(p^h). No other linear term, or term of degree at least two, can cancel +this monomial. The coefficient twist is a field automorphism and cannot turn +a nonzero coefficient into zero. Thus V_h is exactly the span of variables +with height at most h. The flag recovers all heights and N=n. + +For sufficiency, each g_i satisfies its required power relation, and the g_i +span J/J^2. They generate the algebra: expand products in J^k using their +linear parts to obtain `J^k subset C+J^(k+1)`, where C is their unital +subalgebra. Iterate until J^n=0. Substitution therefore gives a surjection +from the proposed truncated-polynomial algebra of dimension N to B. If N=n, +it is an isomorphism. Its matrix C consists of the ordered monomials in g_i. +Compose alpha C, beta C, gamma C to obtain U,V,W. Every basis product of these +maps is checked before acceptance. This proves both directions and supplies +explicit certificates. For n=1, J=0 and the height list is empty. + +The q-power computation is used for the radical. The p-power flag is used for +heights. They cannot be interchanged: over F4, K[x]/x^4 has height two even +though fourth powers already kill its entire radical. + +## Recover the special-linear orbit label + +Let the accepted dimension be n and define + + h=gcd(q-1, n(p^h_1-1)/2, ..., n(p^h_s-1)/2). + +Each exponent is an integer. With no variables, use h=q-1. The pinned PR #5459 +theorem gives the stabilizer determinant image for the covariant action on +`A* tensor A* tensor A`: + + Delta = {(a,b,c): (abc)^((q-1)/h)=1}. + +The empty-height case follows directly: multiplication in K has stabilizer +triples with abc=1. The product of the three determinant-one groups is the +kernel of the determinant map. Hence the number of its orbits in this GL +orbit is h. + +Our certificate gives the tensor action `(U^-T,V^-T,W)`. Its determinant +product is `d=det(W)/(det(U)det(V))`. Define the label + + label = d^((q-1)/h) in K*. + +Two choices of transporter differ by a stabilizer element, whose determinant +product has this power equal to one. The label is therefore intrinsic. The +map `K* -> K*`, d -> d^((q-1)/h), has kernel the h-th power subgroup, exactly +the possible stabilizer products. Its fibers are exactly the cosets of Delta, +so label equality is necessary and sufficient within the fixed height class. +The height list itself is intrinsic by the flag proof. This proves the stated +classification for all accepted tensors. It does not classify tensors outside +this family or claim a new proof of PR #5459's character formula. + +## Construct determinant-one maps + +For two equal-label certificates (U1,V1,W1) and (U2,V2,W2), put +`a=det(U1)/det(U2)`, `b=det(V1)/det(V2)`, `c=det(W1)/det(W2)`. +A model autotopism with these three determinants makes the composite maps +from the first tensor to the second have determinant one. Write the model +autotopism as `(L_x sigma,L_y sigma,L_(xy) sigma)`. Its required automorphism +determinant is `z=ab/c`; its unit determinants must be `a/z` and `b/z`. +Equal labels put z in the character subgroup H_h. + +Find a generator g of K* by enumeration, and write z=g^k. Bezout coefficients +for `h=gcd(q-1,E_1,...,E_s)`, where `E_i=n(p^h_i-1)/2`, give integers b_i +with `sum b_i E_i = h mod (q-1)`. Scale variable i by `g^(b_i k/h)`. +This defines a diagonal algebra automorphism sigma with determinant z. Since +n is a power of p, n is invertible modulo q-1. Scalar units x,y can therefore +supply the required determinants: raise a/z and b/z to that inverse power. +The resulting three model maps have determinants a,b,c. Compose them between +the second certificate and the inverse first certificate. The implementation +checks all three determinants and every transported basis product. This gives +an explicit special-linear transporter without enumerating algebra bases or +automorphisms. Field generator and discrete-log enumeration are bounded by q; +the stated polynomial guarantee remains for fixed q. The empty-height and +q=2 cases use the same formulas with the trivial multiplicative group. + +## Verification and cost + +Run: + +```sh +python3.12 -B scripts/research_package.py --package research/extension-field-tensor-recognition +``` + +The standard library suffices. The registered normal and optimized commands +print `PASS_EXTENSION_FIELD_TENSOR_RECOGNITION`. Every check uses explicit +exceptions and remains active under `-O`. + +The complete F4 2x2x2 domain contains 65,536 tensors. Exactly 13,500 pass, +with exact agreement with a separate orbit generator that applies elementary +GL2 matrices to the three literal coefficient indices. The complete binary +domain gives 54 accepted tensors out of 256. Every accepted transporter is +checked by all basis products. The orbit generator does not use the nucleus, +radical, regular-module or height tests. These complete finite checks do not +replace the written proof in other dimensions. + +Ninety changed-basis presentations cover F2,F3,F4,F8,F9,F16,F25, dimensions +through nine, empty and unequal heights, 2,322 transported products, and 90 +comparisons of orbit labels with known factor maps. Ninety additional +determinant-one transporters pass all 2,322 basis products. The 125 controls include +altered transporters, reducible field polynomials, extra algebra relations, +nonregular dual modules, split algebras and invalid tensors. Over F4, write +a^2=a+1 and use basis `(1,a+x)` for K[x]/x^2. The ordinary kernel of the +squaring columns is `(a^2,1)`, which represents `1+x` and squares to 1. The +correct kernel is `(a,1)`, which represents x and squares to zero. A second +control rejects ordinary matrix iteration. The cutoff-four and two-variable +cutoff-two algebras have orbit counts three and one; all three labels of the +first algebra are attained by explicit output scalings. + +The nucleus has n^3 equations in 2n^2 unknowns. All subsequent steps use +matrix arithmetic, algebra powers and at most ceil(log_p n) kernel levels. +The model monomials are built only after the dimension test accepts, so there +are exactly n. These are deterministic polynomial operations in n at fixed q. +The constructor builds O(q^2) field tables and uses trial-division primality; +there is no polynomial bit-complexity claim in log q. The proof inputs and +finite field operations are checked, but no prior full executable suite, +proof assistant, selected cold replay or independent human review was run. + +## Open next questions + +- Extend the certificate to products and larger residue fields. First specify + component matching and field-isomorphism data; the local residue-K test here + must not be silently removed. +- Use a recognized tensor in a named native producer/consumer pair. Charge its + field representation, coefficients, movement, precision and restoration before + drawing a kappa conclusion. No such physical cost is zero by this result. + +New work: Ali Romman (@aliromman), with substantial OpenAI Codex assistance. +Predecessor methods: apoursh (@apoursh), Nick Petalas (@petalas), David Ganz, +and the linked sources. Apache-2.0. No general literature-priority claim. diff --git a/research/split-product-tensor-recognition/vendor/PR5656.md b/research/split-product-tensor-recognition/vendor/PR5656.md new file mode 100644 index 0000000000..a9f931a378 --- /dev/null +++ b/research/split-product-tensor-recognition/vendor/PR5656.md @@ -0,0 +1,350 @@ +# Determinant characters for split products of Frobenius-truncated algebras + +This note answers the split-product part of the open question in +[Ali Romman's PR5637](https://github.com/CrocSwap/integer-mult-bounds/pull/5637). +The local factor models and a decomposition certificate are supplied. We +derive their product's automorphism determinant image, full covariant tensor +stabilizer image, special-linear orbit label and constructive transporters. +We do not recognize an arbitrary tensor or recover a decomposition from it. +The result is an algebraic interface statement and does not improve kappa. + +## 1. Models and the main formula + +Fix one explicit finite field K = F_q of characteristic p. All algebra +automorphisms and tensor factor maps below are K-linear; coefficient-field +automorphisms are not allowed. Let s >= 1 +and define + + B_j = K[x_(j,1),...,x_(j,r_j)] / (x_(j,i)^(p^h_(j,i))), + A = product_(j=1)^s B_j, + N_j = dim_K B_j = p^(sum_i h_(j,i)), + n = dim_K A = sum_j N_j. + +Each height is a positive integer. An empty height list means B_j = K +and N_j = 1. A factor's **type** is its sorted height list. Within a factor, +use the monomial basis with lexicographically ordered exponent tuples. The +canonical product model orders factor types lexicographically; equal types +are consecutive copies of the same model. + +Set L = q-1, and for every variable define the integer + + E_(j,i) = N_j * (p^h_(j,i) - 1) / 2. + +It is integral: for odd p the second factor is even; for p = 2 every factor +containing a variable has even dimension. Include a swap generator precisely +when q is odd and some type occurs at least twice with odd component +dimension. Its exponent is T = L/2. Set + + g = gcd(L, all E_(j,i), T if that swap generator exists), + H_g = {c^g : c in K*}. + +The gcd of the singleton list (L) is L. This includes field factors with +empty height lists and q = 2, where L = g = 1. Every N_j in this family is +odd when q is odd; the dimension condition identifies the sign's source. + +**Theorem.** The image of Aut_K(A) under determinant is exactly H_g. For +multiplication mu_A and the covariant action on A* tensor A* tensor A, the +full stabilizer determinant image is + + Delta(mu_A) = {(u,v,w) in (K*)^3 : uvw in H_g} + = {(u,v,w) : (uvw)^(L/g) = 1}. + +It has L^3/g elements. The general-linear orbit of mu_A contains exactly g +orbits under SL_n(K)^3. Every allowed determinant triple is attained by an +explicit autotopism. For tensors supplied with verified factor maps, the +canonical type multiset and Section 6's label completely decide +special-linear equivalence. + +## 2. Local type and local determinant character + +We restate the local argument of PR5459 to identify the input to the product +calculation. In B = K[x_1,...,x_r]/(x_i^(p^h_i)), let J = (x_1,...,x_r). +An element with nonzero constant term is a unit by a finite geometric +series; all elements of J are nilpotent. Thus B is local with residue field +K. Its only idempotents are zero and one: one of e and 1-e is a unit, and +e(1-e) = 0 determines an idempotent e. + +The tangent quotient J/J^2 has the variables as a basis. Its intrinsic +height flag is + + V_e = (ker(a -> a^(p^e)) + J^2)/J^2. + +These kernels are K-subspaces even though the power map is semilinear over +an extension field. Frobenius removes mixed terms. A nonzero linear term +in x_i survives the p^e power exactly when h_i > e, and no term of degree +at least two can cancel its degree-p^e monomial. Therefore V_e is exactly +the span of variables of height at most e. Its dimension increments recover +the height multiset. Two displayed local factors are isomorphic if and only +if their types agree; equal dimension alone is insufficient. + +An automorphism's tangent map preserves this flag. Conversely, an invertible +flag-preserving linear substitution respects the defining power relations: +a variable of height h is sent only to variables whose heights are at most +h. Its inverse preserves the same flag, so this substitution is an +automorphism. A general automorphism and its linear substitution induce the +same map on the associated graded algebra for powers of J. A monomial basis +ordered by total degree shows that they have equal determinants. + +The flag-preserving group is generated by allowed elementary substitutions +and diagonal scalings. For an allowed substitution x_i -> x_i + c*x_k, +the monomial expansion is triangular when ordered by x_i exponent, with +diagonal one. Its determinant is one. Scaling x_i -> c*x_i has determinant +c^E_i: the sum of the x_i exponents over the N monomials is + + E_i = N * (p^h_i - 1) / 2. + +Elementary and diagonal matrices generate the full general-linear group +within each equal-height block, while the other allowed elementary matrices +generate the off-diagonal flag-preserving part. Thus the local determinant +image is generated exactly by the subgroups {c^E_i : c in K*}. With an empty +height list, the K-algebra K has only the identity automorphism. + +## 3. Primitive idempotents and the permutation contribution + +An idempotent of A has each coordinate zero or one. The nonzero primitive +idempotents are precisely the e_j supported on a single factor: any +idempotent supported on more than one factor splits into nonzero orthogonal +idempotents. Algebra automorphisms preserve this intrinsic property. + +An automorphism sending e_j to e_k restricts to an isomorphism e_j A -> e_k A, +so those factors have the same type. Conversely, any permutation among +copies of one type, together with an independent automorphism on each factor, +defines an automorphism of A. These are all the possibilities; there are +no additional maps mixing primitive factors. + +Factorwise automorphisms contribute the product of their local determinants. +Swapping two identical factors of dimension N swaps N pairs of matching +basis vectors, so its determinant is (-1)^N. This remains true for blocks +separated by other blocks: those same N basis-vector transpositions describe +the operation. Equivalently, conjugate by a fixed reordering that places the +copies together. For any allowed permutation the sign contribution is + + product_over_types type_permutation_sign^(dimension_of_that_type). + +Hence signs contribute only for repeated isomorphic odd-dimensional factors +in odd characteristic. In characteristic two every sign is one. Unequal +types cannot be swapped, even when they have the same dimension. + +The finite group K* is cyclic of order L. Relative to a generator zeta, the +determinant generators have exponents E_(j,i) and, when present, T = L/2. +They generate precisely = H_g. Each generator is attained by a +literal variable scaling or permitted block transposition. This proves +the automorphism image and its attainment. + +## 4. Unit determinants and the full tensor stabilizer + +For a unit a = (a_j), multiplication by a_j is triangular on its monomials +ordered by total degree. Its constant term c_j is on every diagonal entry. +Consequently + + det(L_a) = product_j c_j^N_j. + +This map is onto K*: choose one component and let all other components +equal one. The chosen N_j is a power of p and is coprime to L, so its scalar +constant can attain any desired determinant. For q = 2 the unit one suffices. +This uses one component dimension N_j, not the total dimension n, which +need not be coprime to L. + +We use the classical unital commutative autotopism normalization retained in +PR5252 and PR5459. Suppose invertible F,G,H satisfy + + F(x) * G(y) = H(x*y). + +Put a = F(1), b = G(1). Evaluation at one gives H(x) = F(x)*b = a*G(x). +Invertibility of F,G,H implies that multiplication by a and b is invertible, +so a and b are units. Then sigma = L_(ab)^(-1) H is a unital algebra +automorphism and + + F = L_a sigma, G = L_b sigma, H = L_(ab) sigma. + +Conversely these maps always form an autotopism. Write x = det L_a, +y = det L_b, z = det sigma. The corresponding covariant stabilizer element +is (F^(-T),G^(-T),H), with determinant triple + + (u,v,w) = (x^(-1) z^(-1), y^(-1) z^(-1), x*y*z). + +Its product is z^(-1), in H_g. Conversely, for a requested triple with +uvw in H_g, set + + z = (u*v*w)^(-1), x = v*w, y = u*w. + +The automorphism and unit determinant constructions attain these three +values and hence the requested triple. This proves the full image formula. +There are L^2 choices for the first two entries and L/g possible products, +so its cardinality is L^3/g. + +## 5. Constructive determinant witnesses + +Fix a generator zeta of K*. For a desired z in H_g, write z = zeta^k +with 0 <= k < L; membership is equivalent to g dividing k. Bezout +coefficients give + + g = b_0 L + sum_(j,i) b_(j,i) E_(j,i) + b_T T, + +omitting the final term when no swap generator exists. Scale variable (j,i) +by zeta^(b_(j,i)*k/g), and compose one fixed permitted transposition to +power b_T*k/g if needed. The resulting determinant is z. Negative +coefficients are allowed because the maps are invertible. If all character +generators are trivial, only z = 1 is requested and the identity suffices. + +For desired unit determinant x, choose a component j and an inverse r of +N_j modulo L. The unit with scalar x^r in that component and one elsewhere +has determinant x. In the trivial multiplicative group use the identity. +Together with Section 4 this constructs every allowed determinant triple. + +Primitive-element and discrete-log enumeration in an explicit finite field +suffice for a fixed q. This is not a polynomial bit-complexity claim in log q. +A different exact subgroup witness search can be used, provided it verifies +the same determinants and transported basis products. + +## 6. Supplied certificates and special-linear labels + +A tensor t: K^n x K^n -> K^n is supplied with model factor types and three +invertible matrices U,V,W, in the convention + + t(U*a,V*b) = W*mu_A(a,b). + +Columns are basis images from the declared model to the tensor. Check the +dimensions, invertibility and all n^2 model basis products. By bilinearity +these finite identities verify the supplied decomposition for all inputs. +They do not provide a procedure for discovering the certificate. + +The reference model must be fixed before comparing labels. Heights inside +each factor are sorted, and factor types are sorted lexicographically. +For another supplied component order, construct the monomial permutation +R from the canonical model to the supplied model, matching full types and +monomial coordinates. Normalize the factor maps to + + U_c = U*R, V_c = V*R, W_c = W*R. + +Thus, with d_raw = det(W)/(det(U)*det(V)), + + d = det(W_c)/(det(U_c)*det(V_c)) = d_raw/det(R), + label(t) = d^(L/g). + +Sorting type metadata alone can lose this permutation sign. If variable +order is also changed inside a supplied factor, its monomial permutation +must also be included, or the interface must require sorted heights from +the start. R changes the reference model coordinates, not the ambient +coordinates of t. + +Two choices of matching among identical factors differ by a model +automorphism, whose determinant lies in H_g, so the label is unchanged. +More generally, two valid certificates from the same canonical model differ +by a tensor stabilizer. Their determinant products differ by an element of +H_g. The label is therefore independent of the certificate. + +For completeness, let G = GL_n(K)^3 and S = SL_n(K)^3. The determinant map +G -> (K*)^3 has kernel S. Since S is normal, its orbits within a fixed +G-orbit correspond to cosets of the stabilizer determinant image. The product +map identifies these cosets with K*/H_g. The map d -> d^(L/g) has kernel +H_g, so its value is a complete label, with exactly g possible values. + +Different type multisets cannot be general-linearly equivalent. An isotopy +between multiplication in two unital commutative algebras normalizes exactly +as in Section 4, using units in the target algebra, to an algebra isomorphism. +It must match primitive idempotents and then local types. Conversely a type +matching gives a literal product algebra isomorphism. For verified +certificates over the same explicit field, therefore, + + SL-equivalent iff canonical type multisets agree and labels agree. + +Different presentations of the finite field need an explicit, checked field +isomorphism before their element-valued labels can be compared. + +## 7. Determinant-one transporters + +Let two normalized certificates (U_1,V_1,W_1) and (U_2,V_2,W_2) have the +same canonical model and label. Put + + a = det(U_1)/det(U_2), + b = det(V_1)/det(V_2), + c = det(W_1)/det(W_2). + +We need a model autotopism (P,Q,R_0) with determinants (a,b,c). In +Section 4's notation choose + + z = a*b/c, x = a/z, y = b/z. + +Equal labels imply (c/(a*b))^(L/g) = 1, hence z belongs to H_g. +Section 5 constructs the required automorphism and units. Then + + F = U_2 * P * U_1^(-1), + G = V_2 * Q * V_1^(-1), + H = W_2 * R_0 * W_1^(-1) + +all have determinant one and satisfy + + t_2(F*x,G*y) = H*t_1(x,y). + +Substitution in the certificate identities proves this. An executable can +also verify the three determinants and every transported basis product. +Unequal labels preclude such maps. + +## 8. Discriminating examples and boundary cases + +Over F_3, let B = F_3[x]/(x^9). Its height list is (2), dimension nine, +and local exponent 9*(9-1)/2 = 36. Since L = 2, the local automorphism +determinant image is {1}; its multiplication orbit splits into two +special-linear orbits. For B x B, a block transposition has determinant +(-1)^9 = -1. The product gcd is gcd(2,36,36,1) = 1, giving only one +special-linear orbit. A product rule using only local characters misses +this change. + +The factors F_3[x]/(x^9) and F_3[y,z]/(y^3,z^3) both have dimension nine, +but their height lists (2) and (1,1) have different tangent dimensions. +A proposed swap is not an algebra automorphism. Equal component size +does not authorize a permutation generator or component match. + +If all heights are empty, A = K^s. For s = 1 the automorphism image is +trivial and g = L. For s >= 2 and odd q, permutations add -1 and g = L/2; +in characteristic two they add nothing and g = L. This agrees with the +split finite-etale case of PR5252. For q = 2 every nonzero determinant and +label is one, and g = 1 for every model. + +Unequal component dimensions add no automorphism generators, but their block +ordering still affects normalization of a supplied certificate. The empty +product and zero-dimensional zero algebra are excluded. An empty height +list inside a nonempty product is a valid field factor. + +## 9. Cost, credit and remaining obligations + +The gcd formula only needs exponents modulo L. Compute +p^(sum_i h_(j,i)) * (p^h_(j,i)-1) modulo 2L and halve its even residue +to obtain E_(j,i) modulo L without materializing a large component dimension. +Modular powers, type comparison and gcd are polynomial in the parameter bit +lengths, given p,q and the finite-field contract. Building and checking +explicit matrices is instead polynomial in the explicit algebra dimension +at fixed q. These are different size statements: a short symbolic height +list can specify an algebra too large to materialize. The executable builds +literal model dimensions and local exponents; the modular method just +described is an arithmetic consequence of the formula, not an implemented +compressed-model runtime guarantee. + +Ali Romman's [PR5459 at bef3575ddb19c44434a7e2460a353eac7c4d9387](https://github.com/aliromman/integer-mult-bounds/blob/bef3575ddb19c44434a7e2460a353eac7c4d9387/research/frobenius-tensor-characters/README.md) +supplies the local height flag and determinant character; those local +results are predecessor work. His +[PR5637 at 86389e525d3efafe236e929f6ae401c68be1d115](https://github.com/aliromman/integer-mult-bounds/blob/86389e525d3efafe236e929f6ae401c68be1d115/research/extension-field-tensor-recognition/README.md) +supplies extension-field recognition, local special-linear labels and the +explicit product handoff. [apoursh's PR5502](https://github.com/CrocSwap/integer-mult-bounds/pull/5502) +supplies the prime-field table height criterion. +[Nick Petalas's PR5252](https://github.com/CrocSwap/integer-mult-bounds/pull/5252) +supplies finite-etale tensor determinants and the normalization lineage. +David Ganz and the retained atlas framework retain their credit. Primitive +idempotents, cyclic subgroup arithmetic and unital isotopy normalization are +classical; no general literature-priority claim is made. + +Open next questions are recovery of this decomposition from an arbitrary +tensor and local factors with residue fields larger than the base. The +latter requires coefficient-field identifications, norms and additional +automorphisms; it does not follow by dropping the residue-field hypothesis. +Neither task is supplied here. Physical coefficient preparation, native +implementation, precision, movement, restoration, supplier admission and +a new multiplication exponent remain outside this result. + +The written theorem covers general finite fields. Executable coverage is +limited to the field contract and domains stated in the package's README; +finite checks are corroboration, not a proof-kernel verification. + +Prepared by apoursh with substantial OpenAI Codex assistance. Apache-2.0. +No independent human or formal proof-kernel acceptance is claimed. diff --git a/research/split-product-tensor-recognition/vendor/local.py b/research/split-product-tensor-recognition/vendor/local.py new file mode 100644 index 0000000000..1066bb74c1 --- /dev/null +++ b/research/split-product-tensor-recognition/vendor/local.py @@ -0,0 +1,370 @@ +"""Exact finite-field tensor recognition. Ali Romman with OpenAI Codex. Apache-2.0.""" +from itertools import product +from math import gcd, isqrt + + +class Field: + """Use base-p digits and a monic polynomial, in constant-first order.""" + + def __init__(self, p, modulus): + if type(p) is not int or p < 2 or any(p % d == 0 for d in range(2, isqrt(p) + 1)): + raise ValueError('p must be prime') + if (not isinstance(modulus, (tuple, list)) or len(modulus) < 2 + or modulus[-1] != 1 + or any(type(c) is not int or not 0 <= c < p for c in modulus)): + raise ValueError('modulus must be monic with canonical prime-field coefficients') + self.p, self.e = p, len(modulus) - 1 + self.modulus = tuple(modulus) + self.q = p ** self.e + digits = [[(a // p ** i) % p for i in range(self.e)] for a in range(self.q)] + self.add = [[sum(((x + y) % p) * p ** i for i, (x, y) in enumerate(zip(a, b))) + for b in digits] for a in digits] + self.neg = [sum((-x % p) * p ** i for i, x in enumerate(a)) for a in digits] + self.mul = [] + for a in digits: + row = [] + for b in digits: + c = [0] * (2 * self.e - 1) + for i, x in enumerate(a): + for j, y in enumerate(b): + c[i + j] = (c[i + j] + x * y) % p + for k in range(len(c) - 1, self.e - 1, -1): + for j in range(self.e): + c[k - self.e + j] = (c[k - self.e + j] - c[k] * modulus[j]) % p + row.append(sum(c[i] * p ** i for i in range(self.e))) + self.mul.append(row) + self.inv = [0] + [self.power(a, self.q - 2) for a in range(1, self.q)] + if any(self.mul[a][self.inv[a]] != 1 for a in range(1, self.q)): + raise ValueError('modulus is reducible') + + def power(self, a, n): + if n < 0: + raise ValueError('negative exponent') + r = 1 + while n: + if n & 1: + r = self.mul[r][a] + a = self.mul[a][a] + n //= 2 + return r + + def total(self, xs): + r = 0 + for x in xs: + r = self.add[r][x] + return r + + +def identity(n): + return [[int(i == j) for j in range(n)] for i in range(n)] + + +def columns(xs, n): + return [[v[i] for v in xs] for i in range(n)] + + +def column(a, j): + return [r[j] for r in a] + + +def rref(a, width, f): + rows = [r[:] for r in a] + pivots = [] + k = 0 + for j in range(width): + pivot = next((i for i in range(k, len(rows)) if rows[i][j]), None) + if pivot is None: + continue + rows[k], rows[pivot] = rows[pivot], rows[k] + rows[k] = [f.mul[f.inv[rows[k][j]]][x] for x in rows[k]] + for i in range(len(rows)): + if i != k and rows[i][j]: + c = f.neg[rows[i][j]] + rows[i] = [f.add[x][f.mul[c][y]] for x, y in zip(rows[i], rows[k])] + pivots.append(j) + k += 1 + if k == len(rows): + break + return rows, pivots + + +def rank(a, f): + return len(rref(a, len(a[0]) if a else 0, f)[1]) + + +def kernel(a, width, f): + rows, pivots = rref(a, width, f) + out = [] + for j in range(width): + if j in pivots: + continue + v = [0] * width + v[j] = 1 + for i, p in enumerate(pivots): + v[p] = f.neg[rows[i][j]] + out.append(v) + return out + + +def inverse(a, f): + n = len(a) + rows, pivots = rref([r + e for r, e in zip(a, identity(n))], n, f) + if len(pivots) != n: + raise ValueError('singular matrix') + return [r[n:] for r in rows] + + +def mv(a, v, f): + return [f.total(f.mul[x][y] for x, y in zip(r, v)) for r in a] + + +def mm(a, b, f): + return columns([mv(a, column(b, j), f) for j in range(len(b[0]))], len(a)) + + +def determinant(a, f): + rows = [r[:] for r in a] + d = 1 + for j in range(len(rows)): + k = next((i for i in range(j, len(rows)) if rows[i][j]), None) + if k is None: + return 0 + if k != j: + rows[k], rows[j] = rows[j], rows[k] + d = f.neg[d] + c = rows[j][j] + d = f.mul[d][c] + for i in range(j + 1, len(rows)): + z = f.neg[f.mul[rows[i][j]][f.inv[c]]] + rows[i] = [f.add[x][f.mul[z][y]] for x, y in zip(rows[i], rows[j])] + return d + + +def tensor_value(t, u, v, f): + n = len(t) + out = [0] * n + for i, x in enumerate(u): + if x: + for j, y in enumerate(v): + if y: + c = f.mul[x][y] + out = [f.add[z][f.mul[c][a]] for z, a in zip(out, t[i][j])] + return out + + +def algebra_power(t, u, exponent, unit, f): + r = unit[:] + while exponent: + if exponent & 1: + r = tensor_value(t, r, u, f) + u = tensor_value(t, u, u, f) + exponent //= 2 + return r + + +def model(heights, f): + bounds = [f.p ** h for h in heights] + exponents = list(product(*(range(b) for b in bounds))) + ix = {v: i for i, v in enumerate(exponents)} + n = len(exponents) + t = [[[0] * n for _ in range(n)] for _ in range(n)] + for i, a in enumerate(exponents): + for j, b in enumerate(exponents): + c = tuple(x + y for x, y in zip(a, b)) + if all(x < bound for x, bound in zip(c, bounds)): + t[i][j][ix[c]] = 1 + return t, exponents + + +def semilinear_kernel(t, unit, h, f): + """Return ker(a -> a^(p^h)), with the coefficient twist removed.""" + n = len(t) + c = columns([algebra_power(t, v, f.p ** h, unit, f) for v in identity(n)], n) + untwist = f.p ** ((-h) % f.e) + return [[f.power(x, untwist) for x in v] for v in kernel(c, n, f)] + + +def validate_tensor(t, f): + if not isinstance(f, Field): + raise ValueError('field contract required') + if not isinstance(t, (list, tuple)) or not t: + raise ValueError('positive square tensor required') + n = len(t) + if any(not isinstance(a, (list, tuple)) or len(a) != n for a in t): + raise ValueError('input dimensions differ') + for a in t: + for b in a: + if not isinstance(b, (list, tuple)) or len(b) != n: + raise ValueError('output dimension differs') + if any(type(x) is not int or not 0 <= x < f.q for x in b): + raise ValueError('noncanonical field entry') + + +def check_certificate(t, cert, f): + """Check the factor maps by all basis products, without nucleus tests.""" + n = len(t) + mu, _ = model(cert['heights'], f) + if len(mu) != n: + return False + u, v, w = (cert[k] for k in ('U', 'V', 'W')) + if any(determinant(a, f) == 0 for a in (u, v, w)): + return False + for i in range(n): + for j in range(n): + if tensor_value(t, column(u, i), column(v, j), f) != mv(w, mu[i][j], f): + return False + return True + + +def recognize(t, f): + """Return (certificate, None), or (None, mathematical rejection reason).""" + validate_tensor(t, f) + n = len(t) + equations = [] + for i, j, k in product(range(n), repeat=3): + row = [0] * (2 * n * n) + for a in range(n): + row[a * n + i] = f.add[row[a * n + i]][t[a][j][k]] + index = n * n + k * n + a + row[index] = f.add[row[index]][f.neg[t[i][j][a]]] + equations.append(row) + basis = kernel(equations, 2 * n * n, f) + if len(basis) != n: + return None, 'nucleus dimension' + xb = [[b[i * n:(i + 1) * n] for i in range(n)] for b in basis] + yb = [[b[n * n + i * n:n * n + (i + 1) * n] for i in range(n)] for b in basis] + if rank([b[:n*n] for b in basis], f) != n or rank([b[n*n:] for b in basis], f) != n: + return None, 'nucleus projection' + if any(mm(a, b, f) != mm(b, a, f) for a in yb for b in yb): + return None, 'noncommutative nucleus' + right = [[t[i][j][k] for j in range(n)] for i in range(n) for k in range(n)] + if rank(right, f) != n: + return None, 'right kernel' + flat = [sum(a, []) for a in yb] + _, positions = rref(flat, n * n, f) + coord_inverse = inverse([[a[j] for a in flat] for j in positions], f) + + def coordinates(a): + v = sum(a, []) + c = mv(coord_inverse, [v[j] for j in positions], f) + if [f.total(f.mul[c[k]][flat[k][j]] for k in range(n)) for j in range(n*n)] != v: + raise ArithmeticError('nucleus closure') + return c + + table = [[coordinates(mm(a, b, f)) for b in yb] for a in yb] + unit = coordinates(identity(n)) + exponent = 1 + while exponent < n: + exponent *= f.q + qmap = columns([algebra_power(table, v, exponent, unit, f) for v in identity(n)], n) + radical = kernel(qmap, n, f) + if len(radical) != n - 1: + return None, 'residue field or number of components' + + def cyclic(module): + actions = [[[f.total(f.mul[c[k]][module[k][i][j]] for k in range(n)) + for j in range(n)] for i in range(n)] for c in radical] + jm = [column(a, j) for a in actions for j in range(n)] + if rank(jm, f) != n - 1: + return None + seed = next(v for v in identity(n) if rank(jm + [v], f) == n) + return columns([mv(a, seed, f) for a in module], n), seed + + ux, wy = cyclic(xb), cyclic(yb) + if ux is None or wy is None: + return None, 'nonregular nucleus module' + u, u0 = ux + w, _ = wy + phi = columns([tensor_value(t, u0, e, f) for e in identity(n)], n) + v = mm(inverse(phi, f), w, f) + span = [tensor_value(table, a, b, f) for a in radical for b in radical] + current = rank(span, f) + generators, heights = [], [] + h, power = 0, 1 + while power < n: + h += 1 + power *= f.p + for a in semilinear_kernel(table, unit, h, f): + new_rank = rank(span + [a], f) + if new_rank > current: + span.append(a) + generators.append(a) + heights.append(h) + current = new_rank + if f.p ** sum(heights) != n: + return None, 'height dimension' + mu, exponents = model(heights, f) + images = [] + for exps in exponents: + value = unit[:] + for g, e in zip(generators, exps): + value = tensor_value(table, value, algebra_power(table, g, e, unit, f), f) + images.append(value) + c = columns(images, n) + if determinant(c, f) == 0: + raise ArithmeticError('height criterion did not produce a basis') + cert = {'heights': heights, 'U': mm(u, c, f), 'V': mm(v, c, f), 'W': mm(w, c, f)} + if not check_certificate(t, cert, f): + raise ArithmeticError('transported product mismatch') + index = gcd(f.q - 1, *(n * (f.p ** h - 1) // 2 for h in heights)) + detu, detv, detw = (determinant(cert[k], f) for k in ('U', 'V', 'W')) + delta = f.mul[detw][f.inv[f.mul[detu][detv]]] + cert['sl_orbit_count'] = index + cert['sl_orbit_label'] = f.power(delta, (f.q - 1) // index) + return cert, None + + +def bezout(a, b): + x, y, u, v = 1, 0, 0, 1 + while b: + quotient, remainder = divmod(a, b) + a, b = b, remainder + x, u = u, x - quotient * u + y, v = v, y - quotient * v + return a, x, y + + +def sl_transporter(first, second, f): + """Return determinant-one maps F,G,H with second(Fu,Gv)=H first(u,v).""" + a, why = recognize(first, f) + if a is None: + return None, 'first tensor: ' + why + b, why = recognize(second, f) + if b is None: + return None, 'second tensor: ' + why + if a['heights'] != b['heights'] or a['sl_orbit_label'] != b['sl_orbit_label']: + return None, 'different special-linear orbits' + n, m = len(first), f.q - 1 + du, dv, dw = [f.mul[determinant(a[k], f)][f.inv[determinant(b[k], f)]] + for k in ('U', 'V', 'W')] + z = f.mul[f.mul[du][dv]][f.inv[dw]] + primitive = next(c for c in range(1, f.q) + if len({f.power(c, i) for i in range(m)}) == m) + logz = next(i for i in range(m) if f.power(primitive, i) == z) + g, coefficients = m, [] + for h in a['heights']: + g, x, y = bezout(g, n * (f.p ** h - 1) // 2) + coefficients = [x * c for c in coefficients] + [y] + if logz % g: + raise ArithmeticError('orbit label disagrees with determinant image') + scalars = [f.power(primitive, (c * (logz // g)) % m) for c in coefficients] + _, exponents = model(a['heights'], f) + diagonal = [1] * n + for j, es in enumerate(exponents): + for c, e in zip(scalars, es): + diagonal[j] = f.mul[diagonal[j]][f.power(c, e)] + inverse_n = pow(n, -1, m) + unit_a = f.power(f.mul[du][f.inv[z]], inverse_n) + unit_b = f.power(f.mul[dv][f.inv[z]], inverse_n) + factors = [unit_a, unit_b, f.mul[unit_a][unit_b]] + out = {} + for key, target, scalar in zip(('U', 'V', 'W'), ('F', 'G', 'H'), factors): + middle = [[f.mul[scalar][diagonal[i]] if i == j else 0 for j in range(n)] for i in range(n)] + out[target] = mm(mm(b[key], middle, f), inverse(a[key], f), f) + if determinant(out[target], f) != 1: + raise ArithmeticError('determinant correction failed') + for i in range(n): + for j in range(n): + if tensor_value(second, column(out['F'], i), column(out['G'], j), f) != mv(out['H'], first[i][j], f): + raise ArithmeticError('special-linear product mismatch') + return out, None From e7acb154bcff76d95dcfd605c14251175a3af13e Mon Sep 17 00:00:00 2001 From: Ali Romman <226877337+aliromman@users.noreply.github.com> Date: Sun, 25 Oct 2026 22:33:04 -0500 Subject: [PATCH 2/3] Recognize split Frobenius products from arbitrary tensors --- .../split-product-tensor-recognition/PROOF.md | 198 ++++++++++++++ .../README.md | 107 ++++++++ .../RESULT.json | 26 ++ .../SOURCES.json | 65 +++++ .../TASK.json | 109 ++++++++ .../VALIDATION.md | 20 ++ .../VERIFY.json | 32 +++ .../recognize.py | 258 ++++++++++++++++++ .../verify.py | 175 ++++++++++++ 9 files changed, 990 insertions(+) create mode 100644 research/split-product-tensor-recognition/PROOF.md create mode 100644 research/split-product-tensor-recognition/README.md create mode 100644 research/split-product-tensor-recognition/RESULT.json create mode 100644 research/split-product-tensor-recognition/SOURCES.json create mode 100644 research/split-product-tensor-recognition/TASK.json create mode 100644 research/split-product-tensor-recognition/VALIDATION.md create mode 100644 research/split-product-tensor-recognition/VERIFY.json create mode 100644 research/split-product-tensor-recognition/recognize.py create mode 100644 research/split-product-tensor-recognition/verify.py diff --git a/research/split-product-tensor-recognition/PROOF.md b/research/split-product-tensor-recognition/PROOF.md new file mode 100644 index 0000000000..b7e7973821 --- /dev/null +++ b/research/split-product-tensor-recognition/PROOF.md @@ -0,0 +1,198 @@ +# Recover split products from arbitrary tensors + +Let K=F_q be an explicitly represented finite field of characteristic p. +For a nonempty list of sorted height lists H=(h_1,...,h_s), put + + A_H = product_j K[x_ji] / (x_ji^(p^h_ji)). + +An empty height list is a field factor K. Sort the component height lists +lexicographically. Each local model uses the monomial order of the retained +PR5637 implementation. This fixes one reference tensor for each type multiset. + +**Result.** For any square tensor t:K^n x K^n -> K^n, the algorithm decides +whether t is isotopic to some A_H. On acceptance it returns H and invertible +U,V,W such that t(Ua,Vb)=W ab. It also returns a complete special-linear orbit +label and constructs determinant-one factor maps between equal-label tensors. +No algebra promise, component list, common input basis or invertible slice is +supplied. The algorithm is deterministic and polynomial in n for fixed K. + +The new result removes the supplied-decomposition premise of PR5656. It uses +the nucleus and local recognition results of PR5252, PR5540 and PR5637, the +height criterion of PR5502, and the product character theorem of PR5656. +These sources retain their credit. This is an algebraic interface result. +It supplies no physical supplier, paid implementation or complete kappa gain. + +## 1. Recover the algebra + +Solve the linear equations + + B = {(X,Y): t(Xu,v)=Y t(u,v) for every u,v}. + +Require dim B=n, injective projections to X and Y, commutativity of the Y +projection, and zero right kernel of t. B is a unital algebra under componentwise +composition. The injective Y projection identifies it with a commutative matrix +algebra and gives a multiplication table and unit by linear coordinates. + +For multiplication in any commutative unital algebra A, setting u=1 shows +Y(v)=X(1)v, and setting v=1 shows X=Y. Thus B is exactly the regular copy of +A. Isotopy transports both representations. All four tests are necessary. +They are not sufficient alone: both nucleus modules must also be regular. + +## 2. Find the radical and every primitive idempotent + +Write J for the nilradical of B. A finite-dimensional commutative algebra has +a decomposition into local Artinian factors. Here is the needed nilpotence +bound. Its radical is nilpotent: choose a finite basis of nilpotent generators; +every sufficiently long monomial contains a generator to a zero power. If two +successive nonzero powers J^k and J^(k+1) were equal, iteration would contradict +nilpotence. Their dimensions strictly decrease until zero. Therefore J^n=0. + +Let Q be the least q-power at least n. The map b -> b^Q is K-linear. Its kernel +is J: it kills J by the bound above, and any element it kills is nilpotent. +This calculates J with exact linear algebra. + +The reduced quotient B/J is a product of finite residue fields. Primitive +idempotents lift uniquely through J. For existence, lift an idempotent to b; +then (b^2-b)^Q=0 gives an idempotent b^Q with the same residue. For uniqueness, +if idempotents e,f differ by an element of J, their commuting products e(1-f) +and f(1-e) are nilpotent idempotents, hence zero. Thus e=f. + +Let C=ker(b -> b^q-b). On each local factor the only fixed elements are the +scalars in K times that factor's unit. Indeed, its residue must lie in F_q. +After subtracting that scalar, a fixed nilpotent z satisfies z=z^(q^a)=0 for +large a. Hence C is K^s, where s is the number of local factors. The dimensions +give the exact split-residue test + + dim(B/J) = dim C. + +Each residue-field degree is positive. Equality holds precisely when every +degree is one. A nonsplit residue field is rejected, even when its q-power +map is invertible. + +Choose any K-basis c_1,...,c_s of C. Start with the part 1. For each c_i and +each lambda in K, refine every current part e by + + e * (1 - (c_i-lambda*1)^(q-1)), + +and discard zero results. In C=K^s this is the characteristic function of the +coordinates where c_i=lambda. The full basis separates every pair of distinct +coordinates. The resulting nonzero parts are exactly the s primitive +idempotents. Stop once s parts are present. This works when s>q; it does not +assume that one element separates all components. It also works with nonzero +nilpotent directions because every c_i belongs to the fixed subalgebra. + +## 3. Recover regular-module generators without enumeration + +For either nucleus module M, let M_j=e_j M. Compute JM_j from the literal +matrix actions. Require dim(M_j/JM_j)=1 for every j. Choose a basis vector of +M_j outside JM_j and call it m_j. Set m=sum_j m_j. + +In a regular module these dimensions are one because the residue fields are +K. Conversely, the cyclic submodule Bm maps onto each component's top. The +quotient N=M/Bm satisfies N=JN. Iteration and J^n=0 give N=0. Thus m is cyclic. +Since dim B=dim M=n, b -> bm is an isomorphism. This proves sufficiency and +gives a deterministic generator selection, without enumerating q^n vectors. + +Let u0,w0 be the generators for the X and Y actions. Define + + alpha(b)=X_b u0, gamma(b)=Y_b w0, Phi(v)=t(u0,v). + +If Phi(v)=0, the nucleus identity and cyclicity give t(u,v)=0 for every u. +The zero right kernel makes Phi invertible. Set beta=Phi^-1 gamma. Then + + t(alpha(a),beta(b)) = Y_a gamma(b) = gamma(ab). + +This gives three factor maps from B to the original tensor. The algorithm +checks each primitive component separately and then checks the generator +matrices for invertibility. + +## 4. Recognize each local factor and fix its basis + +For e_j, obtain a basis for e_j B from the columns of multiplication by e_j. +Restrict the recovered table to that basis. Apply the retained finite-field +recognizer of PR5637. It accepts exactly the split Frobenius-truncated local +algebras. Its semilinear p-power kernels recover the height flag; q-power +Frobenius is used only for the radical. The two operations are not exchanged. + +The local routine returns maps U_j,V_j,W_j with + + U_j(a) V_j(b) = W_j(ab). + +They need not be the same map. Put c=W_j(1). Setting one argument to 1 shows +that U_j(1) and V_j(1) are units: their multiplication maps are compositions of +invertible factor maps. Their product is c. The normalized map + + sigma_j = L_c^-1 W_j + +is a unital algebra isomorphism. Indeed, evaluation at 1 gives +U_j=L_(U_j(1)) sigma_j and V_j=L_(V_j(1)) sigma_j; substitution gives the +multiplication identity for sigma_j. The algorithm applies this normalization. +Treating W_j itself as an algebra isomorphism would be incorrect. + +Embed each sigma_j into B, sort the components by their full height lists, +and concatenate the actual basis columns into C. Set + + U=alpha C, V=beta C, W=gamma C. + +All n^2 transported basis products are checked. Bilinearity makes this a +certificate for all inputs. Rejected local factors cannot be replaced by +equal-dimensional ones: the height multiset is intrinsic. Necessity follows +from the primitive decomposition of A_H and the local recognition theorem. +Sufficiency follows from the explicit maps. This proves the recognition result. + +## 5. Product characters and determinant-one maps + +Use the exact theorem of PR5656. For component dimension N_j=p^(sum_i h_ji), +let E_ji=N_j(p^h_ji-1)/2. Let g be the gcd of q-1 and all these integers, +including (q-1)/2 if q is odd and some full component type repeats. If there +are no variables and no such repetition, g=q-1. The automorphism determinant +image is the subgroup of g-th powers in K*. The covariant tensor stabilizer +has determinant products in that same subgroup. + +Define + + d=det(W)/(det(U)det(V)), label=d^((q-1)/g). + +The full height-type multiset and label decide special-linear equivalence. +The basis concatenation above fixes the component-order determinant sign; +sorting metadata without reordering the matrix columns would lose it. + +For two equal-label certificates, set a=det(U1)/det(U2), b=det(V1)/det(V2), +c=det(W1)/det(W2). Construct a model automorphism sigma of determinant z=ab/c. +Bezout coefficients for the character exponents give it as variable scalings +and, when needed, one transposition of identical odd-dimensional components. +The implementation uses the literal block permutation, not a free scalar sign. + +The unit-multiplication determinant map is onto K*: choose one component of +dimension N_j, which is coprime to q-1, and vary only its scalar constant. +Choose units x,y with determinants a/z,b/z. Then +(L_x sigma,L_y sigma,L_(xy) sigma) has determinants a,b,c. Compose these maps +between the second certificate and the inverse first certificate. The resulting +F,G,H have determinant one and satisfy t2(Fu,Gv)=H t1(u,v). The checker verifies +all three determinants and every basis product. The total product dimension +need not be coprime to q-1; no inverse of that total dimension is used. + +## 6. Cost, use and limits + +The nucleus has n^3 equations in 2n^2 unknowns. Dense elimination uses O(n^7) +field operations. The component refinements use at most n^2 q exponentiations +with exponent q-1; dense algebra multiplication costs O(n^3). The local +recognizers cost at most the sum of their dimension-seventh powers, bounded +by n^7. Module, coordinate and product checks are polynomial as well. A +conservative total bound is O(n^8 + q*n^6*log(q*n) + q^2) field operations, +with polynomial space. This is polynomial in n for fixed q. The explicit +field tables and primitive-element/discrete-log enumeration are not polynomial +bit algorithms in log q. No such uniform claim is made. + +This closes the decomposition-discovery task for the declared split product +class, including extension fields, repeated factors, nilpotents, and independent +tensor factor bases. It does not recognize arbitrary commutative algebras or +nontrivial residue extensions. The tensor atlas can now check this class from +raw tensors and return exact maps. A physical application must still pay for +coefficient operations, native realization, ownership, restoration, storage, +precision and the whole supplier/caller. These costs are unknown here. The +complete kappa calculation and selected frontier are unchanged. + +Ali Romman, with substantial OpenAI Codex assistance. Apache-2.0. The same +assistant supplied the proof and checks. Independent human and formal review +remain open. diff --git a/research/split-product-tensor-recognition/README.md b/research/split-product-tensor-recognition/README.md new file mode 100644 index 0000000000..d02be53c45 --- /dev/null +++ b/research/split-product-tensor-recognition/README.md @@ -0,0 +1,107 @@ +# Split-product tensor recognition + +From an arbitrary square tensor over an explicit finite field, this package +recovers a product of split Frobenius-truncated local algebras, or rejects the +tensor. Acceptance returns the full local height types and three invertible +factor maps. It also gives a complete special-linear orbit label and constructs +determinant-one transporters. The test is necessary and sufficient for this +class and runs in deterministic polynomial time in dimension for fixed q. + +This resolves the decomposition-discovery handoff in +[PR #5656](https://github.com/CrocSwap/integer-mult-bounds/pull/5656). +The earlier result requires supplied component types and factor maps. Here, +Frobenius-fixed spectral projectors recover the primitive factors, the module +top tests recover cyclic generators, and the retained local classifier supplies +the height types. Actual basis columns fix the component-order sign. Nilpotents, +extension fields and independent input/output bases are included. + +Read [PROOF.md](PROOF.md), [recognize.py](recognize.py), and [RESULT.json](RESULT.json). +The maps satisfy `t(Ua,Vb)=W mu(a,b)` and are checked on every basis pair. +`recognize(t, field)` returns `(certificate, None)` or `(None, reason)`. +`sl_transporter(first, second, field)` returns maps F,G,H with determinant one +and `second(Fu,Gv)=H first(u,v)`. The explicit field representation and arithmetic +are retained unchanged from PR5637. Invalid tensor shapes or entries raise +`ValueError`; well-formed tensors outside the class have a rejection reason. + +## Evidence and reproduction + +The standard library suffices. Run with Python 3.12: + +```sh +python3 -B scripts/research_package.py --package research/split-product-tensor-recognition +``` + +Both registered commands must print `PASS_SPLIT_PRODUCT_TENSOR_RECOGNITION`. +The complete two-dimensional domains contain 256, 6,561 and 65,536 tensors. +The independent coefficient-index orbit generator accepts 162, 3,456 and +49,500 tensors, respectively. Every acceptance agrees with the recognizer and +has a literal factor-map check. The oracle does not use a nucleus, radical, +module top or local recognition test. + +There are 62 additional changed-basis presentations, 798 basis products, +62 special-linear transporters and 325 rejection/control checks. These include +products with more components than field elements, repeated nilpotent factors, +wrong residue fields, nonregular modules, incorrect maps and labels, and the +nontrivial component-order sign for F3 times F3[x]/x^9. Finite checks support the +written proof; they do not replace review in other dimensions. + +Source hashes are checked before imports. [SOURCES.json](SOURCES.json) records +the exact upstream commits and the retained, byte-identical source copies. +[VALIDATION.md](VALIDATION.md) records the actual publication checks and limits. + +## Use and limits + +The tensor atlas can now obtain this class and its equivalence maps directly +from tensor coefficients. This is an interface result, with no new complete +kappa or change to the selected frontier. Native realization, coefficient +operations, ownership, restoration, storage, precision and the complete caller +remain unpriced. No multiplier or profitable supplier is claimed. + +Residue fields must equal the supplied field. Arbitrary commutative algebras, +nonsplit residue extensions, and field-presentation changes are outside the +contract. Complexity is polynomial in dimension for fixed q; explicit field +tables and discrete-log enumeration do not give a polynomial bound in log q. +Independent human and formal proof-kernel acceptance remain open. + +Base: `df0137efd35e11b4445734bf612bdd4c7ebc330c`, priority revision 7. +The [advance claim](https://github.com/CrocSwap/integer-mult-bounds/discussions/5655#discussioncomment-19187666) +records the released handoff, scope and overlap coverage. Main's selected +conditional kappa was 0.00310045 at this checkpoint. This package changes no +selected record or predecessor package. + +## Credit + +- apoursh's [PR #5656](https://github.com/CrocSwap/integer-mult-bounds/pull/5656), + head `b5e6e7c45f606d639d102570f9fab257e1d0d393`, supplies the product character + theorem and the decomposition-discovery handoff. Its exact proof is retained + in [vendor/PR5656.md](vendor/PR5656.md). +- Ali Romman's [PR #5637](https://github.com/CrocSwap/integer-mult-bounds/pull/5637), + head `86389e525d3efafe236e929f6ae401c68be1d115`, supplies the finite-field + arithmetic, local tensor recognizer, semilinear height proof and local factor + normalization inputs. The exact executable and proof are retained in vendor. +- The retained sources credit apoursh's + [PR #5502](https://github.com/CrocSwap/integer-mult-bounds/pull/5502) for the + height criterion; Nick Petalas's + [PR #5252](https://github.com/CrocSwap/integer-mult-bounds/pull/5252) for the + nucleus approach; Ali Romman's + [PR #5540](https://github.com/CrocSwap/integer-mult-bounds/pull/5540) and + [PR #5459](https://github.com/CrocSwap/integer-mult-bounds/pull/5459) for local + recovery and characters; and David Ganz for the tensor atlas lineage. + +Primitive decomposition and spectral projectors are classical algebra. The +new contribution is their verified composition with regular-module recovery, +the local recognition algorithm and the product character interface, with no +supplied-decomposition premise. No literature-priority claim is made. + +Prepared by Ali Romman with substantial OpenAI Codex assistance. The same +assistant supplied the proof and verifier. Apache-2.0. + +## Open next questions + +- Recover coefficient-field sections for nonsplit residue factors before + extending the local height test. This needs explicit embeddings and a + nonsplit character theorem. +- Bind one accepted tensor and its maps to a complete paid native caller. + Charge coefficient execution and restoration before claiming a kappa gain. + +The structured first steps and blockers are in [TASK.json](TASK.json). diff --git a/research/split-product-tensor-recognition/RESULT.json b/research/split-product-tensor-recognition/RESULT.json new file mode 100644 index 0000000000..5892393060 --- /dev/null +++ b/research/split-product-tensor-recognition/RESULT.json @@ -0,0 +1,26 @@ +{ + "SL_transporters": 62, + "basis_products": 798, + "exhaustive": [ + { + "accepted": 162, + "q": 2, + "sha256": "02e167732c293afba5ffa3fdeca2464eef6fc0a8f4780c65db8e946376a3c1e0", + "tensors": 256 + }, + { + "accepted": 3456, + "q": 3, + "sha256": "72c1d78d4c5712417876c56f12ba3ee92d864382ac57d798becffdb72b8e9eae", + "tensors": 6561 + }, + { + "accepted": 49500, + "q": 4, + "sha256": "eb70d13e16f6bc6480f5b2ca628f95998c54fc3ba4bcdf7d314d4e83d24a161c", + "tensors": 65536 + } + ], + "presentations": 62, + "rejection_controls": 325 +} diff --git a/research/split-product-tensor-recognition/SOURCES.json b/research/split-product-tensor-recognition/SOURCES.json new file mode 100644 index 0000000000..95f6f04f09 --- /dev/null +++ b/research/split-product-tensor-recognition/SOURCES.json @@ -0,0 +1,65 @@ +{ + "schema_version": 1, + "base_commit": "df0137efd35e11b4445734bf612bdd4c7ebc330c", + "files": [ + { + "path": "docs/research/agent-task-catalog.json", + "usage": "provenance", + "git_blob": "f126dd2e2dad2b669e75d1d0d0bd05c600725602", + "sha256": "f7a48bfa2659b88378282a8eee7d9fe52cdf505594124c4d1686b58510fffd72" + }, + { + "path": "certificates/selected-result.json", + "usage": "provenance", + "git_blob": "581f8d87008354eb5b869f7ed9de1317ad837ce8", + "sha256": "2a0220e866417774606e0f991e41b9c1d26b1f43b97857238cf478dbc7d330b5" + }, + { + "path": "research/split-product-tensor-recognition/vendor/local.py", + "usage": "input", + "git_blob": "1066bb74c19d180bfef7d9dd1c0650ec6bbd7780", + "sha256": "6daa160346d04691c6ca3c9c820b3df8982de4320ec01e5db10e3cb932f42c00", + "pin": "head:a41789ca4881f0576f290fd7b8010f3dc7500a7d:research/split-product-tensor-recognition/vendor/local.py" + }, + { + "path": "research/split-product-tensor-recognition/vendor/PR5637.md", + "usage": "input", + "git_blob": "d0c74a3c49fba38e389b6ef8c714882bdd0bf797", + "sha256": "4b297e57762284c69c7202ee183f43c5fe170fbc9104e4ff0cce3faa345c7c97", + "pin": "head:a41789ca4881f0576f290fd7b8010f3dc7500a7d:research/split-product-tensor-recognition/vendor/PR5637.md" + }, + { + "path": "research/split-product-tensor-recognition/vendor/PR5656.md", + "usage": "input", + "git_blob": "a9f931a378ebf7a67881d209f46c2f7fe47d1041", + "sha256": "0eb6c9f9eba70dc339e54b72a98b5b0fdcef706bcff5e02546ab2d0426a85ad9", + "pin": "head:a41789ca4881f0576f290fd7b8010f3dc7500a7d:research/split-product-tensor-recognition/vendor/PR5656.md" + } + ], + "external_inputs": [ + { + "local_path": "vendor/local.py", + "source_repository": "aliromman/integer-mult-bounds", + "source_commit": "86389e525d3efafe236e929f6ae401c68be1d115", + "source_path": "research/extension-field-tensor-recognition/recognize.py", + "sha256": "6daa160346d04691c6ca3c9c820b3df8982de4320ec01e5db10e3cb932f42c00", + "git_blob": "1066bb74c19d180bfef7d9dd1c0650ec6bbd7780" + }, + { + "local_path": "vendor/PR5637.md", + "source_repository": "aliromman/integer-mult-bounds", + "source_commit": "86389e525d3efafe236e929f6ae401c68be1d115", + "source_path": "research/extension-field-tensor-recognition/README.md", + "sha256": "4b297e57762284c69c7202ee183f43c5fe170fbc9104e4ff0cce3faa345c7c97", + "git_blob": "d0c74a3c49fba38e389b6ef8c714882bdd0bf797" + }, + { + "local_path": "vendor/PR5656.md", + "source_repository": "apoursh/integer-mult-bounds", + "source_commit": "b5e6e7c45f606d639d102570f9fab257e1d0d393", + "source_path": "research/frobenius-product-characters/PROOF.md", + "sha256": "0eb6c9f9eba70dc339e54b72a98b5b0fdcef706bcff5e02546ab2d0426a85ad9", + "git_blob": "a9f931a378ebf7a67881d209f46c2f7fe47d1041" + } + ] +} diff --git a/research/split-product-tensor-recognition/TASK.json b/research/split-product-tensor-recognition/TASK.json new file mode 100644 index 0000000000..d865f3f808 --- /dev/null +++ b/research/split-product-tensor-recognition/TASK.json @@ -0,0 +1,109 @@ +{ + "schema_version": 1, + "task_id": "formal-interface-lemma", + "priority_revision": 7, + "base_commit": "df0137efd35e11b4445734bf612bdd4c7ebc330c", + "original_card": { + "id": "formal-interface-lemma", + "question": "Can one uncovered interface implication be formalized with exact caller and certificate bindings?", + "starting_points": [ + "docs/research/research-family-status.md", + "certificates/selected-result.json", + "research/gate-operand-parity-lean/README.md", + "research/staged544-certified-endpoint/README.md", + "research/unconditional-batched-crt/README.md" + ], + "methods": [ + "Formalize a missing boundary lemma identified by the selected review.", + "Audit a formal theorem-to-certificate binding independently." + ], + "acceptance_gate": "State the exact formalized proposition and remaining assumptions; avoid duplicate arithmetic formalizations already present.", + "first_step": { + "command": [ + "python3", + "-B", + "scripts/research_baseline.py" + ], + "expected": "PASS_RESEARCH_BASELINE_BINDINGS_ONLY", + "inspect": "Inventory the gate-operand parity lemma (#3807) and certified endpoint arithmetic (#3857). Neither is a full multiplication proof. For #4100, audit the compact-switch statement and its hypotheses before formalizing it.", + "scope": "Source-binding orientation only; no scientific replay, theorem acceptance or supplier admission. Budget any heavy replay separately." + }, + "first_experiment": "Write one missing statement with quantified hypotheses, actual caller and existing coverage. A compact-switch lemma is a candidate only after its mathematical contract is reviewed. Establish a bounded proof plan before a separately budgeted proof-assistant build; do not rerun large Lean jobs as orientation.", + "bottleneck_link": "A missing interface proof can reduce the conditional gap even if it does not change kappa.", + "allowed_variations": [ + "Narrow to one formal lemma or one theorem-to-certificate binding." + ], + "scope_change_triggers": [ + "Formalizing already-covered arithmetic and claiming the full multiplication theorem." + ], + "overlap_terms": [ + "hyperplane end", + "formal interface", + "Lean binding", + "3807", + "3857", + "4100", + "gate-operand-parity-lean", + "staged544-certified-endpoint", + "unconditional-batched-crt" + ], + "existing_checks": [ + { + "scope": "PR #3807: scoped gate-operand parity formalization.", + "evidence": "research/gate-operand-parity-lean/README.md", + "remaining": "Exact theorem-to-caller binding and genuinely uncovered interface lemmas.", + "status": "author-checked", + "source_commit": "4c3530f42a6abcc48e7a6bcffd6c901911dc8269", + "selected_record_sha256": "bb2eaa58647b353f88d0aec2eafb9d30df1be53589231b23e12ceef3e4bad129" + }, + { + "scope": "PR #3857: certified real-power moment/endpoint arithmetic.", + "evidence": "research/staged544-certified-endpoint/README.md", + "remaining": "Uniform algorithmic implications, not another endpoint digit.", + "status": "author-checked", + "source_commit": "ef4315b8caa605e47a2515004845eb2d2ed71a86", + "selected_record_sha256": "bb2eaa58647b353f88d0aec2eafb9d30df1be53589231b23e12ceef3e4bad129" + }, + { + "scope": "PR #4100: compact-switch formalization proposed as future validation.", + "evidence": "research/unconditional-batched-crt/README.md", + "remaining": "Audit the statement and assumptions before a formal proof campaign.", + "status": "author-checked", + "source_commit": "337d04939571a637aeab54a0f58f54fde811663a", + "selected_record_sha256": "bb2eaa58647b353f88d0aec2eafb9d30df1be53589231b23e12ceef3e4bad129" + } + ] + }, + "scope_status": "changed", + "actual_scope": "Recognize split products of Frobenius-truncated local algebras from arbitrary finite-field tensors, and return complete SL labels and transporters.", + "scope_change_reason": "Take the released decomposition-discovery handoff of PR5656. This is a written algebraic interface proof with exact checks, rather than a proof-kernel formalization.", + "bottleneck_link": "Remove the supplied algebra decomposition from the tensor atlas interface. A paid native supplier is still required for a kappa gain.", + "budget_minutes": 120, + "stop_rule": "Complete the necessary-and-sufficient split-product test and its literal certificates. Do not start a physical supplier search without a complete cost contract.", + "outcome": "completed", + "evidence": "PROOF.md, recognize.py, verify.py and RESULT.json.", + "author": "Ali Romman", + "ai_assistance": "Substantial OpenAI Codex assistance. The same assistant supplied the proof and verifier; no independent human review.", + "open_questions": [ + { + "question": "Can nonsplit residue fields be recognized with exact coefficient-field embeddings?", + "why_it_matters": "This extends the atlas interface beyond split local factors.", + "first_step": "Specify and check a coefficient-field section in each recovered local component before applying a height classifier.", + "blocked_by": "No such section or nonsplit character theorem is implemented here." + }, + { + "question": "Can a physical supplier use these certified maps at a favorable complete cost?", + "why_it_matters": "Algebraic recognition alone does not increase kappa.", + "first_step": "Choose one actual tensor and charge its coefficient maps, native calls and restoration in a complete caller.", + "blocked_by": "No physical realization or complete paid bill is supplied." + } + ], + "coordination": { + "claim": "https://github.com/CrocSwap/integer-mult-bounds/discussions/5655#discussioncomment-19187666", + "upstream": "df0137efd35e11b4445734bf612bdd4c7ebc330c", + "priority_revision": 7, + "overlap_utc": "2026-10-26T03:20:38+00:00", + "local_notes": 7676, + "coverage": "Complete cached open PR and Discussion pagination; all tracked main README/TASK/ledger notes. No arbitrary diff or unpublished-work coverage." + } +} diff --git a/research/split-product-tensor-recognition/VALIDATION.md b/research/split-product-tensor-recognition/VALIDATION.md new file mode 100644 index 0000000000..99c0b0a978 --- /dev/null +++ b/research/split-product-tensor-recognition/VALIDATION.md @@ -0,0 +1,20 @@ +# Validation + +The registered Python 3.12.14 normal and optimized commands passed. Both +returned the exact RESULT.json data and PASS_SPLIT_PRODUCT_TENSOR_RECOGNITION. +The package runner returned PASS_REGISTERED_RESEARCH_PACKAGE. + +The complete independent tensor-orbit comparison covers 72,353 tensors. +The sign-sensitive F3 times F3[x]/x^9 control also passed. The proof and +implementation received a separate reading by the same assistant; there was +no independent human or proof-kernel review. + +The exact upstream source bytes are retained in the first branch commit and +are checked before executable imports. The branch starts at canonical main +df0137efd35e11b4445734bf612bdd4c7ebc330c. The checkout is shallow. Full-history +source preflight is not claimed; the immediate base and retained-source commit +can be checked as ancestors. The public package is self-contained. + +Committed-byte, export and Git-free replay receipts are recorded in the +publication handoff. Hosted CI and scientific acceptance are separate. +No selected cold replay, physical supplier or complete multiplier was run. diff --git a/research/split-product-tensor-recognition/VERIFY.json b/research/split-product-tensor-recognition/VERIFY.json new file mode 100644 index 0000000000..ed4a1349ba --- /dev/null +++ b/research/split-product-tensor-recognition/VERIFY.json @@ -0,0 +1,32 @@ +{ + "schema_version": 1, + "status": "ready", + "python": "3.12", + "requirements": [], + "inputs": [ + "research/split-product-tensor-recognition/vendor/local.py", + "research/split-product-tensor-recognition/vendor/PR5637.md", + "research/split-product-tensor-recognition/vendor/PR5656.md" + ], + "commands": [ + { + "argv": [ + "{python}", + "-B", + "{package}/verify.py" + ], + "timeout_seconds": 600, + "checks": "Check all 72353 two-dimensional tensors over F2,F3,F4 against separate coefficient-index GL orbits; product and SL fixtures; malformed-map, nonregular-module and nonsplit-residue controls." + }, + { + "argv": [ + "{python}", + "-B", + "-O", + "{package}/verify.py" + ], + "timeout_seconds": 600, + "checks": "Check all 72353 two-dimensional tensors over F2,F3,F4 against separate coefficient-index GL orbits; product and SL fixtures; malformed-map, nonregular-module and nonsplit-residue controls." + } + ] +} diff --git a/research/split-product-tensor-recognition/recognize.py b/research/split-product-tensor-recognition/recognize.py new file mode 100644 index 0000000000..21f1347361 --- /dev/null +++ b/research/split-product-tensor-recognition/recognize.py @@ -0,0 +1,258 @@ +"""Recover split local products. Ali Romman with OpenAI Codex. Apache-2.0.""" +from itertools import product +from math import gcd +from vendor import local as a + + +def span(vectors, n, f): + rows, pivots = a.rref(vectors, n, f) + return rows[:len(pivots)] + + +def coordinate_map(basis, n, f): + _, pivots = a.rref(basis, n, f) + inv = a.inverse([[v[j] for v in basis] for j in pivots], f) + + def coordinates(v): + c = a.mv(inv, [v[j] for j in pivots], f) + if a.mv(a.columns(basis, n), c, f) != v: + raise ArithmeticError('value is outside the declared subspace') + return c + + return coordinates + + +def linear_combination(coefficients, matrices, f): + n = len(matrices[0]) + return [[f.total(f.mul[c][m[i][j]] for c, m in zip(coefficients, matrices)) + for j in range(n)] for i in range(n)] + + +def split_algebra(table, unit, f): + """Return the radical and primitive idempotents, or a residue rejection.""" + n = len(table) + power = 1 + while power < n: + power *= f.q + radical = a.kernel(a.columns([a.algebra_power(table, e, power, unit, f) + for e in a.identity(n)], n), n, f) + qcols = [a.algebra_power(table, e, f.q, unit, f) for e in a.identity(n)] + fixed = a.kernel([[f.add[qcols[j][i]][f.neg[int(i == j)]] + for j in range(n)] for i in range(n)], n, f) + if len(radical) + len(fixed) != n: + return None, 'nonsplit residue field' + parts = [unit] + for c in fixed: + refined = [] + for e in parts: + for scalar in range(f.q): + shifted = [f.add[x][f.neg[f.mul[scalar][y]]] for x, y in zip(c, unit)] + v = a.algebra_power(table, shifted, f.q - 1, unit, f) + projector = [f.add[x][f.neg[y]] for x, y in zip(unit, v)] + piece = a.tensor_value(table, e, projector, f) + if any(piece): + refined.append(piece) + parts = refined + if len(parts) == len(fixed): + break + if len(parts) != len(fixed): + raise ArithmeticError('primitive idempotent count') + return (radical, parts), None + + +def regular_generator(matrices, radical, parts, f): + n = len(matrices[0]) + seed = [0] * n + radical_actions = [linear_combination(c, matrices, f) for c in radical] + for e in parts: + projector = linear_combination(e, matrices, f) + block = span([a.column(projector, j) for j in range(n)], n, f) + jm = span([a.mv(action, v, f) for action in radical_actions for v in block], n, f) + if len(block) - len(jm) != 1: + return None + v = next(v for v in block if a.rank(jm + [v], f) > len(jm)) + seed = [f.add[x][y] for x, y in zip(seed, v)] + matrix = a.columns([a.mv(m, seed, f) for m in matrices], n) + if not a.determinant(matrix, f): + raise ArithmeticError('component generators did not give a regular module') + return matrix, seed + + +def product_model(types, f): + models = [a.model(h, f)[0] for h in types] + n = sum(map(len, models)) + table = [[[0] * n for _ in range(n)] for _ in range(n)] + offset = 0 + for mu in models: + for i, row in enumerate(mu): + for j, value in enumerate(row): + table[offset+i][offset+j][offset:offset+len(mu)] = value + offset += len(mu) + return table + + +def character_index(types, f): + exponents = [f.q-1] + for heights in types: + n = f.p ** sum(heights) + exponents.extend(n * (f.p ** h - 1) // 2 for h in heights) + if f.p != 2 and len({tuple(h) for h in types}) < len(types): + exponents.append((f.q-1)//2) + return gcd(*exponents) + + +def check_certificate(t, cert, f): + """Check literal products and the canonical character label.""" + try: + a.validate_tensor(t, f) + types = cert['types'] + if not types or types != sorted(types): + return False + if any(hs != sorted(hs) or any(type(h) is not int or h < 1 for h in hs) for hs in types): + return False + n = len(t) + if sum(f.p ** sum(hs) for hs in types) != n: + return False + matrices = [cert[k] for k in ('U', 'V', 'W')] + if any(len(m) != n or any(len(row) != n or any(type(x) is not int or not 0 <= x < f.q for x in row) + for row in m) for m in matrices): + return False + if any(not a.determinant(m, f) for m in matrices): + return False + u, v, w = matrices + mu = product_model(types, f) + for i, j in product(range(n), repeat=2): + if a.tensor_value(t, a.column(u, i), a.column(v, j), f) != a.mv(w, mu[i][j], f): + return False + g = character_index(types, f) + delta = f.mul[a.determinant(w, f)][f.inv[f.mul[a.determinant(u, f)][a.determinant(v, f)]]] + return cert['sl_orbit_count'] == g and cert['sl_orbit_label'] == f.power(delta, (f.q-1)//g) + except (KeyError, TypeError, ValueError, IndexError): + return False + + +def recognize(t, f): + """Return a complete product certificate, or a mathematical rejection.""" + a.validate_tensor(t, f) + n = len(t) + equations = [] + for i, j, k in product(range(n), repeat=3): + row = [0] * (2*n*n) + for z in range(n): + row[z*n+i] = f.add[row[z*n+i]][t[z][j][k]] + row[n*n+k*n+z] = f.add[row[n*n+k*n+z]][f.neg[t[i][j][z]]] + equations.append(row) + basis = a.kernel(equations, 2*n*n, f) + if len(basis) != n: + return None, 'nucleus dimension' + xb = [[b[i*n:(i+1)*n] for i in range(n)] for b in basis] + yb = [[b[n*n+i*n:n*n+(i+1)*n] for i in range(n)] for b in basis] + if any(a.rank([b[start:start+n*n] for b in basis], f) != n for start in (0, n*n)): + return None, 'nucleus projection' + if any(a.mm(x, y, f) != a.mm(y, x, f) for x in yb for y in yb): + return None, 'noncommutative nucleus' + if a.rank([[t[i][j][k] for j in range(n)] for i in range(n) for k in range(n)], f) != n: + return None, 'right kernel' + coordinates = coordinate_map([sum(m, []) for m in yb], n*n, f) + table = [[coordinates(sum(a.mm(x, y, f), [])) for y in yb] for x in yb] + unit = coordinates(sum(a.identity(n), [])) + split, reason = split_algebra(table, unit, f) + if split is None: + return None, reason + radical, parts = split + ux, wy = (regular_generator(ms, radical, parts, f) for ms in (xb, yb)) + if ux is None or wy is None: + return None, 'nonregular nucleus module' + u, u0 = ux + w, _ = wy + phi = a.columns([a.tensor_value(t, u0, e, f) for e in a.identity(n)], n) + v = a.mm(a.inverse(phi, f), w, f) + factors = [] + for e in parts: + block = span([a.tensor_value(table, e, x, f) for x in a.identity(n)], n, f) + coord = coordinate_map(block, n, f) + local = [[coord(a.tensor_value(table, x, y, f)) for y in block] for x in block] + cert, reason = a.recognize(local, f) + if cert is None: + return None, 'local factor: '+reason + # Normalize the local output map to a unital algebra isomorphism. + image_one = a.column(cert['W'], 0) + multiply_one = a.columns([a.tensor_value(local, image_one, x, f) + for x in a.identity(len(block))], len(block)) + sigma = a.mm(a.inverse(multiply_one, f), cert['W'], f) + images = a.mm(a.columns(block, n), sigma, f) + factors.append((cert['heights'], images)) + factors.sort(key=lambda item: item[0]) + change = a.columns([a.column(m, j) for _, m in factors for j in range(len(m[0]))], n) + cert = {'types': [hs for hs, _ in factors], 'U': a.mm(u, change, f), + 'V': a.mm(v, change, f), 'W': a.mm(w, change, f)} + g = character_index(cert['types'], f) + du, dv, dw = (a.determinant(cert[k], f) for k in ('U', 'V', 'W')) + cert['sl_orbit_count'] = g + cert['sl_orbit_label'] = f.power(f.mul[dw][f.inv[f.mul[du][dv]]], (f.q-1)//g) + if not check_certificate(t, cert, f): + raise ArithmeticError('product certificate failed') + return cert, None + + +def sl_transporter(first, second, f): + one, why = recognize(first, f) + if one is None: + return None, 'first tensor: '+why + two, why = recognize(second, f) + if two is None: + return None, 'second tensor: '+why + if one['types'] != two['types'] or one['sl_orbit_label'] != two['sl_orbit_label']: + return None, 'different special-linear orbits' + types, n, length = one['types'], len(first), f.q-1 + du, dv, dw = [f.mul[a.determinant(one[k], f)][f.inv[a.determinant(two[k], f)]] + for k in ('U', 'V', 'W')] + z = f.mul[f.mul[du][dv]][f.inv[dw]] + primitive = next(x for x in range(1, f.q) if len({f.power(x, j) for j in range(length)}) == length) + logz = next(j for j in range(length) if f.power(primitive, j) == z) + generators = [] + offset = 0 + starts = [] + for hs in types: + size = f.p ** sum(hs) + starts.append((offset, size)) + for i, h in enumerate(hs): + generators.append((size*(f.p**h-1)//2, ('scale', offset, hs, i))) + offset += size + repeated = next((i for i in range(1, len(types)) if types[i] == types[i-1]), None) + if f.p != 2 and repeated is not None: + generators.append((length//2, ('swap', repeated-1, repeated))) + g, weights = length, [] + for exponent, _ in generators: + g, x, y = a.bezout(g, exponent) + weights = [x*c for c in weights]+[y] + if logz % g: + raise ArithmeticError('character witness failed') + sigma = a.identity(n) + for weight, (_, operation) in zip(weights, generators): + coefficient = weight*(logz//g) + if operation[0] == 'scale': + _, start, hs, index = operation + scalar = f.power(primitive, coefficient % length) + for j, exps in enumerate(a.model(hs, f)[1]): + sigma[start+j] = [f.mul[f.power(scalar, exps[index])][x] for x in sigma[start+j]] + elif coefficient % 2: + _, left, right = operation + lstart, size = starts[left] + rstart, _ = starts[right] + for j in range(size): + sigma[lstart+j], sigma[rstart+j] = sigma[rstart+j], sigma[lstart+j] + size = starts[0][1] + inverse_size = pow(size, -1, length) + x = f.power(f.mul[du][f.inv[z]], inverse_size) + y = f.power(f.mul[dv][f.inv[z]], inverse_size) + out = {} + for key, target, scalar in zip(('U', 'V', 'W'), ('F', 'G', 'H'), (x, y, f.mul[x][y])): + middle = [[f.mul[scalar if i < size else 1][value] for value in row] for i, row in enumerate(sigma)] + out[target] = a.mm(a.mm(two[key], middle, f), a.inverse(one[key], f), f) + if any(a.determinant(m, f) != 1 for m in out.values()): + raise ArithmeticError('special-linear determinant') + for i, j in product(range(n), repeat=2): + if a.tensor_value(second, a.column(out['F'], i), a.column(out['G'], j), f) != a.mv(out['H'], first[i][j], f): + raise ArithmeticError('special-linear product') + return out, None diff --git a/research/split-product-tensor-recognition/verify.py b/research/split-product-tensor-recognition/verify.py new file mode 100644 index 0000000000..e173eed25d --- /dev/null +++ b/research/split-product-tensor-recognition/verify.py @@ -0,0 +1,175 @@ +"""Check the product recognizer. Ali Romman with OpenAI Codex. Apache-2.0.""" +import copy +import hashlib +import itertools +import json +from pathlib import Path +import random +import sys +from collections import deque + +HERE = Path(__file__).resolve().parent +sys.path.insert(0, str(HERE)) + + +def require(ok, message): + if not ok: + raise RuntimeError(message) + + +def changed(t, u, v, w, f): + n = len(t) + ui, vi = r.a.inverse(u, f), r.a.inverse(v, f) + return [[r.a.mv(w, r.a.tensor_value(t, r.a.column(ui, i), r.a.column(vi, j), f), f) + for j in range(n)] for i in range(n)] + + +def random_gl(n, f, rng, special=False): + m = r.a.identity(n) + for _ in range(4*n): + if n > 1: + i, j = rng.sample(range(n), 2) + c = rng.randrange(f.q) + m[i] = [f.add[x][f.mul[c][y]] for x, y in zip(m[i], m[j])] + if not special: + for i in range(n): + c = rng.randrange(1, f.q) + m[i] = [f.mul[c][x] for x in m[i]] + return m + + +def orbit(f, seeds): + """Apply GL2 generators directly to the three coefficient indices.""" + generators = [[[0,1],[1,0]]] + generators.extend([[[1,c],[0,1]] for c in range(1,f.q)]) + generators.extend([[[c,0],[0,1]] for c in range(2,f.q)]) + + def pack(vals): + return sum(c*f.q**i for i,c in enumerate(vals)) + + seen = {pack(sum(sum(t, []), [])) for t in seeds} + queue = deque(seen) + while queue: + code = queue.popleft() + vals = [(code//f.q**i)%f.q for i in range(8)] + for axis in (1,2,4): + for m in generators: + out = vals[:] + for i in range(8): + if not i & axis: + x,y = vals[i],vals[i+axis] + out[i] = f.add[f.mul[m[0][0]][x]][f.mul[m[0][1]][y]] + out[i+axis] = f.add[f.mul[m[1][0]][x]][f.mul[m[1][1]][y]] + value = pack(out) + if value not in seen: + seen.add(value) + queue.append(value) + return seen + + +def exhaustive(f): + seeds = [r.product_model([[],[]],f)] + if f.p == 2: + seeds.append(r.product_model([[1]],f)) + expected = orbit(f,seeds) + accepted = 0 + digest = hashlib.sha256() + for code in range(f.q**8): + vals = [(code//f.q**i)%f.q for i in range(8)] + t = [[vals[4*i+2*j:4*i+2*j+2] for j in range(2)] for i in range(2)] + cert, why = r.recognize(t,f) + require((cert is not None) == (code in expected), str((f.q,code,why))) + if cert is not None: + require(r.check_certificate(t,cert,f),'literal exhaustive certificate') + accepted += 1 + digest.update(code.to_bytes(4,'big')) + return {'q':f.q,'tensors':f.q**8,'accepted':accepted,'sha256':digest.hexdigest()} + + +def main(): + sources = json.loads((HERE/'SOURCES.json').read_text()) + for item in sources['external_inputs']: + require(hashlib.sha256((HERE/item['local_path']).read_bytes()).hexdigest() == item['sha256'], 'retained source changed') + global r + import recognize as r + fields = [r.a.Field(2,[0,1]),r.a.Field(3,[0,1]),r.a.Field(2,[1,1,1]), + r.a.Field(2,[1,1,0,1]),r.a.Field(3,[1,0,1])] + rng = random.Random(56565637) + fixtures = products = transports = controls = 0 + for f in fields: + for types in [[[]],[[],[]],[[],[],[]],[[],[1]],[[1],[1]],[[],[2]],[[],[1,1]]]: + types = sorted(types) + mu = r.product_model(types,f) + n = len(mu) + if n > 9: + continue + for _ in range(2): + u,v,w = (random_gl(n,f,rng) for _ in range(3)) + t = changed(mu,u,v,w,f) + cert,why = r.recognize(t,f) + require(cert is not None, str((f.q,types,why))) + require(cert['types'] == types and r.check_certificate(t,cert,f),'factor types or products') + delta = f.mul[r.a.determinant(w,f)][f.inv[f.mul[r.a.determinant(u,f)][r.a.determinant(v,f)]]] + require(cert['sl_orbit_label'] == f.power(delta,(f.q-1)//cert['sl_orbit_count']),'label independent of recovered basis') + other = changed(t,*(random_gl(n,f,rng,True) for _ in range(3)),f) + maps,why = r.sl_transporter(t,other,f) + require(maps is not None, str(why)) + require(all(r.a.determinant(m,f)==1 for m in maps.values()),'SL determinant') + for i,j in itertools.product(range(n),repeat=2): + require(r.a.tensor_value(other,r.a.column(maps['F'],i),r.a.column(maps['G'],j),f) + == r.a.mv(maps['H'],t[i][j],f),'SL literal coefficient') + fixtures += 1 + products += n*n + transports += 1 + for key in ('U','V','W'): + bad = copy.deepcopy(cert) + bad[key][0][0] = f.add[bad[key][0][0]][1] + require(not r.check_certificate(t,bad,f),'changed factor accepted') + controls += 1 + for key in ('sl_orbit_count','sl_orbit_label'): + bad = copy.deepcopy(cert); bad[key] = 0 + require(not r.check_certificate(t,bad,f),'changed character accepted') + controls += 1 + # A nonsplit quadratic field is outside the declared product class. + if f.q in (2,3): + c = 1 if f.q == 2 else 2 + d = 1 if f.q == 2 else 0 + ext = [[[1,0],[0,1]],[[0,1],[c,d]]] + require(r.recognize(ext,f)[1] == 'nonsplit residue field','nonsplit field accepted') + controls += 1 + # The square-zero local algebra has two tangent generators and dimension 3. + square = [[[0]*3 for _ in range(3)] for _ in range(3)] + for i in range(3): + square[0][i][i] = square[i][0][i] = 1 + require(r.recognize(square,f)[0] is None,'extra local relation accepted') + dual = [[[square[i][k][j] for k in range(3)] for j in range(3)] for i in range(3)] + require(r.recognize(dual,f)[1] == 'nonregular nucleus module','nonregular dual accepted') + controls += 2 + # Over F4 the repeated field factors have three SL classes. + f = fields[2] + mu = r.product_model([[],[]],f) + labels = set() + for c in range(1,f.q): + w = [[c,0],[0,1]] + t = changed(mu,r.a.identity(2),r.a.identity(2),w,f) + labels.add(r.recognize(t,f)[0]['sl_orbit_label']) + if c != 1: + require(r.sl_transporter(mu,t,f)[0] is None,'unequal SL labels accepted') + controls += 1 + require(labels == {1,2,3},'missing split-product SL class') + # The component permutation sign must be applied to the actual factor maps. + f = fields[1] + mu = r.product_model([[],[2]],f) + permutation = r.a.identity(10)[9:]+r.a.identity(10)[:9] + t = changed(mu,permutation,permutation,permutation,f) + cert,_ = r.recognize(t,f) + require(cert['sl_orbit_count'] == 2 and cert['sl_orbit_label'] == 2,'component-order sign') + controls += 1 + out = {'presentations':fixtures,'basis_products':products,'SL_transporters':transports, + 'rejection_controls':controls,'exhaustive':[exhaustive(f) for f in fields[:3]]} + print(json.dumps(out,sort_keys=True)) + print('PASS_SPLIT_PRODUCT_TENSOR_RECOGNITION') + + +if __name__ == '__main__': + main() From 5d722279f4292c63361f1e958ff4ed5a6ec638aa Mon Sep 17 00:00:00 2001 From: Ali Romman <226877337+aliromman@users.noreply.github.com> Date: Sun, 25 Oct 2026 22:34:26 -0500 Subject: [PATCH 3/3] Credit the reduced spectral-projector predecessor --- research/split-product-tensor-recognition/PROOF.md | 4 ++++ research/split-product-tensor-recognition/README.md | 3 ++- research/split-product-tensor-recognition/SOURCES.json | 6 ++++++ 3 files changed, 12 insertions(+), 1 deletion(-) diff --git a/research/split-product-tensor-recognition/PROOF.md b/research/split-product-tensor-recognition/PROOF.md index b7e7973821..c3d085b38a 100644 --- a/research/split-product-tensor-recognition/PROOF.md +++ b/research/split-product-tensor-recognition/PROOF.md @@ -40,6 +40,10 @@ They are not sufficient alone: both nucleus modules must also be regular. ## 2. Find the radical and every primitive idempotent +This extends Nick Petalas's fixed-algebra spectral projectors in PR5252 from +the reduced case to algebras with a nilradical. The projector formula itself +is retained mathematical precedent. + Write J for the nilradical of B. A finite-dimensional commutative algebra has a decomposition into local Artinian factors. Here is the needed nilpotence bound. Its radical is nilpotent: choose a finite basis of nilpotent generators; diff --git a/research/split-product-tensor-recognition/README.md b/research/split-product-tensor-recognition/README.md index d02be53c45..e93cfcf8cf 100644 --- a/research/split-product-tensor-recognition/README.md +++ b/research/split-product-tensor-recognition/README.md @@ -83,7 +83,8 @@ selected record or predecessor package. [PR #5502](https://github.com/CrocSwap/integer-mult-bounds/pull/5502) for the height criterion; Nick Petalas's [PR #5252](https://github.com/CrocSwap/integer-mult-bounds/pull/5252) for the - nucleus approach; Ali Romman's + nucleus approach and the reduced-case Frobenius-fixed spectral projectors; + Ali Romman's [PR #5540](https://github.com/CrocSwap/integer-mult-bounds/pull/5540) and [PR #5459](https://github.com/CrocSwap/integer-mult-bounds/pull/5459) for local recovery and characters; and David Ganz for the tensor atlas lineage. diff --git a/research/split-product-tensor-recognition/SOURCES.json b/research/split-product-tensor-recognition/SOURCES.json index 95f6f04f09..d45856d604 100644 --- a/research/split-product-tensor-recognition/SOURCES.json +++ b/research/split-product-tensor-recognition/SOURCES.json @@ -34,6 +34,12 @@ "git_blob": "a9f931a378ebf7a67881d209f46c2f7fe47d1041", "sha256": "0eb6c9f9eba70dc339e54b72a98b5b0fdcef706bcff5e02546ab2d0426a85ad9", "pin": "head:a41789ca4881f0576f290fd7b8010f3dc7500a7d:research/split-product-tensor-recognition/vendor/PR5656.md" + }, + { + "path": "research/etale-tensor-determinant-image/README.md", + "usage": "provenance", + "git_blob": "0f07df6ce2a8c43ea1fcc5f0081ee3532da28208", + "sha256": "2ec18042a1a63d5fd5da246f4f6060c5fb66cff338f25a2a1b95e3ea8b4f0fba" } ], "external_inputs": [