#!/usr/bin/env python3
"""
Computation 57 -- The 3 quaternionic sub-algebras of O containing a fixed C
=============================================================================
Per research/ngen_3.md section 16 (and Furey's structural argument), the
N_gen = 3 derivation requires breaking the G_2 automorphism symmetry of O
down to the stabilizer of a preferred complex sub-algebra C ⊂ O.  Once
C is fixed, a classical fact about the octonions guarantees exactly 3
quaternionic sub-algebras containing C.

This script verifies the count explicitly and characterizes the structure:
  - Fix C = {1, e_1} subset O (i.e., preferred imaginary unit = e_1)
  - Enumerate all quaternionic sub-algebras of O containing C
  - Verify: exactly 3
  - Characterize: each is determined by a Fano-plane line through e_1
  - Show: the 3 sub-algebras partition Im(O)\{e_1} = {e_2, ..., e_7}
    into 3 pairs, one per generation

This is the structural seed of N_gen = 3 if PST's modal threshold tau
is Im(O)-valued (the proposed refinement).
"""
from itertools import combinations


# Octonion multiplication table (from Comp 52)
def O_mult_table():
    n = 8
    table = [[(0, 0) for _ in range(n)] for _ in range(n)]
    for i in range(n):
        table[0][i] = (1, i); table[i][0] = (1, i)
    for i in range(1, 8):
        table[i][i] = (-1, 0)
    triples = [(1, 2, 3), (1, 4, 5), (1, 7, 6),
               (2, 4, 6), (2, 5, 7), (3, 4, 7), (3, 6, 5)]
    for i, j, k in triples:
        table[i][j] = (1, k); table[j][i] = (-1, k)
        table[j][k] = (1, i); table[k][j] = (-1, i)
        table[k][i] = (1, j); table[i][k] = (-1, j)
    return table


O_T = O_mult_table()


def is_quaternionic_triple(a, b):
    """Return c such that {1, a, b, c} forms a quaternionic sub-algebra of O,
    or None if a*b does not generate a third imaginary unit.

    Quaternionic if a*b = ±e_c for some c != 0, c != a, c != b.
    """
    sign, idx = O_T[a][b]
    if idx == 0 or idx == a or idx == b:
        return None
    return idx, sign


def quaternionic_subalgebras_containing(fixed_unit):
    """List all quaternionic sub-algebras of O containing {1, e_{fixed_unit}}.

    A quaternionic sub-algebra is Q = span{1, a, b, a*b} with a, b, a*b ∈ Im(O)
    pairwise distinct and anti-commuting.  We list each as a frozenset of the
    three imaginary units {a, b, a*b}.
    """
    subs = set()
    for b in range(1, 8):
        if b == fixed_unit:
            continue
        triple = is_quaternionic_triple(fixed_unit, b)
        if triple is None:
            continue
        c, _ = triple
        if c == 0:
            continue
        # Sub-algebra spanned by {fixed_unit, b, c}
        subs.add(frozenset([fixed_unit, b, c]))
    return sorted(subs, key=lambda s: tuple(sorted(s)))


