Skip to content

products

quiverlab.hochschild.products

Plan 35 -- the HH product surface: structure-constant tables for the cup product, the cap module action, the Gerstenhaber bracket, and the induced Connes differential, as frozen result objects with one canonical block serialization (consumed identically by hpc/spec.py and docs/gui/runner.py).

Constants are ALWAYS exact strings at the boundary (str(entry)): ints mod p on the GF(p) routes, Domain reprs on the CS route. No floats can appear (the AST gate scans this file).

BVOperator

BVOperator(top, hh_dims, matrices, ranks, hypothesis, nakayama, basis, window, references, bracket_check=None, derived_bracket=None, basis_classes=None, chain_basis=None, differentials=None)

The Batalin-Vilkovisky operator Delta: HH^n -> HH^{n-1} (Plan 54).

Delta lowers cohomological degree by 1 and is the adjoint of the (twisted) Connes B under the Frobenius perfect pairing. matrices[n] is Delta_n, a dim HH^{n-1} x dim HH^n matrix of exact strings (rows indexed by the OUTPUT degree HH^{n-1}, mirroring ConnesB); the family starts at n = 1 (Delta_0 = 0 by degree: there is no HH^{-1}). Constants live in the recorded basis (Plan 35 basis-dependence doctrine).

Source code in src/quiverlab/hochschild/products.py
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
def __init__(self, top, hh_dims, matrices, ranks, hypothesis, nakayama,
             basis, window, references, bracket_check=None,
             derived_bracket=None, basis_classes=None, chain_basis=None,
             differentials=None):
    self.top = top
    self.hh_dims = list(hh_dims)      # dim HH^0 .. dim HH^top (cohomology)
    self.matrices = dict(matrices)    # {n: rows-of-str}, Delta_n hh^{n-1} x hh^n
    self.ranks = dict(ranks)          # {n: int}
    self.hypothesis = hypothesis      # provenance: WHICH hypothesis certified it
    self.nakayama = dict(nakayama)    # {matrix, semisimple, order, inner}
    self.basis = basis                # WHICH basis the constants live in
    self.window = window              # certified degree window served
    self.references = list(references)
    self.bracket_check = dict(bracket_check) if bracket_check else None
    self.derived_bracket = derived_bracket    # an HHProducts(kind="bracket")
    self.basis_classes = dict(basis_classes) if basis_classes else None
    self.chain_basis = dict(chain_basis) if chain_basis else None
    self.differentials = dict(differentials) if differentials else None

ConnesB

ConnesB(top, hh_dims, matrices, ranks, engine, references, basis_classes=None, chain_basis=None, differentials=None)

Induced Connes differentials B: HH_n -> HH_{n+1} for 0 <= n < top.

Source code in src/quiverlab/hochschild/products.py
80
81
82
83
84
85
86
87
88
89
90
91
92
def __init__(self, top, hh_dims, matrices, ranks, engine, references,
             basis_classes=None, chain_basis=None, differentials=None):
    self.top = top
    self.hh_dims = list(hh_dims)   # dim HH_0..HH_top
    self.matrices = dict(matrices) # {n: rows of str, shape hh_dims[n+1] x hh_dims[n]}
    self.ranks = dict(ranks)       # {n: int}
    self.engine = engine
    self.references = list(references)
    # Plan 35 explicit representatives: the homology cycle bases z^n_j (0..top),
    # their ordered chain enumeration, and the boundary b_n that annihilates them.
    self.basis_classes = dict(basis_classes) if basis_classes else None
    self.chain_basis = dict(chain_basis) if chain_basis else None
    self.differentials = dict(differentials) if differentials else None

HHProducts

HHProducts(kind, top, tables, engine, basis, window, references, basis_classes=None, chain_basis=None, differentials=None)

A family of product tables up to top. kind in {"cup","cap","bracket"}.

Source code in src/quiverlab/hochschild/products.py
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
def __init__(self, kind, top, tables, engine, basis, window, references,
             basis_classes=None, chain_basis=None, differentials=None):
    self.kind = kind
    self.top = top
    self.tables = dict(tables)     # {(p, q): ProductTable}
    self.engine = engine
    self.basis = basis
    self.window = window           # int for bracket (served window), else None
    self.references = list(references)
    # Plan 35 explicit representatives: {(side, n): [class dict, ...]} the ACTUAL
    # (co)cycles that produced the constants; the ordered enumeration they index
    # into; and the annihilating differential (self-certification). None when a
    # legacy caller omits them (blocks() then omits the fields; renderers fall back).
    self.basis_classes = dict(basis_classes) if basis_classes else None
    self.chain_basis = dict(chain_basis) if chain_basis else None
    self.differentials = dict(differentials) if differentials else None

connes_b_tables

connes_b_tables(A, top, max_cells=4000000)

Induced Connes differentials B: HH_n -> HH_{n+1}, 0 <= n < top.

