08 — Gröbner: general relations, completed and certified¶
The mathematics¶
A monomial ideal (Chapter 02) is easy because a basis of kQ/I is just the paths avoiding
the forbidden ones. A general admissible ideal I ⊆ kQ is generated by relations that are
linear combinations of parallel paths — a*b - c*d, not a single word — and now "avoid the
relations" is no longer a well-defined subword test. The classical fix is a noncommutative
Gröbner basis: fix an admissible order on paths, orient each relation into a rewrite rule
(leading word) → (smaller tail), and complete the rules (Buchberger–Mora, the
path-algebra form of Buchberger's algorithm) until the rewriting is confluent — every
element reduces to a unique normal form regardless of the order of rewrites. Bergman's
Diamond Lemma then says the words that no rule can touch (the irreducible words) are an
exact k-basis of kQ/I, and any product is computed by concatenating and rewriting to normal
form. Everything here is exact and characteristic-independent; the only inputs from the
field are its arithmetic operations.
How it is represented¶
Every object lives in quiverlab/groebner/. Paths compose left to right throughout
(Chapter 02): the word ("c", "d") is "first c, then d".
- An element of kQ is a dict (lookup table)
word -> coefficient, e.g.{("c", "d"): 1, ("a", "b"): -1}, carrying no zero coefficients; the zero element is the empty dict{}. The coefficient is an element of the exactDomain(Chapter 01), so the same code runs over QQ, CC, or GF(p).lc_add,lc_sub(reduction.py) do the arithmetic and drop any coefficient that cancels to zero. - The order is a
PathOrder(order.py): a length-then-lexicographic well-order whose arrow ranks are the insertion order ofquiver.arrows(the first arrow is smallest). Itskey(word)returns the sort key(length, ranks), andleading(comb)returns the largest word in an element — the one a rule will target.path_order(quiver)builds it. - A rule is a frozen (immutable)
ReductionRule(reduction.py) with four fields:lead(the leading word, a path tuple),tail(a tuple of(coeff, word)pairs, every word strictly smaller thanlead), andsource/target(the shared endpoints, so the rule is parallel). It means "rewrite any occurrence ofleadintotail".rule_from_combturns an element into a rule by dividing through by its leading coefficient. - An ambiguity is a frozen
Ambiguity(overlap.py): two leads that clash inside one word.kindis"overlap"(a nonemptybthat is a proper suffix of one lead and a proper prefix of the other — left-to-right, so suffix meets prefix) or"inclusion"(one lead a proper factor of the other);wordis the clashing word anda/cits prefix/suffix context. - The whole thing is a frozen
ReductionSystem(system.py):quiver,domain,order,rules(a confluent tuple),irreducibles(the certified basis words),degree_bound, andis_confluent. Its methodsreduce,normal_form,leading_words, andambiguitiesare the surface the structure-constant lowering (below) and Plan 04 (Chouhy–Solotar) consume.
How the computation runs¶
build_reduction_system(quiver, relations, field) (system.py) is the pipeline:
-
Parse and orient. Relation strings are parsed (Chapter 02); any relation with a path of length < 2 is refused loudly (
AdmissibilityError— an admissible ideal lives inside the square of the arrow ideal). The coefficients seen are collected into an exactDomain, and each relation becomes an initial rule viarule_from_comb: its leading word under the order becomeslead, everything else is moved to the other side astail. A relation whose coefficients all vanish in the chosen field raisesRelationError. -
Complete (
complete.py,complete). Repeatedly: form everyAmbiguityof the current rules withall_ambiguities; for each, build its S-polynomial — reduce the ambiguity word two ways (apply one rule at the front, the other in place) and subtract, so the leads cancel and only smaller words survive (s_polynomial); reduce that remainder to normal form with the current rules (reduce_comb). If it is nonzero, it is a genuinely new relation the rules could not see, so orient it into a rule and restart. When a full pass adds nothing, the system is confluent.reduce_combalways rewrites the largest reducible word first, using the leftmost matching lead (first_factor); because every rewrite replaces a word by strictly smaller ones in a well-order, reduction terminates. Only ambiguity words up todegree_boundare formed, so completion always halts; a runaway system (more thanmax_rules) stops with anAdmissibilityErrorrather than hanging. Finally_minimize_leadsdrops any rule whose lead contains another's as a factor, leaving the leads an antichain (this is why a completed system has only overlap ambiguities left, never inclusions). -
Certify (
certificate.py). Let L be the longest leading word. Every overlap ambiguity word has length ≤ 2L−1, so if2L-1 <= degree_boundthen every ambiguity was actually formed and reduced to zero — confluence is proved, not assumed. If2L-1exceeds the bound,check_degree_boundrefuses with anAdmissibilityErrortelling you the exact bound to raise to; it never certifies an unchecked system. Given confluence, the irreducible words are enumerated by the very same Plan-01 forbidden-word automaton as the monomial case (core.monomial.irreducible_paths, Chapter 02) with the leads as the forbidden words: finitely many ⇒ certified finite-dimensional; a cycle ⇒NotFiniteDimensionalErrornaming the offending arrow cycle. -
Lower to structure constants (
lower.py,groebner_algebra). The algebra basis is the vertex idempotents (inquiver.verticesorder) followed by the certified irreducible words sorted(length, word)— exactly the orderingbuild_monomial_algebrauses, so on a monomial input the Gröbner route reproduces the Plan-01Algebraelementwise. Each structure constantb_i · b_jis computed by concatenating the two words and reducing to normal form (rs.reduce); the resulting coefficient vector is one column of the multiplication tableT. The output is an ordinaryAlgebra(Chapter 03), so Hochschild cohomology flows through the existing bar path unchanged.
A worked micro-example — completing Fixture 3¶
Take the two-loop quiver Q with one vertex and loops x, y (so x has rank 0, y rank
1), and the ideal generated by {y*y, x*y, y*x - x*x}. Oriented under length-lex, the three
initial rules are yy → 0, xy → 0, and yx → xx (the tail xx is smaller than the lead
yx because x < y at the first letter). These rules are not yet confluent:
- The leads
yyandyxoverlap on the shared middle lettery:yy = (y)·(y)andyx = (y)·(x), so the ambiguity word isy·y·x = ("y","y","x")with prefix contexta = ("y",)and suffix contextc = ("x",). - Its S-polynomial reduces
yyxtwo ways: applyingyy → 0at the front gives0·x = 0; applyingyx → xxat the back givesy·xx = ("y","x","x"). The difference is0 - yxx = {("y","x","x"): -1}(verified by runnings_polynomial). - Reducing
yxxwith the current rules firesyx → xxat position 0, givingxx·x = xxx, which no rule touches. So the normal form is-xxx ≠ 0: a new relation. Oriented, it is the monomial rulexxx → 0(empty tail).
Completion adds exactly this rule; a second pass finds every remaining ambiguity now reduces
to zero. The completed leads are {xxx, xy, yx, yy} — the same result the completion test
asserts. The moral in one line: xxx was hidden in the ideal — the free-algebra identity
y·(yx−xx) − (yy)·x = −yxx puts an element of I in front of us, and rewriting yx → xx
turns it into −xxx, so xxx ∈ I — and completion is what makes this visible to the
rewriting system.
For the structure-constant payoff, take the commutative square Q with arrows
a:1→2, b:2→4, c:1→3, d:3→4 and the single non-monomial relation a*b - c*d. Here the one
rule is cd → ab (ab < cd because a < c), with source 1, target 4; the longest lead
has length L = 2, so 2L−1 = 3 ≤ the default bound 8 and there are no ambiguities at all.
The certified irreducibles are a, b, c, d, ab, giving the basis
[e_1, e_2, e_3, e_4, a, b, c, d, a*b] — dimension 9. When the table is built, the product
c·d concatenates to ("c","d") and reduces to {("a","b"): 1}, so in the algebra
c*d = a*b: the commutativity of the square is now a literal structure constant. (Every dim,
lead, tail, and normal form in this section was produced by running the code.)
Where to look in the code¶
| concept | file | function / class |
|---|---|---|
| element arithmetic, rules, normal form | groebner/reduction.py |
lc_add, lc_sub, ReductionRule, rule_from_comb, first_factor, reduce_comb |
| admissible length-lex order | groebner/order.py |
PathOrder, path_order |
| overlap / inclusion ambiguities | groebner/overlap.py |
Ambiguity, overlaps, inclusions, all_ambiguities |
| S-polynomials, Buchberger–Mora completion | groebner/complete.py |
s_polynomial, complete, _minimize_leads |
| finiteness certificate (2L−1 ≤ D, automaton) | groebner/certificate.py |
default_degree_bound, check_degree_bound, certified_irreducibles |
| the frozen reduction system (Plan 04 surface) | groebner/system.py |
ReductionSystem, build_reduction_system |
| general kQ/I → structure-constant Algebra | groebner/lower.py |
groebner_algebra |
| monomial-vs-Gröbner dispatch | combinat/quiver.py |
Quiver.algebra |
| loud refusals | errors.py |
AdmissibilityError, NotFiniteDimensionalError, RelationError |