def main():
    print("=" * 90)
    print("  Computation 57 -- 3 quaternionic sub-algebras of O containing fixed C")
    print("=" * 90)
    print()

    print("  (1) Octonion multiplication structure:")
    print("      7 quaternionic triples (Fano-plane lines):")
    for (i, j, k) in [(1, 2, 3), (1, 4, 5), (1, 7, 6),
                      (2, 4, 6), (2, 5, 7), (3, 4, 7), (3, 6, 5)]:
        print(f"        e_{i} * e_{j} = +e_{k}")
    print()

    print("  (2) Fix preferred complex sub-algebra C = {1, e_1}:")
    fixed = 1
    Q_subs = quaternionic_subalgebras_containing(fixed)
    print(f"      Quaternionic sub-algebras of O containing e_{fixed}:")
    for k, Q in enumerate(Q_subs, 1):
        others = sorted(Q - {fixed})
        print(f"        Q_{k} = {{1, e_{fixed}, e_{others[0]}, e_{others[1]}}}")
    print()
    print(f"      Count: {len(Q_subs)}  (expected 3)")
    print()

    # Verify each is genuinely quaternionic by checking closure
    print("  (3) Verify each Q_k is a genuine sub-algebra:")
    for k, Q in enumerate(Q_subs, 1):
        a, b, c = sorted(Q)
        # Check all products a*b, b*c, c*a land back in {±1, ±a, ±b, ±c}
        elements = {0, a, b, c}
        ok = True
        for x in Q:
            for y in Q:
                sign, idx = O_T[x][y]
                if idx not in elements:
                    ok = False
                    break
            if not ok:
                break
        print(f"        Q_{k} closed under multiplication: {ok}")
    print()

    # Show the partition of Im(O)\{e_1}
    print("  (4) Partition structure:")
    print(f"      Im(O) \\ {{e_{fixed}}} = {{e_2, e_3, e_4, e_5, e_6, e_7}} (6 units)")
    print(f"      Each Q_k contributes 2 'extra' units (besides e_{fixed}):")
    extras = []
    for k, Q in enumerate(Q_subs, 1):
        ex = sorted(Q - {fixed})
        print(f"        Q_{k} contributes {{e_{ex[0]}, e_{ex[1]}}}")
        extras.append(set(ex))

    # Check disjoint
    overlap = set.intersection(*extras)
    union = set.union(*extras)
    print(f"      Pairwise intersection of extras: {overlap if overlap else 'empty'}")
    print(f"      Union: {sorted(union)} (should be {{2,3,4,5,6,7}})")
    if union == {2, 3, 4, 5, 6, 7} and not overlap:
        print(f"      => PARTITION verified: 6 = 3 * 2, three generations naturally identified")
    print()

    # ---- Verify the count is robust under choice of fixed unit ----
    print("  (5) Robustness: does the count = 3 depend on which imaginary unit is fixed?")
    counts = {}
    for u in range(1, 8):
        counts[u] = len(quaternionic_subalgebras_containing(u))
    print(f"      Counts for each fixed unit u: {dict(counts)}")
    if all(v == 3 for v in counts.values()):
        print(f"      => 3 is INDEPENDENT of which imaginary unit is selected (G_2-symmetric statement)")
    print()

    # ---- Total number of quaternionic sub-algebras of O ----
    print("  (6) Sanity: total number of quaternionic sub-algebras of O:")
    all_subs = set()
    for u in range(1, 8):
        all_subs.update(quaternionic_subalgebras_containing(u))
    print(f"      Total: {len(all_subs)} (expected 7, one per Fano-plane line)")
    # Each is counted 3 times (once per imaginary unit it contains) when ranging u
    print(f"      Sum of per-unit counts: {sum(counts.values())} = 7 * 3 = 21 (each Q counted 3 times)")
    print()

    print("=" * 90)
    print("  Verdict")
    print("=" * 90)
    print()
    print("  The count 3 = (number of quaternionic sub-algebras of O containing a")
    print("  fixed complex sub-algebra C) is a structural fact of O independent of")
    print("  which complex sub-algebra is fixed.  This is the candidate structural")
    print("  source of N_gen = 3 in PST, conditional on the foundational refinement:")
    print()
    print("    PROPOSED REFINEMENT: the modal threshold tau is Im(O)-valued (not")
    print("    just a real scalar).  Its directedness selects a preferred i_C in")
    print("    Im(O), breaking G_2 -> Stab_{i_C} = SU(3) x U(1).  The 3 quaternionic")
    print("    sub-algebras of O containing C carry the 3 generations of matter.")
    print()
    print("  Next step (Comp 58 candidate): verify that under this refinement, the")
    print("  3 quaternionic sub-algebras produce DISTINCT copies of the one-generation")
    print("  matter content (rather than 3 copies of the same content), so they are")
    print("  identified with 3 generations of fermions.")


if __name__ == "__main__":
    main()
