From 46836b9ec283030ac4c7efc3f4cd223adf3ce7b8 Mon Sep 17 00:00:00 2001 From: Andromeda Date: Fri, 20 Mar 2026 00:49:23 -0400 Subject: [PATCH 1/8] Naive implementation of IsJoinIrreducible and IsMeetIrreducible --- joinmeetirreducible.g | 44 +++++++++++++++++++++++++++++++++++++++++ joinmeetirreducible.tst | 38 +++++++++++++++++++++++++++++++++++ 2 files changed, 82 insertions(+) create mode 100644 joinmeetirreducible.g create mode 100644 joinmeetirreducible.tst diff --git a/joinmeetirreducible.g b/joinmeetirreducible.g new file mode 100644 index 000000000..d887f34fd --- /dev/null +++ b/joinmeetirreducible.g @@ -0,0 +1,44 @@ +IsJoinIrreducible := function(G, v) + local joinTable, row, x, y; + joinTable := DigraphJoinTable(G); + + for y in [1..Length(joinTable)] do + if y = v then + continue; + fi; + row := joinTable[y]; + for x in [1..Length(row)] do + if x = v then + continue; + fi; + if row[x] = v then + return false; + fi; + od; + od; + + return true; +end; + + +IsMeetIrreducible := function(G, v) + local meetTable, row, x, y; + meetTable := DigraphMeetTable(G); + + for y in [1..Length(meetTable)] do + if y = v then + continue; + fi; + row := meetTable[y]; + for x in [1..Length(row)] do + if x = v then + continue; + fi; + if row[x] = v then + return false; + fi; + od; + od; + + return true; +end; diff --git a/joinmeetirreducible.tst b/joinmeetirreducible.tst new file mode 100644 index 000000000..049ea560b --- /dev/null +++ b/joinmeetirreducible.tst @@ -0,0 +1,38 @@ +# Setup test environment +gap> START_TEST("Digraphs package: joinmeetirreducible.tst"); +gap> LoadPackage("digraphs", false);; +gap> DIGRAPHS_StartTest(); + +# Define a lattice +gap> graph := Digraph([[2, 3], [5], [4], [5], []]); + +gap> lattice := DigraphReflexiveTransitiveClosure(graph); + + +# Test IsJoinIrreducible +gap> IsJoinIrreducible(lattice, 1); +true +gap> IsJoinIrreducible(lattice, 2); +true +gap> IsJoinIrreducible(lattice, 3); +true +gap> IsJoinIrreducible(lattice, 4); +true +gap> IsJoinIrreducible(lattice, 5); +false + +# Test IsMeetIrreducible +gap> IsMeetIrreducible(lattice, 1); +false +gap> IsMeetIrreducible(lattice, 2); +true +gap> IsMeetIrreducible(lattice, 3); +true +gap> IsMeetIrreducible(lattice, 4); +true +gap> IsMeetIrreducible(lattice, 5); +true + +# Teardown test environment +gap> DIGRAPHS_StopTest(); +gap> STOP_TEST("Digraphs package: joinmeetirreducible.tst", 0); From 3bb2bb871e5d3bc5502d783378f8b50b6867bf27 Mon Sep 17 00:00:00 2001 From: Andromeda Date: Fri, 20 Mar 2026 01:43:55 -0400 Subject: [PATCH 2/8] Optimise join/meet irreducible functions --- joinmeetirreducible.g | 49 +++++++++---------------------------------- 1 file changed, 10 insertions(+), 39 deletions(-) diff --git a/joinmeetirreducible.g b/joinmeetirreducible.g index d887f34fd..321f331ad 100644 --- a/joinmeetirreducible.g +++ b/joinmeetirreducible.g @@ -1,44 +1,15 @@ -IsJoinIrreducible := function(G, v) - local joinTable, row, x, y; - joinTable := DigraphJoinTable(G); - - for y in [1..Length(joinTable)] do - if y = v then - continue; - fi; - row := joinTable[y]; - for x in [1..Length(row)] do - if x = v then - continue; - fi; - if row[x] = v then - return false; - fi; - od; - od; +# https://doc.sagemath.org/html/en/reference/combinat/sage/combinat/posets/hasse_diagram.html#sage.combinat.posets.hasse_diagram.HasseDiagram.find_nontrivial_congruence - return true; +IsJoinIrreducible := function(G, v) + local hasse; + hasse := DigraphReflexiveTransitiveReduction(G); + # join-irreducible iff at most one lower cover + return InDegreeOfVertex(hasse, v) <= 1; end; - IsMeetIrreducible := function(G, v) - local meetTable, row, x, y; - meetTable := DigraphMeetTable(G); - - for y in [1..Length(meetTable)] do - if y = v then - continue; - fi; - row := meetTable[y]; - for x in [1..Length(row)] do - if x = v then - continue; - fi; - if row[x] = v then - return false; - fi; - od; - od; - - return true; + local hasse; + # meet-irreducible iff at most one upper cover + hasse := DigraphReflexiveTransitiveReduction(G); + return OutDegreeOfVertex(hasse, v) <= 1; end; From 7b7d883cdd3d53de4de7173ba2639dcb76dc3e7a Mon Sep 17 00:00:00 2001 From: Andromeda Date: Fri, 20 Mar 2026 01:46:56 -0400 Subject: [PATCH 3/8] Add error handling inspired by existing .gi files --- joinmeetirreducible.g | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/joinmeetirreducible.g b/joinmeetirreducible.g index 321f331ad..dd3051b17 100644 --- a/joinmeetirreducible.g +++ b/joinmeetirreducible.g @@ -2,6 +2,9 @@ IsJoinIrreducible := function(G, v) local hasse; + if not IsPartialOrderDigraph(G) then + ErrorNoReturn("the 1st argument must be a partial order digraph,"); + fi; hasse := DigraphReflexiveTransitiveReduction(G); # join-irreducible iff at most one lower cover return InDegreeOfVertex(hasse, v) <= 1; @@ -9,6 +12,9 @@ end; IsMeetIrreducible := function(G, v) local hasse; + if not IsPartialOrderDigraph(G) then + ErrorNoReturn("the 1st argument must be a partial order digraph,"); + fi; # meet-irreducible iff at most one upper cover hasse := DigraphReflexiveTransitiveReduction(G); return OutDegreeOfVertex(hasse, v) <= 1; From 6c07453cb4f3ca19f80456fb773498e1a1d0e62d Mon Sep 17 00:00:00 2001 From: Andromeda Date: Fri, 20 Mar 2026 02:21:47 -0400 Subject: [PATCH 4/8] Expand tests with LLM assistance --- joinmeetirreducible.tst | 84 +++++++++++++++++++++++++++++++++++++++-- 1 file changed, 81 insertions(+), 3 deletions(-) diff --git a/joinmeetirreducible.tst b/joinmeetirreducible.tst index 049ea560b..56e71c993 100644 --- a/joinmeetirreducible.tst +++ b/joinmeetirreducible.tst @@ -1,15 +1,17 @@ +#@local b2, chain, graph, lattice, m3 + # Setup test environment gap> START_TEST("Digraphs package: joinmeetirreducible.tst"); gap> LoadPackage("digraphs", false);; gap> DIGRAPHS_StartTest(); -# Define a lattice +# The pentagon lattice N5: 1 < {2, 3}, 3 < 4, {2, 4} < 5 gap> graph := Digraph([[2, 3], [5], [4], [5], []]); gap> lattice := DigraphReflexiveTransitiveClosure(graph); -# Test IsJoinIrreducible +# Test IsJoinIrreducible on N5 gap> IsJoinIrreducible(lattice, 1); true gap> IsJoinIrreducible(lattice, 2); @@ -21,7 +23,7 @@ true gap> IsJoinIrreducible(lattice, 5); false -# Test IsMeetIrreducible +# Test IsMeetIrreducible on N5 gap> IsMeetIrreducible(lattice, 1); false gap> IsMeetIrreducible(lattice, 2); @@ -33,6 +35,82 @@ true gap> IsMeetIrreducible(lattice, 5); true +# A 4-element chain: every element is doubly irreducible +gap> chain := DigraphReflexiveTransitiveClosure(ChainDigraph(4)); + + +# Test IsJoinIrreducible on a chain +gap> IsJoinIrreducible(chain, 1); +true +gap> IsJoinIrreducible(chain, 2); +true +gap> IsJoinIrreducible(chain, 3); +true +gap> IsJoinIrreducible(chain, 4); +true + +# Test IsMeetIrreducible on a chain +gap> IsMeetIrreducible(chain, 1); +true +gap> IsMeetIrreducible(chain, 2); +true +gap> IsMeetIrreducible(chain, 3); +true +gap> IsMeetIrreducible(chain, 4); +true + +# The Boolean lattice B2: 1 < {2, 3} < 4 +gap> b2 := DigraphReflexiveTransitiveClosure(Digraph([[2, 3], [4], [4], []])); + + +# Test IsJoinIrreducible on B2 +gap> IsJoinIrreducible(b2, 1); +true +gap> IsJoinIrreducible(b2, 2); +true +gap> IsJoinIrreducible(b2, 3); +true +gap> IsJoinIrreducible(b2, 4); +false + +# Test IsMeetIrreducible on B2 +gap> IsMeetIrreducible(b2, 1); +false +gap> IsMeetIrreducible(b2, 2); +true +gap> IsMeetIrreducible(b2, 3); +true +gap> IsMeetIrreducible(b2, 4); +true + +# The M3 lattice: 1 < {2, 3, 4} < 5 +gap> m3 := DigraphReflexiveTransitiveClosure(Digraph([[2, 3, 4], [5], [5], [5], []])); + + +# Test IsJoinIrreducible on M3 +gap> IsJoinIrreducible(m3, 1); +true +gap> IsJoinIrreducible(m3, 2); +true +gap> IsJoinIrreducible(m3, 3); +true +gap> IsJoinIrreducible(m3, 4); +true +gap> IsJoinIrreducible(m3, 5); +false + +# Test IsMeetIrreducible on M3 +gap> IsMeetIrreducible(m3, 1); +false +gap> IsMeetIrreducible(m3, 2); +true +gap> IsMeetIrreducible(m3, 3); +true +gap> IsMeetIrreducible(m3, 4); +true +gap> IsMeetIrreducible(m3, 5); +true + # Teardown test environment gap> DIGRAPHS_StopTest(); gap> STOP_TEST("Digraphs package: joinmeetirreducible.tst", 0); From 8cf99cab690f6dc90d0e5e520d515ef93eda19ff Mon Sep 17 00:00:00 2001 From: Andromeda Date: Fri, 20 Mar 2026 02:58:05 -0400 Subject: [PATCH 5/8] Integrate joinmeetirreducible into oper.gi/oper.gd --- gap/oper.gd | 3 +++ gap/oper.gi | 32 ++++++++++++++++++++++++++++++++ joinmeetirreducible.g | 21 --------------------- tst/standard/oper.tst | 6 +++--- 4 files changed, 38 insertions(+), 24 deletions(-) delete mode 100644 joinmeetirreducible.g diff --git a/gap/oper.gd b/gap/oper.gd index f6a37e0f8..08dbf19f5 100644 --- a/gap/oper.gd +++ b/gap/oper.gd @@ -161,3 +161,6 @@ DeclareOperation("PartialOrderDigraphJoinOfVertices", [IsDigraph, IsPosInt, IsPosInt]); DeclareOperation("PartialOrderDigraphMeetOfVertices", [IsDigraph, IsPosInt, IsPosInt]); + +DeclareOperation("IsJoinIrreducible", [IsDigraph, IsPosInt]); +DeclareOperation("IsMeetIrreducible", [IsDigraph, IsPosInt]); diff --git a/gap/oper.gi b/gap/oper.gi index 3876db50e..c652d8c91 100644 --- a/gap/oper.gi +++ b/gap/oper.gi @@ -2720,6 +2720,38 @@ function(D, i, j) return fail; end); +InstallMethod(IsJoinIrreducible, +"for a digraph and a positive integer", +[IsDigraph, IsPosInt], +function(D, v) + local hasse; + if not IsPartialOrderDigraph(D) then + ErrorNoReturn("the 1st argument must satisfy IsPartialOrderDigraph,"); + elif not v in DigraphVertices(D) then + ErrorNoReturn("the 2nd argument must be a vertex of the ", + "1st argument ,"); + fi; + hasse := DigraphReflexiveTransitiveReduction(DigraphMutableCopyIfMutable(D)); + # join-irreducible iff at most one lower cover in the Hasse diagram + return InDegreeOfVertexNC(hasse, v) <= 1; +end); + +InstallMethod(IsMeetIrreducible, +"for a digraph and a positive integer", +[IsDigraph, IsPosInt], +function(D, v) + local hasse; + if not IsPartialOrderDigraph(D) then + ErrorNoReturn("the 1st argument must satisfy IsPartialOrderDigraph,"); + elif not v in DigraphVertices(D) then + ErrorNoReturn("the 2nd argument must be a vertex of the ", + "1st argument ,"); + fi; + hasse := DigraphReflexiveTransitiveReduction(DigraphMutableCopyIfMutable(D)); + # meet-irreducible iff at most one upper cover in the Hasse diagram + return OutDegreeOfVertexNC(hasse, v) <= 1; +end); + InstallMethod(DigraphKings, "for a digraph and a positive integer", [IsDigraph, IsPosInt], function(D, n) diff --git a/joinmeetirreducible.g b/joinmeetirreducible.g deleted file mode 100644 index dd3051b17..000000000 --- a/joinmeetirreducible.g +++ /dev/null @@ -1,21 +0,0 @@ -# https://doc.sagemath.org/html/en/reference/combinat/sage/combinat/posets/hasse_diagram.html#sage.combinat.posets.hasse_diagram.HasseDiagram.find_nontrivial_congruence - -IsJoinIrreducible := function(G, v) - local hasse; - if not IsPartialOrderDigraph(G) then - ErrorNoReturn("the 1st argument must be a partial order digraph,"); - fi; - hasse := DigraphReflexiveTransitiveReduction(G); - # join-irreducible iff at most one lower cover - return InDegreeOfVertex(hasse, v) <= 1; -end; - -IsMeetIrreducible := function(G, v) - local hasse; - if not IsPartialOrderDigraph(G) then - ErrorNoReturn("the 1st argument must be a partial order digraph,"); - fi; - # meet-irreducible iff at most one upper cover - hasse := DigraphReflexiveTransitiveReduction(G); - return OutDegreeOfVertex(hasse, v) <= 1; -end; diff --git a/tst/standard/oper.tst b/tst/standard/oper.tst index 1c813fe21..b6500fbf3 100644 --- a/tst/standard/oper.tst +++ b/tst/standard/oper.tst @@ -1514,18 +1514,18 @@ gap> gr := ChainDigraph(5); gap> DigraphRandomWalk(gr, 2, 100); [ [ 2, 3, 4, 5 ], [ 1, 1, 1 ] ] -gap> DigraphRandomWalk(gr, 2, 2); +gap> DigraphRandomWalk(gr, 2, 2); [ [ 2, 3, 4 ], [ 1, 1 ] ] gap> DigraphRandomWalk(gr, 5, 100); [ [ 5 ], [ ] ] gap> gr := CompleteBipartiteDigraph(10, 8);; -gap> DigraphRandomWalk(gr, 3, 0); +gap> DigraphRandomWalk(gr, 3, 0); [ [ 3 ], [ ] ] gap> DigraphRandomWalk(gr, 19, 5); Error, the 2nd argument must be a vertex of the 1st argument , gap> DigraphRandomWalk(gr, 123, 5); Error, the 2nd argument must be a vertex of the 1st argument , -gap> DigraphRandomWalk(gr, 3, -1); +gap> DigraphRandomWalk(gr, 3, -1); Error, the 3rd argument must be a non-negative int, # DigraphLayers From 2c37a4b94b9b1c2a0e44b2cfa9723b27ac281ea6 Mon Sep 17 00:00:00 2001 From: Andromeda Date: Fri, 20 Mar 2026 02:58:38 -0400 Subject: [PATCH 6/8] Remove dirty whitespace from tst/standard/oper.tst --- tst/standard/oper.tst | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/tst/standard/oper.tst b/tst/standard/oper.tst index b6500fbf3..3f7e5a231 100644 --- a/tst/standard/oper.tst +++ b/tst/standard/oper.tst @@ -2460,9 +2460,9 @@ gap> ConormalProduct(CycleDigraph(2), CycleDigraph(8)); #HomomorphicProduct gap> D := Digraph([[2, 3], [1, 3, 3], [1, 2, 2]]); -gap> HomomorphicProduct(D, D); +gap> HomomorphicProduct(D, D); Error, the 1st argument (a digraph) must not satisfy IsMultiDigraph -gap> DigraphSymmetricClosure(CycleDigraph(6)); +gap> DigraphSymmetricClosure(CycleDigraph(6)); gap> HomomorphicProduct(PetersenGraph(), last); @@ -2525,7 +2525,7 @@ gap> StrongProduct(NullDigraph(0), CompleteDigraph(3)); gap> D1 := Digraph([[2], [1, 3, 4], [2, 5], [2, 5], [3, 4]]); -gap> D2 := Digraph([[2], [1, 3, 4], [2], [2]]); +gap> D2 := Digraph([[2], [1, 3, 4], [2], [2]]); gap> LexicographicProduct(D1, D2); @@ -2545,7 +2545,7 @@ gap> OutNeighbours(last); [ 9, 10, 11, 12, 13, 14, 15, 16, 17, 19, 20 ], [ 9, 10, 11, 12, 13, 14, 15, 16, 18 ], [ 9, 10, 11, 12, 13, 14, 15, 16, 18 ] ] -gap> LexicographicProduct(ChainDigraph(3), CycleDigraph(7)); +gap> LexicographicProduct(ChainDigraph(3), CycleDigraph(7)); # SwapDigraphs @@ -3032,7 +3032,7 @@ Error, expected an edge between the 2nd and 3rd arguments (vertices) 1 and # DigraphContractEdge: Edge is a looped edge (u = v) gap> D := DigraphByEdges([[1, 1], [2, 1], [1, 2]]);; -gap> DigraphVertexLabels(D);; +gap> DigraphVertexLabels(D);; gap> C := DigraphContractEdge(D, 1, 1); Error, The 2nd argument must not be equal to the 3rd argument gap> DigraphHasLoops(D); @@ -3196,7 +3196,7 @@ Error, expected an edge between the 2nd and 3rd arguments (vertices) 1 and # DigraphContractEdge: Edge is a looped edge (u = v) (mutable) gap> D := DigraphByEdges(IsMutableDigraph, [[1, 1], [2, 1], [1, 2]]);; -gap> DigraphVertexLabels(D);; +gap> DigraphVertexLabels(D);; gap> DigraphContractEdge(D, 1, 1); Error, The 2nd argument must not be equal to the 3rd argument gap> DigraphHasLoops(D); From 8ae6cba4a441f512fe1cc661bb753d6b1ad43384 Mon Sep 17 00:00:00 2001 From: Andromeda Date: Fri, 20 Mar 2026 02:58:53 -0400 Subject: [PATCH 7/8] Add joinmeetirreducible tests to tst/standard/oper.tst --- joinmeetirreducible.tst | 116 ---------------------------------------- tst/standard/oper.tst | 103 +++++++++++++++++++++++++++++++++++ 2 files changed, 103 insertions(+), 116 deletions(-) delete mode 100644 joinmeetirreducible.tst diff --git a/joinmeetirreducible.tst b/joinmeetirreducible.tst deleted file mode 100644 index 56e71c993..000000000 --- a/joinmeetirreducible.tst +++ /dev/null @@ -1,116 +0,0 @@ -#@local b2, chain, graph, lattice, m3 - -# Setup test environment -gap> START_TEST("Digraphs package: joinmeetirreducible.tst"); -gap> LoadPackage("digraphs", false);; -gap> DIGRAPHS_StartTest(); - -# The pentagon lattice N5: 1 < {2, 3}, 3 < 4, {2, 4} < 5 -gap> graph := Digraph([[2, 3], [5], [4], [5], []]); - -gap> lattice := DigraphReflexiveTransitiveClosure(graph); - - -# Test IsJoinIrreducible on N5 -gap> IsJoinIrreducible(lattice, 1); -true -gap> IsJoinIrreducible(lattice, 2); -true -gap> IsJoinIrreducible(lattice, 3); -true -gap> IsJoinIrreducible(lattice, 4); -true -gap> IsJoinIrreducible(lattice, 5); -false - -# Test IsMeetIrreducible on N5 -gap> IsMeetIrreducible(lattice, 1); -false -gap> IsMeetIrreducible(lattice, 2); -true -gap> IsMeetIrreducible(lattice, 3); -true -gap> IsMeetIrreducible(lattice, 4); -true -gap> IsMeetIrreducible(lattice, 5); -true - -# A 4-element chain: every element is doubly irreducible -gap> chain := DigraphReflexiveTransitiveClosure(ChainDigraph(4)); - - -# Test IsJoinIrreducible on a chain -gap> IsJoinIrreducible(chain, 1); -true -gap> IsJoinIrreducible(chain, 2); -true -gap> IsJoinIrreducible(chain, 3); -true -gap> IsJoinIrreducible(chain, 4); -true - -# Test IsMeetIrreducible on a chain -gap> IsMeetIrreducible(chain, 1); -true -gap> IsMeetIrreducible(chain, 2); -true -gap> IsMeetIrreducible(chain, 3); -true -gap> IsMeetIrreducible(chain, 4); -true - -# The Boolean lattice B2: 1 < {2, 3} < 4 -gap> b2 := DigraphReflexiveTransitiveClosure(Digraph([[2, 3], [4], [4], []])); - - -# Test IsJoinIrreducible on B2 -gap> IsJoinIrreducible(b2, 1); -true -gap> IsJoinIrreducible(b2, 2); -true -gap> IsJoinIrreducible(b2, 3); -true -gap> IsJoinIrreducible(b2, 4); -false - -# Test IsMeetIrreducible on B2 -gap> IsMeetIrreducible(b2, 1); -false -gap> IsMeetIrreducible(b2, 2); -true -gap> IsMeetIrreducible(b2, 3); -true -gap> IsMeetIrreducible(b2, 4); -true - -# The M3 lattice: 1 < {2, 3, 4} < 5 -gap> m3 := DigraphReflexiveTransitiveClosure(Digraph([[2, 3, 4], [5], [5], [5], []])); - - -# Test IsJoinIrreducible on M3 -gap> IsJoinIrreducible(m3, 1); -true -gap> IsJoinIrreducible(m3, 2); -true -gap> IsJoinIrreducible(m3, 3); -true -gap> IsJoinIrreducible(m3, 4); -true -gap> IsJoinIrreducible(m3, 5); -false - -# Test IsMeetIrreducible on M3 -gap> IsMeetIrreducible(m3, 1); -false -gap> IsMeetIrreducible(m3, 2); -true -gap> IsMeetIrreducible(m3, 3); -true -gap> IsMeetIrreducible(m3, 4); -true -gap> IsMeetIrreducible(m3, 5); -true - -# Teardown test environment -gap> DIGRAPHS_StopTest(); -gap> STOP_TEST("Digraphs package: joinmeetirreducible.tst", 0); diff --git a/tst/standard/oper.tst b/tst/standard/oper.tst index 3f7e5a231..0bf0c42a1 100644 --- a/tst/standard/oper.tst +++ b/tst/standard/oper.tst @@ -17,6 +17,7 @@ #@local out, out1, out2, out3, p1, p2, path, preorder, qr, r, res, rtclosure, t #@local tclosure, u1, u2, x #@local p, q, idp, idt, M +#@local b2, chain, lattice, m3 gap> START_TEST("Digraphs package: standard/oper.tst"); gap> LoadPackage("digraphs", false);; @@ -1822,6 +1823,108 @@ fail gap> PartialOrderDigraphJoinOfVertices(gr1, 3, 4); fail +# IsJoinIrreducible, IsMeetIrreducible + +# The pentagon lattice N5: 1 < {2, 3}, 3 < 4, {2, 4} < 5 +gap> gr := Digraph([[2, 3], [5], [4], [5], []]); + +gap> lattice := DigraphReflexiveTransitiveClosure(gr); + +gap> IsJoinIrreducible(lattice, 1); +true +gap> IsJoinIrreducible(lattice, 2); +true +gap> IsJoinIrreducible(lattice, 3); +true +gap> IsJoinIrreducible(lattice, 4); +true +gap> IsJoinIrreducible(lattice, 5); +false +gap> IsMeetIrreducible(lattice, 1); +false +gap> IsMeetIrreducible(lattice, 2); +true +gap> IsMeetIrreducible(lattice, 3); +true +gap> IsMeetIrreducible(lattice, 4); +true +gap> IsMeetIrreducible(lattice, 5); +true + +# A 4-element chain: every element is doubly irreducible +gap> chain := DigraphReflexiveTransitiveClosure(ChainDigraph(4)); + +gap> IsJoinIrreducible(chain, 1); +true +gap> IsJoinIrreducible(chain, 2); +true +gap> IsJoinIrreducible(chain, 3); +true +gap> IsJoinIrreducible(chain, 4); +true +gap> IsMeetIrreducible(chain, 1); +true +gap> IsMeetIrreducible(chain, 2); +true +gap> IsMeetIrreducible(chain, 3); +true +gap> IsMeetIrreducible(chain, 4); +true + +# The Boolean lattice B2: 1 < {2, 3} < 4 +gap> b2 := DigraphReflexiveTransitiveClosure(Digraph([[2, 3], [4], [4], []])); + +gap> IsJoinIrreducible(b2, 1); +true +gap> IsJoinIrreducible(b2, 2); +true +gap> IsJoinIrreducible(b2, 3); +true +gap> IsJoinIrreducible(b2, 4); +false +gap> IsMeetIrreducible(b2, 1); +false +gap> IsMeetIrreducible(b2, 2); +true +gap> IsMeetIrreducible(b2, 3); +true +gap> IsMeetIrreducible(b2, 4); +true + +# The M3 lattice: 1 < {2, 3, 4} < 5 +gap> m3 := DigraphReflexiveTransitiveClosure(Digraph([[2, 3, 4], [5], [5], [5], []])); + +gap> IsJoinIrreducible(m3, 1); +true +gap> IsJoinIrreducible(m3, 2); +true +gap> IsJoinIrreducible(m3, 3); +true +gap> IsJoinIrreducible(m3, 4); +true +gap> IsJoinIrreducible(m3, 5); +false +gap> IsMeetIrreducible(m3, 1); +false +gap> IsMeetIrreducible(m3, 2); +true +gap> IsMeetIrreducible(m3, 3); +true +gap> IsMeetIrreducible(m3, 4); +true +gap> IsMeetIrreducible(m3, 5); +true + +# Error handling +gap> IsJoinIrreducible(CycleDigraph(3), 1); +Error, the 1st argument must satisfy IsPartialOrderDigraph, +gap> IsMeetIrreducible(CycleDigraph(3), 1); +Error, the 1st argument must satisfy IsPartialOrderDigraph, +gap> IsJoinIrreducible(Digraph([[1]]), 2); +Error, the 2nd argument must be a vertex of the 1st argument , +gap> IsMeetIrreducible(Digraph([[1]]), 2); +Error, the 2nd argument must be a vertex of the 1st argument , + # DigraphClosure gap> gr := Digraph([[4, 5, 6, 7, 9], [7, 3], [2, 6, 7, 9, 10], > [5, 6, 7, 1, 9], [1, 4, 6, 7], [7, 1, 3, 4, 5], From d2fd4fe86e6ead9cc3f9150ff604c72aff1d3538 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andromeda=20=E2=9C=A8?= Date: Wed, 1 Apr 2026 16:44:25 +0100 Subject: [PATCH 8/8] Apply suggestion from @james-d-mitchell If I understand correctly, InDegrees is faster than InDegreeOfVertexNC here due to caching behaviour where the in degrees of the digraph are computed once then looked up from cache, as opposed to the other function which has to recompute for each input vertex. Co-authored-by: James Mitchell --- gap/oper.gi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gap/oper.gi b/gap/oper.gi index c652d8c91..cf9b23465 100644 --- a/gap/oper.gi +++ b/gap/oper.gi @@ -2733,7 +2733,7 @@ function(D, v) fi; hasse := DigraphReflexiveTransitiveReduction(DigraphMutableCopyIfMutable(D)); # join-irreducible iff at most one lower cover in the Hasse diagram - return InDegreeOfVertexNC(hasse, v) <= 1; + return InDegrees(hasse)[v] <= 1; end); InstallMethod(IsMeetIrreducible,