Returns a ConnesB whose matrices[n] is the hh_{n+1} x hh_n matrix of the induced B in the class bases (rows indexed by HH_{n+1}); B^2 = 0 holds at the induced level because bB + Bb = 0 makes B descend to homology and B^2 vanishes on chains. GF(p): the fast (b,B) engine; any other exact Domain: the generic bar (b,B) mixed complex (max_cells guards the blow-up).

Source code in src/quiverlab/hochschild/products.py
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
def connes_b_tables(A, top, max_cells=4_000_000):
    """Induced Connes differentials B: HH_n -> HH_{n+1}, 0 <= n < top.

    Returns a ConnesB whose matrices[n] is the hh_{n+1} x hh_n matrix of the
    induced B in the class bases (rows indexed by HH_{n+1}); B^2 = 0 holds at
    the induced level because bB + Bb = 0 makes B descend to homology and B^2
    vanishes on chains. GF(p): the fast (b,B) engine; any other exact Domain:
    the generic bar (b,B) mixed complex (max_cells guards the blow-up)."""
    from quiverlab.fields.primefield import PrimeField
    from quiverlab.hochschild import basis_reps as BR
    dom = A.domain
    AU = A.unit_adapted()
    labels = BR.labels_of(AU)
    if isinstance(dom, PrimeField):
        import numpy as np
        from quiverlab.errors import DepthLimitError
        from quiverlab.engine.adapter import to_engine
        from quiverlab.engine.cyclic import connes_B_matrix
        from quiverlab.engine.hh_engine import cn_basis
        from quiverlab.engine.tt_calculus import homology_classes
        p = dom.p
        E = to_engine(AU)
        # Guard the bar (b,B) blow-up BEFORE building any matrix. homology_classes(n)
        # materializes the DENSE boundary matrices b_n (cn[n-1] x cn[n]) and b_{n+1}
        # (cn[n] x cn[n+1]); the bar chain basis grows exponentially with degree, so at
        # high top these are gigabytes (e.g. QuantumCI connes_b:0..7 needs b_8, an
        # 8748 x 26244 int64 matrix ~= 1.8 GB, whose rref/nullspace copies peaked ~6 GB
        # and SIGKILLed the memory-capped worker). This mirrors the cup/cap/bracket
        # cochain-pair guard: over GF(p) connes has NO Chouhy-Solotar route, so -- like
        # an explicit bar engine -- it refuses LOUDLY rather than silently OOMing. The
        # max_cells parameter was already honoured on the generic-Domain branch below;
        # the GF(p) branch simply dropped it (the bug). Dims/other invariants stand.
        cdims = [len(cn_basis(E, n)) for n in range(top + 2)]
        for n in range(top + 1):
            cells = max(cdims[n] * cdims[n + 1],
                        cdims[n - 1] * cdims[n] if n else 0)
            if cells > max_cells:
                raise DepthLimitError(
                    f"connes_b: the bar (b,B) boundary at degree {n} pairs {cells} "
                    f"cells (> max_cells = {max_cells})",
                    hint="raise max_cells or lower top")
        H = {n: homology_classes(E, n, p) for n in range(top + 1)}
        matrices, ranks = {}, {}
        for n in range(top):
            idx = {g: i for i, g in enumerate(cn_basis(E, n + 1))}
            B = connes_B_matrix(E, n, cn_basis(E, n), idx)
            rows = []
            for i in range(H[n].dim):
                img = (B @ H[n].reps[:, i]) % p
                rows.append([int(x) for x in H[n + 1].coords(img)])
            # rows[i] = coords of B(e_i); store as matrix hh_{n+1} x hh_n
            matrices[n] = [[str(rows[i][k]) for i in range(H[n].dim)]
                           for k in range(H[n + 1].dim)]
            ranks[n] = _int_rank_mod_p(rows, H[n + 1].dim, p)
        hh = [H[n].dim for n in range(top + 1)]
        engine = f"engine (b,B) GF({p})"
        bc, cb, diffs = {}, {}, {}
        for n in range(top + 1):
            elems = BR.engine_hom_elements(E, n, labels)
            cols = [H[n].reps[:, i] for i in range(H[n].reps.shape[1])]
            bc[("hom", n)] = BR.classes_from_columns(cols, elems, n, "chain", None)
            cb[("hom", n)] = BR.enumeration_labels(elems, "chain")
            shape, build, note = _gfp_hom_diff(E, n)
            diffs[("hom", n)] = BR.serialize_differential(shape, build, note, None)
    else:
        from quiverlab.fields.linalg import rank as _rank
        from quiverlab.hochschild.cyclic import connes_B_matrix
        quots = {n: _generic_homology_quotient(AU, n, max_cells)
                 for n in range(top + 1)}
        matrices, ranks = {}, {}
        for n in range(top):
            M, ncols, nrows = connes_B_matrix(AU, n, max_cells)
            reps_n, _ = quots[n]
            reps_n1, img_n1 = quots[n + 1]
            cols = []
            for v in reps_n:
                w = [dom.zero()] * nrows
                for r in range(nrows):
                    acc = dom.zero()
                    for c in range(ncols):
                        acc = dom.add(acc, dom.mul(M[r][c], dom.coerce(v[c])))
                    w[r] = acc
                cols.append(_class_coords(w, reps_n1, img_n1, dom, stringify=False))
            matrices[n] = [[str(cols[i][k]) for i in range(len(reps_n))]
                           for k in range(len(reps_n1))]
            ranks[n] = _rank([[dom.coerce(cols[i][k]) for i in range(len(reps_n))]
                              for k in range(len(reps_n1))], dom) if reps_n else 0
        hh = [len(quots[n][0]) for n in range(top + 1)]
        engine = f"generic (b,B) mixed complex / {dom.name}"
        bc, cb, diffs = {}, {}, {}
        m = AU.dim
        for n in range(top + 1):
            elems = BR.bar_chain_elements(m, n, labels)
            bc[("hom", n)] = BR.classes_from_columns(quots[n][0], elems, n, "chain", dom)
            cb[("hom", n)] = BR.enumeration_labels(elems, "chain")
            shape = ((m * (m - 1) ** (n - 1)) if n else 0, m * (m - 1) ** n)
            note = ("quiverlab.hochschild.bar.boundary_matrix(A.unit_adapted(), %d, "
                    "max_cells)[0]" % n)
            build = (lambda nn=n: _generic_boundary_rows(AU, nn, max_cells))
            diffs[("hom", n)] = BR.serialize_differential(shape, build, note, dom)
    return ConnesB(top=top, hh_dims=hh, matrices=matrices, ranks=ranks,
                   engine=engine, references=_REFERENCES["connes_b"],
                   basis_classes=bc, chain_basis=cb, differentials=diffs)

gfp_product_tables

gfp_product_tables(A, kind, top, max_cells)

The GF(p) bar-route table family: tt_calculus structure constants on the bar HH basis. A must be over a prime field (the caller routes).

Source code in src/quiverlab/hochschild/products.py
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
def gfp_product_tables(A, kind, top, max_cells):
    """The GF(p) bar-route table family: tt_calculus structure constants on the
    bar HH basis. A must be over a prime field (the caller routes)."""
    from quiverlab.engine.adapter import to_engine
    from quiverlab.engine import tt_calculus as TT
    from quiverlab.engine.scan3 import cochain_basis
    from quiverlab.errors import DepthLimitError
    from quiverlab.hochschild import basis_reps as BR
    prime = A.domain.p
    AU = A.unit_adapted()
    E = to_engine(AU)
    labels = BR.labels_of(AU)
    out_deg = {"cup": lambda p, q: p + q, "cap": lambda p, n: n - p,
               "bracket": lambda p, q: p + q - 1}[kind]

    # Class caches: cohomology/homology reps computed ONCE and shared -- the SAME
    # objects both produce the constants (passed into the tt matrix builders) and
    # are captured as the explicit representatives (Plan 35).
    _coh, _hom = {}, {}

    def coh(n):
        if n not in _coh:
            _coh[n] = TT.cohomology_classes(E, n, prime)
        return _coh[n]

    def hom(n):
        if n not in _hom:
            _hom[n] = TT.homology_classes(E, n, prime)
        return _hom[n]

    tables = {}
    for (p, q) in _pairs(kind, top):
        cells = len(cochain_basis(E, p)) * len(cochain_basis(E, q))
        if cells > max_cells:
            raise DepthLimitError(
                f"{kind} product table ({p}, {q}): the two cochain bases pair "
                f"{cells} cells (> max_cells = {max_cells})",
                hint="raise max_cells or lower top")
        if kind == "cup":
            C, dl, dr, dout = TT.cup_product_matrix(E, p, q, prime,
                                                    coh(p), coh(q), coh(p + q))
        elif kind == "bracket":
            C, dl, dr, dout = TT.gerstenhaber_bracket_matrix(
                E, p, q, prime, coh(p), coh(q), coh(p + q - 1))
        else:  # cap: (p, n) -> HH^p (x) HH_n -> HH_{n-p}
            C, dl, dr, dout = TT.cap_product_matrix(E, p, q, prime,
                                                    coh(p), hom(q), hom(q - p))
        tables[(p, q)] = ProductTable(
            kind=kind, degrees=(p, q), out_degree=out_deg(p, q),
            dims=(dl, dr, dout),
            constants=tuple(tuple(tuple(str(int(C[k, i, j])) for j in range(dr))
                                  for i in range(dl)) for k in range(dout)))

    bc, cb, diffs = _capture_gfp(E, labels, kind, top, coh, hom)
    window = top if kind == "bracket" else None
    return HHProducts(kind=kind, top=top, tables=tables,
                      engine="hanlab engine (F_p fast rank)",
                      basis=f"bar/GF({prime})", window=window,
                      references=_REFERENCES[kind],
                      basis_classes=bc, chain_basis=cb, differentials=diffs)