From daf6d6fc1effa12b6b642174da143db08e5f05e0 Mon Sep 17 00:00:00 2001 From: reiniscirpons <43414125+reiniscirpons@users.noreply.github.com> Date: Mon, 16 Mar 2020 17:01:39 +0000 Subject: [PATCH] Add DigraphMaximumMatching (#294) * Add maximal mathing and maximum mathing methods and helper methods. * Add documentation and examples for DigraphMaximalMatching and DigraphMaximumMatching as well as documentation for IsMaximumMatching. * Fix typo, add examples and implementation for IsMaximumMatching * Fix manual examples * Add tests for matching methods, fix label bug in maximum matching code * Add more tests for maximum matching, improve documentation and code * Update oper.xml Remove duplicate "that" * Remove non-deterministic tests * Fix tests Co-authored-by: James Mitchell --- doc/attr.xml | 64 ++++++++++++ doc/oper.xml | 29 ++++-- doc/z-chap4.xml | 2 + gap/attr.gd | 3 + gap/attr.gi | 234 ++++++++++++++++++++++++++++++++++++++++++ gap/oper.gd | 1 + gap/oper.gi | 7 ++ tst/standard/attr.tst | 212 ++++++++++++++++++++++++++++++++++++++ tst/standard/oper.tst | 10 ++ 9 files changed, 553 insertions(+), 9 deletions(-) diff --git a/doc/attr.xml b/doc/attr.xml index f8b9157ca..5f8e361ca 100644 --- a/doc/attr.xml +++ b/doc/attr.xml @@ -2179,3 +2179,67 @@ true <#/GAPDoc> + +<#GAPDoc Label="DigraphMaximalMatching"> + + + A list of pairs of vertices. + + This function returns a maximal matching of the digraph digraph. +

+ + For the definition of a maximal matching, see . + + D := DigraphFromDiSparse6String(".IeAoXCJU@|SHAe?d"); + +gap> M := DigraphMaximalMatching(D);; IsMaximalMatching(D, M); +true +gap> D := RandomDigraph(100);; +gap> IsMaximalMatching(D, DigraphMaximalMatching(D)); +true +gap> D := GeneralisedPetersenGraph(IsMutableDigraph, 9, 2); + +gap> IsMaximalMatching(D, DigraphMaximalMatching(D)); +true +]]> + + +<#/GAPDoc> + +<#GAPDoc Label="DigraphMaximumMatching"> + + + A list of pairs of vertices. + + This function returns a maximum matching of the digraph digraph. +

+ + For the definition of a maximum matching, see . + If digraph is bipartite (see ), then + the algorithm used has complexity O(m*sqrt(n)). Otherwise for general + graphs the complexity is O(m*n*log(n)). Here n is the number of vertices + and m is the number of edges. + + D := DigraphFromDigraph6String("&I@EA_A?AdDp[_c??OO"); + +gap> M := DigraphMaximumMatching(D);; IsMaximalMatching(D, M); +true +gap> Length(M); +5 +gap> D := Digraph([[5, 6, 7, 8], [6, 7, 8], [7, 8], [8], +> [], [], [], []]);; +gap> M := DigraphMaximumMatching(D); +[ [ 1, 5 ], [ 2, 6 ], [ 3, 7 ], [ 4, 8 ] ] +gap> D := GeneralisedPetersenGraph(IsMutableDigraph, 9, 2); + +gap> M := DigraphMaximumMatching(D);; +gap> IsMaximalMatching(D, M); +true +gap> Length(M); +9 +]]> + + +<#/GAPDoc> diff --git a/doc/oper.xml b/doc/oper.xml index 610fde462..11ffbcebc 100644 --- a/doc/oper.xml +++ b/doc/oper.xml @@ -1658,28 +1658,34 @@ true + true or false. If digraph is a digraph and list is a list of pairs of vertices of digraph, then IsMatching returns true if - list is a matching of digraph. The operations - IsMaximalMatching and IsPerfectMatching return true if - list is a maximal, or perfect, matching of digraph, - respectively. Otherwise, these operations return false.

+ list is a matching of digraph. The operation + IsMaximalMatching returns true if list is a maximal + matching, IsMaximumMatching returns true if list is a + maximum matching and IsPerfectMatching returns true if + list is a perfect, matching of digraph, respectively. + Otherwise, each of these operations return false. +

A matching M of a digraph digraph is a subset of the edges of digraph, i.e. DigraphEdges(digraph), such that no pair of distinct edges in M are incident to the same vertex of digraph. Note that this definition allows a matching to contain loops. See . The matching M is - maximal if it is contained in no larger matching of the digraph, and + maximal if it is contained in no larger matching of the digraph, + is maximum if it has the greatest cardinality among all matchings and is perfect if every vertex of the digraph is incident to an edge in - the matching. Every perfect matching is maximal. + the matching. Every maximum or perfect matching is maximal. Note, however, + that not every perfect matching of digraphs with loops is maximum. D := Digraph([[2], [1], [2, 3, 4], [3, 5], [1]]); - +gap> D := Digraph([[1, 2], [1, 2], [2, 3, 4], [3, 5], [1]]); + gap> IsMatching(D, [[2, 1], [3, 2]]); false gap> edges := [[3, 2]];; @@ -1687,7 +1693,7 @@ gap> IsMatching(D, edges); true gap> IsMaximalMatching(D, edges); false -gap> edges := [[5, 1], [3, 3]];; +gap> edges := [[2, 1], [3, 4]];; gap> IsMaximalMatching(D, edges); true gap> IsPerfectMatching(D, edges); @@ -1695,6 +1701,11 @@ false gap> edges := [[1, 2], [3, 3], [4, 5]];; gap> IsPerfectMatching(D, edges); true +gap> IsMaximumMatching(D, edges); +false +gap> edges := [[1, 1], [2, 2], [3, 3], [4, 5]];; +gap> IsMaximumMatching(D, edges); +true ]]> diff --git a/doc/z-chap4.xml b/doc/z-chap4.xml index 266b98642..3a4daedec 100644 --- a/doc/z-chap4.xml +++ b/doc/z-chap4.xml @@ -15,6 +15,8 @@ <#Include Label="DigraphOutEdges"> <#Include Label="IsDigraphEdge"> <#Include Label="IsMatching"> + <#Include Label="DigraphMaximalMatching"> + <#Include Label="DigraphMaximumMatching">

Neighbours and degree diff --git a/gap/attr.gd b/gap/attr.gd index 3f1cbe312..40f70d42c 100644 --- a/gap/attr.gd +++ b/gap/attr.gd @@ -114,3 +114,6 @@ DeclareAttribute("DigraphMycielskianAttr", IsDigraph); DeclareAttribute("DigraphCartesianProductProjections", IsDigraph); DeclareAttribute("DigraphDirectProductProjections", IsDigraph); + +DeclareAttribute("DigraphMaximalMatching", IsDigraph); +DeclareAttribute("DigraphMaximumMatching", IsDigraph); diff --git a/gap/attr.gi b/gap/attr.gi index 9761bc160..b63ab73ee 100644 --- a/gap/attr.gi +++ b/gap/attr.gi @@ -2044,3 +2044,237 @@ InstallMethod(DigraphMycielskian, InstallMethod(DigraphMycielskianAttr, "for an immutable digraph", [IsImmutableDigraph], DigraphMycielskian); + +# Uses a simple greedy algorithm. +BindGlobal("DIGRAPHS_MaximalMatching", +function(D) + local mate, u, v; + mate := ListWithIdenticalEntries(DigraphNrVertices(D), 0); + for v in DigraphVertices(D) do + if mate[v] = 0 then + for u in OutNeighboursOfVertex(D, v) do + if mate[u] = 0 then + mate[u] := v; + mate[v] := u; + break; + fi; + od; + fi; + od; + return mate; +end); + +# For bipartite digraphs implements the Hopcroft-Karp matching algorithm, +# complexity O(m*sqrt(n)) +BindGlobal("DIGRAPHS_BipartiteMatching", +function(D, mate) + local U, dist, inf, dfs, bfs, u; + + U := DigraphBicomponents(D); + U := U[PositionMinimum(U, Length)]; + + bfs := function() + local v, que, q; + que := []; + for v in U do + if mate[v] = inf then + dist[v] := 0; + Add(que, v); + else + dist[v] := inf; + fi; + od; + dist[inf] := inf; + + q := 1; + while q <= Length(que) do + if dist[que[q]] < dist[inf] then + for v in OutNeighborsOfVertex(D, que[q]) do + if dist[mate[v]] = inf then + dist[mate[v]] := dist[que[q]] + 1; + Add(que, mate[v]); + fi; + od; + fi; + q := q + 1; + od; + return dist[inf] <> inf; + end; + + dfs := function(u) + local v; + if u = inf then + return true; + fi; + for v in OutNeighborsOfVertex(D, u) do + if dist[mate[v]] = dist[u] + 1 and dfs(mate[v]) then + mate[v] := u; + mate[u] := v; + return true; + fi; + od; + dist[u] := inf; + return false; + end; + + inf := DigraphNrVertices(D) + 1; + dist := ListWithIdenticalEntries(inf, inf); + for u in [1 .. Length(mate)] do + if mate[u] = 0 then + mate[u] := inf; + fi; + od; + + while bfs() do + for u in U do + if mate[u] = inf then dfs(u); + fi; + od; + od; + + for u in [1 .. DigraphNrVertices(D)] do + if mate[u] = inf then + mate[u] := 0; + fi; + od; + + return mate; +end); + +# For general digraphs implements a modified version of Gabow's maximum matching +# algorithm, complexity O(m*n*log(n)). +BindGlobal("DIGRAPHS_GeneralMatching", +function(D, mate) + local blos, pred, time, t, tj, u, dfs, mark, blosfind; + + blosfind := function(x) + if x <> blos[x] then + blos[x] := blosfind(blos[x]); + fi; + return blos[x]; + end; + + mark := function(v, x, b, path) + while blosfind(v) <> b do + pred[v] := x; + x := mate[v]; + Add(tj, v); + Add(tj, x); + if time[x] = 0 then + t := t + 1; + time[x] := t; + Add(path, x); + fi; + v := pred[x]; + od; + end; + + dfs := function(v) + local x, bx, bv, b, y, z, path; + for x in OutNeighboursOfVertex(D, v) do + bv := blosfind(v); + bx := blosfind(x); + if bx <> bv then + if time[x] > 0 then + path := []; + tj := []; + if time[bx] < time[bv] then + b := bx; + mark(v, x, b, path); + else + b := bv; + mark(x, v, b, path); + fi; + for z in tj do + blos[z] := b; + od; + for z in path do + if dfs(z) then + return true; + fi; + od; + elif pred[x] = 0 then + pred[x] := v; + if mate[x] = 0 then + while x <> 0 do + y := pred[x]; + v := mate[y]; + mate[y] := x; + mate[x] := y; + x := v; + od; + return true; + fi; + if time[mate[x]] = 0 then + t := t + 1; + time[mate[x]] := t; + if dfs(mate[x]) then + return true; + fi; + fi; + fi; + fi; + od; + return false; + end; + + time := ListWithIdenticalEntries(DigraphNrVertices(D), 0); + blos := [1 .. DigraphNrVertices(D)]; + pred := ListWithIdenticalEntries(DigraphNrVertices(D), 0); + t := 0; + for u in DigraphVertices(D) do + if mate[u] = 0 then + t := t + 1; + time[u] := t; + if dfs(u) then + time := ListWithIdenticalEntries(DigraphNrVertices(D), 0); + blos := [1 .. DigraphNrVertices(D)]; + pred := ListWithIdenticalEntries(DigraphNrVertices(D), 0); + fi; + fi; + od; + + return mate; +end); + +BindGlobal("DIGRAPHS_MateToMatching", +function(D, mate) + local u, M; + M := []; + for u in DigraphVertices(D) do + if u <= mate[u] then + if IsDigraphEdge(D, u, mate[u]) then + Add(M, [u, mate[u]]); + elif IsDigraphEdge(D, mate[u], u) then + Add(M, [mate[u], u]); + fi; + fi; + od; + return Set(M); +end); + +InstallMethod(DigraphMaximalMatching, "for a digraph", [IsDigraph], +D -> DIGRAPHS_MateToMatching(D, DIGRAPHS_MaximalMatching(D))); + +InstallMethod(DigraphMaximumMatching, "for a digraph", [IsDigraph], +function(D) + local mateG, mateD, G, M, i, lab; + G := DigraphImmutableCopy(D); + G := InducedSubdigraph(G, Difference(DigraphVertices(G), DigraphLoops(G))); + lab := DigraphVertexLabels(G); + G := DigraphSymmetricClosure(G); + mateG := DIGRAPHS_MaximalMatching(G); + if IsBipartiteDigraph(G) then + mateG := DIGRAPHS_BipartiteMatching(G, mateG); + else + mateG := DIGRAPHS_GeneralMatching(G, mateG); + fi; + mateD := ListWithIdenticalEntries(DigraphNrVertices(D), 0); + for i in DigraphVertices(G) do + if mateG[i] <> 0 then + mateD[lab[i]] := lab[mateG[i]]; + fi; + od; + M := List(DigraphLoops(D), x -> [x, x]); + return Union(M, DIGRAPHS_MateToMatching(D, mateD)); +end); diff --git a/gap/oper.gd b/gap/oper.gd index a635c7d1e..88d90b6b0 100644 --- a/gap/oper.gd +++ b/gap/oper.gd @@ -88,6 +88,7 @@ DeclareOperation("IsUndirectedSpanningForest", [IsDigraph, IsDigraph]); DeclareOperation("IsMatching", [IsDigraph, IsHomogeneousList]); DeclareOperation("IsMaximalMatching", [IsDigraph, IsHomogeneousList]); +DeclareOperation("IsMaximumMatching", [IsDigraph, IsHomogeneousList]); DeclareOperation("IsPerfectMatching", [IsDigraph, IsHomogeneousList]); # 9. Connectivity . . . diff --git a/gap/oper.gi b/gap/oper.gi index 2688aec11..20380da6e 100644 --- a/gap/oper.gi +++ b/gap/oper.gi @@ -1108,6 +1108,13 @@ function(D, edges) return SizeBlist(seen) = DigraphNrVertices(D); end); +InstallMethod(IsMaximumMatching, "for a digraph and a list", +[IsDigraph, IsHomogeneousList], +function(D, edges) + return IsMatching(D, edges) + and Length(edges) = Length(DigraphMaximumMatching(D)); +end); + InstallMethod(IsMaximalMatching, "for a digraph and a list", [IsDigraphByOutNeighboursRep, IsHomogeneousList], function(D, edges) diff --git a/tst/standard/attr.tst b/tst/standard/attr.tst index f203be973..30180f528 100644 --- a/tst/standard/attr.tst +++ b/tst/standard/attr.tst @@ -2210,6 +2210,218 @@ gap> P := DigraphRemoveAllMultipleEdges(ReducedDigraph(OnDigraphs(D, proj[2]))); gap> IsIsomorphicDigraph(H, P); true +# DigraphMaximalMatching +gap> D := DigraphFromDigraph6String("&Sq_MN|bDCLy~Xj}u}GxOLlGfqJtnSQ|l\ +> Q?lYvjbqN~XNNAQYDJE[UHOhyGOqtsjCWJy["); + +gap> M := DigraphMaximalMatching(D);; IsMaximalMatching(D, M); +true +gap> D := DigraphFromDigraph6String(IsMutable, "&Sq_MN|bDCLy~Xj}u}GxOLlGfqJtnSQ|l\ +> Q?lYvjbqN~XNNAQYDJE[UHOhyGOqtsjCWJy["); + +gap> M := DigraphMaximalMatching(D);; IsMaximalMatching(D, M); +true +gap> D := Digraph(IsMutable, [[2], [3], [4], [1]]); + +gap> M := DigraphMaximalMatching(D);; +gap> M = [[1, 2], [3, 4]] or M = [[2, 3], [4, 1]]; +true +gap> D; + + +# DigraphMaximumMatching +gap> D := DigraphFromDiSparse6String(".]cBn@kqAlt?EpclQp|M}bAgFjHkoDsIuACyCM_Hj"); + +gap> M := DigraphMaximumMatching(D);; IsMaximalMatching(D, M); +true +gap> Length(M); +14 +gap> D := Digraph([[5, 6, 7, 8], [6, 7, 8], [7, 8], [8], [], [], [], []]); + +gap> DigraphMaximumMatching(D); +[ [ 1, 5 ], [ 2, 6 ], [ 3, 7 ], [ 4, 8 ] ] +gap> D := Digraph(IsMutable, [[2, 3], [1, 4], [2, 4], [5], [3, 5]]); + +gap> M := DigraphMaximumMatching(D);; IsMaximalMatching(D, M); +true +gap> Length(M); +3 +gap> D := DigraphFromDiSparse6String("\ +> .~?B]zsE?cB?kH?cK?{M?{O?SIaWHaoQ_{X??@?wJ@gT`{[BKF@s^BG[_OOAca?{@@gXB_^bK?A\ +> gXbGc_gF@o\\dGG`gXC[X`K__OC?oG@GI@wOAGQAWSAoWBOZBo_CGgDGkDk?BGd_wMBgfdsFC{Q\ +> Ao]CGmdsJBGbC_ebGdD{ZDsXCgnEsC?oHAWkDsFbK@BGb`?PDsD?wfcGmE[Fb?ZD?mEWsE{LBGb\ +> DSmEW~aOmE[XB_^C[XbKmEW~G[gDp@_x?dop_wfdosGKWDp@dsJBGt`wYDopFHJH{FA{F_waG@I\ +> I[OC?mbGtdsUDor`?IAG_DGmFhVbWgDovGHH_GXBwbFcFCwqdpVJKXG{XGx]_wVISC?omFKXF[X\ +> CkFCP?IXSaOmEXCbGtIsXGs?BGddpP_xS_wKAwfIP_dpVJH\\_?TBGdDWnEowFXEGx]JxaKXfLC\ +> mEHJIKUDorJCFL[XDXfLkWDosGHLHpY`GkDox`WXEhOIsmEW~dorFxtbGjLhpcGmEW~MkA?_E@?\ +> H@ONA?PAWSBO_DGkDgmEGxFhJHxPIhVJH\\KHhL`mM[A@?IA?PA__DGlDo|IhVJH\\L`x_WF`wY\ +> DpPNKQAo]DorFxCJ@dL{IAGmJHkNHydopHxPNKUDorNkgDp@JS?BGdL@lbGeEk@@WLBG[BwbC_e\ +> DOtF`AGhOIpZKplMaBcGmEW~c?lDpxNSFdorFxBHCFL[mIHhNKmFHx_wfEP[aOUB?ZBo`D?mEWs\ +> Ew~GHBG`GHHLHpWJPdLxqMhuN@xNi?OIDPCSC?mNHybGbDPDOcFNYFbGbOaN_waIcF_wyQ[FLYH\ +> do|JHxNSFHPSLSmEW~OiLbOmIHhLpxPSF@`jaWmFHx__E@GNAWYD_mEGxHXNIH`LHmMXxNP{NyI\ +> PYXR[XChbLkXCgnKXlRkmGHMMQLdo|JHxNQUaWmFHxPY[dp@JQLbWmEx@HHYPkmFHxPY[SKFAxj\ +> PITdp@HhqPi^a?_DpTNHydp@JQLSSXEhUKqC_WFFQS_yFQCB?waFP?HPRI`cLPzOyOQQRQaVTQj\ +> dp@JQLSQbTCD?wK@oVBgfE?qFpKIP[K@jMAHPaTRQdTcFCxKJam_xSLQVTc_DgmNHyOsmGHMMQL\ +> dorNi?PkXCotOYCbHEKPfLk]DorNi?PkgDp@HHYPkFCw}HamT{FQYkdorFyDPiWdosGHLMQL_WF\ +> NYkdp@JQ@PkRDoxNIZRcAC?lDpxNSmGHqPi^SsWDp@MQLbGzJpaLkXC_tKqCagXChl_?TBGdLjC\ +> cGmEW~NALbGcEiCW[FIXSKak_WFFPSNYFQARQaiTYkVI{_gFCwoFqmb?mGHqPj@dp@JQ@Pi|a__\ +> DpTNHyPsmHxPNH~RcmEW~GXtMqLbGdDWzGpFJp^KPfLhpMytWSXCYCPyP_waIaQTcFLXoQimdor\ +> Ni?Pir_yRTaxXKF@`jRQm_x?HPSTc??GB?gF@WK@gMAgVBG[Bg^CObC_dCofDOjDonE?qEguF?y\ +> FW{Fp?GPDGpFHPKI@QIXSIpZJ`]Jx_KPbK`eKxgLPjLhoMHsMxzOQBOaFPIKPyOQIQQYSQiVRQ\\ +> \RqdTIiTYkTqnUAsUiwVI{WRBWbDWzGXJIYBPYRRYjUY{GDGmJHxNSAC?mNHyV{mGHMMQLUS]Do\ +> rNiLUsFLXoTrRYrW");; +gap> M := DigraphMaximumMatching(D);; IsMaximalMatching(D, M); +true +gap> Length(M); +111 +gap> M1 := [ +> [1, 198], [2, 61], [3, 219], [4, 189], [5, 10], [6, 63], [7, 98], [8, 26], +> [9, 62], [11, 18], [12, 81], [13, 155], [14, 67], [15, 30], [16, 125], +> [17, 168], [19, 23], [20, 162], [21, 143], [22, 197], [24, 166], [25, 79], +> [27, 154], [28, 56], [29, 70], [31, 221], [32, 92], [33, 90], [34, 134], +> [35, 101], [36, 54], [37, 39], [38, 209], [40, 108], [41, 130], [42, 218], +> [43, 144], [44, 120], [45, 116], [46, 192], [47, 217], [48, 159], [49, 203], +> [50, 128], [51, 141], [52, 66], [53, 188], [55, 57], [58, 82], [59, 171], +> [60, 99], [64, 126], [65, 216], [68, 208], [69, 102], [71, 182], [72, 96], +> [73, 137], [74, 184], [75, 152], [76, 111], [77, 185], [78, 167], [80, 207], +> [83, 97], [84, 201], [85, 202], [86, 206], [87, 117], [88, 94], [89, 112], +> [91, 115], [93, 176], [95, 195], [100, 158], [103, 170], [104, 114], +> [105, 131], [106, 139], [107, 177], [109, 127], [110, 133], [113, 212], +> [118, 119], [121, 199], [122, 142], [123, 157], [124, 145], [129, 183], +> [132, 181], [135, 178], [136, 172], [138, 150], [140, 165], [146, 210], +> [147, 211], [148, 149], [151, 161], [153, 187], [156, 191], [160, 193], +> [163, 169], [164, 174], [173, 175], [179, 220], [180, 213], [186, 214], +> [190, 205], [194, 204], [196, 200], [215, 222]];; +gap> M = M1; +true +gap> D := DigraphFromDiSparse6String("\ +> .~?@}~ggEb?eM@X?@_?CC@OWIAowO_PEPdOOPcX_HBHaPDgWICW[GAOoLE@e?@`ESbp]PfG_[cP\ +> M?@_gMCPk\\_OOJC@CQDPWYd@yHB@_[`pqPD`gdcQA[IH_XFHCUEaShapCd_?SEA_wPCpk\\GAK\ +> cHQiPJwMPHQeGFAE^frQPCqKn_OOJCPSUEaShJQwq__MA?o[GAOoLBpCSDp_XF@w^GQGeHq_jJB\ +> CrLBSwfrOtMWSMCQ}@CPGdfBePDaShKb]PCq{u_?SEA_wPEpscJrm]MW{^MXCdIRGvNgCPCaS{`\ +> os[IAkxNXCiJrAFFA_xPXCRGAgnKCYPGAgnQGOJCPSdIQwv_@C\\HA|?_PCdNCQA?pwpMBe@C@C\ +> db`CnOGCPHWCPHSPK_rCxRWs[IBc|PX[^MW_[GbeSFbd@`@CTHQwvQgkPHQwvQgGBBpOVF@w^Hb\ +> CsLR_xMcDARTHSTgCOCQTMbp{sMSHXdp{xTDe@CQTO_b_xRTeDB`CnMsA^MTPXVGGBD@w^HbCwM\ +> SDLSdXXVg_WFACaKrdTaP_XFAoxcPKnNx[^MTd[a?cKE@c[GQGfJBKxPTTaWwCOCQTCRd@YVWs[\ +> MSTRdp{xUTpdfbd@Tdd`fACrMUHeb`CnOC|^bp{sLRcyOddZVHCRJr|cfrdSUTp_b`CnOC|kcQ{\ +> oPca@CQTMSDtffBc|PTMPCqKnLhCRGAKiJr?uNs@EQCdcZfDsd@weMTd`_PCQHRpC`pogMSTF_P\ +> CdPCpPfA_jMSULFBdDSuaFFA_jMSTyfBc|PTLr]~");; +gap> M := DigraphMaximumMatching(D);; IsMaximalMatching(D, M); +true +gap> Length(M); +63 +gap> M1 := [ +> [1, 76], [2, 56], [3, 95], [4, 57], [5, 22], [6, 60], [7, 30], [8, 125], +> [9, 52], [10, 100], [11, 28], [12, 89], [13, 40], [14, 105], [15, 37], +> [16, 67], [17, 91], [18, 58], [19, 120], [20, 73], [21, 87], [23, 63], +> [24, 85], [25, 99], [26, 45], [27, 46], [29, 90], [31, 78], [32, 98], +> [33, 74], [34, 108], [35, 86], [36, 117], [38, 48], [39, 119], [41, 84], +> [42, 75], [43, 71], [44, 123], [47, 88], [49, 114], [50, 83], [51, 68], +> [53, 92], [54, 59], [55, 64], [61, 77], [62, 116], [65, 118], [66, 107], +> [69, 104], [70, 103], [72, 121], [79, 115], [80, 113], [81, 94], [82, 122], +> [93, 110], [96, 109], [97, 112], [101, 111], [102, 106], [124, 126]];; +gap> M = M1; +true +gap> D := DigraphFromDiSparse6String("\ +> .~?BG`WHawSbOT_wJbwYcOOcgCCS`d?SBkj?gedo_`sp?OOdSuCCC?o^bS[cwgdD?A[wdC}gofF\ +> [FGLJA_\\GhIi?uio_j?RF[bH|OaGyjgjjwOFdAHXYdhMbSQIDdE`KKTf?PalGh__jIKYHXPe@H\ +> gD]kLfdXcekPA`pmoSfslG[[n_CCGx_gpGd~CGdDhfic}IKBAhPbS@?XJJpnbogGHdg\\_kXslS\ +> aHeKJKaeXphhqk@pqOODABe[fKHgqoTfCKEPOrOSFxEHHqNQKr`qd@|cTc`YSqMb@G]CsRptl`h\ +> LSc@G`QrSZSS@?G~h`hPKD@X@GpTTLiMifSyjc@[NYUmq@PAOp[D?o]bG\\Gq[T|uiMvCq]Ryjv\ +> H^LUbchZKejUsoRC]mqga`}RaocpHH`wNczJ@WPY]hHPJ|DKa@OqHUK@DhMNYbij@axmQr@xCJ@\ +> KP@sVAcYAkA?wJboOcOOcgabSgBkjCsmCCMCkP_Sieo__cCb_ifWggGwdC}gofF[FGLJBhDHSMh\ +> oMi?uiONHSCH|U@w_fcocXNfhOaLBjwCAD`Dk~ILOkhKKTf?PSKThDLPbSoHKPGD]m@fkctaGUM\ +> LYmoSC{}LklG\\{CGxnw`K|SfsBAmCBp]L{gGHd_@BJ{jKDbg@bLSaHXKpgafS@BpijxpqOADAB\ +> eWycxHKHgNeUAmW@_qI@YhCSFxEHHqr`^MSgN@|cOokeSqMb@?WBoeaXHptl`hLSc@GdkRSZfxw\ +> pIc_gJGHEIiblHiMijc@CN[_OIGQCNOYJuWXBhERancXuuy^nSZCxis[VChZK`ddijvo]H@YLYV\ +> dPuaaohHKNCzJ@WKY]w`DOIH_GHDhzS\\TTlmQv");; +gap> M := DigraphMaximumMatching(D);; IsMaximalMatching(D, M); +true +gap> Length(M); +96 +gap> D := DigraphFromDiSparse6String("\ +> .~?BZ_O?__B_SF?CE_kC_[A@[M@KP?sDACC@{M_OL`cJ`OV`GU`?T_{EA[DASCAKB_O]_GMBk?@\ +> g[b[JBSIBKHBCGA{FC{TCsDAcCAWc_WQ_OP_G`_?_`sL`_\\`W[D{IDsHBOl`?XDcFB?ja{U__g\ +> _WSC{AAWe_GQCgy_?PC_xa?w`waE{MCGuekKB{JBor`O\\ESH`?ZdxE_oXDpDb?lGcVD`B_WUDX\ +> A_OTDSSDH?_?RDCfFsPCo|cg{c_z`obFPR`gaFHQ`_wIK_ExO`O^H{HEhM`?\\Ecr_oZESDBOpH\ +> SCBGob?nHCVDpF_GUDhE_?TGh_a_jJ{idHAJkPD@@JcOCx?J[NCo~JSMFsLJCb`WaIsICGyIk_F\ +> HS`?wI[FBovL{uIKDB_tLkCBWsHxk_WYHpjhk@EHKLK?AwoHXgdxIK{THLdaWkGxcaOjK[PDPDK\ +> SODHCKKgGX_cxAJx}`geGL{`[ICXZ`GaJPx`?`NC_JC^FPVMsDBoxIpt__wIhs_W[ExrbWu_GY_\ +> ?XIKWEXOL{VEPNLqNaopHplPsTLaLa_nHaKaWmH[lHPhPSPPKODXfPCNDPFKshGpdOsgGhc`_fG\ +> aCgXaO[ICh`OScKCGCX?Jy?_waF{ECH\\NsDC?|J`|SCCBw{JX{R{BBozJQ]bhXNQ\\fHWNI[_?\ +> ZF@VNAZexUMyYbGuIhuRKWEhSMiWawsIXsQ{UIPrQsTEPPMQTa_pMIShyRaOnHpnaGmLqPdhKLi\ +> O`wkHXkP{MDXILYMU[LDPHLShHAp`WgGxgUCfPQn`GeGhePImchCPAlc`BKaFTcECXbOt@KQDTS\ +> CCH?KIhc?~KABTCAFp^OQf_G]Fh]Ss?Bg{OAdbacfPZNqbfHYNiajI`b@zSCVNREehUNI]WkTIh\ +> wWcSI`vRbBaWqIXuRZAaOpIPtRR@aGoIHsWCnI@rRA~dpNMQV`olHppQq|`gkHhoQi{`_jH`nV[\ +> JDPJLqRVSIDHILiQVKHD@HLcfQAvcpFPyu_pELIM_hDUfZ__B_o@_CE`WB_OJ_GI_CG_{EaWC_[\ +> A@k@@c?@[V`GUakFAcEaSCAKBACA@{@Bk?@g[`_Z`[I`GW`CFAof_oT_gd_cQC[AAGa_GOCK?@w\ +> _b{]`_\\ECJB_n`OZDsHBOl`?XDcFBCEAwi_gUDKTDCSf[@AOd_?Pa?bFCNCOvcGu`g_EkKBws`\ +> W]`O\\ESHB_pbWo_wYDxE_om_glGcCAwkG[BD[AAgiGK@GCRF{QFsPCsOCkNC_zfPR`gaFHQ`_`\ +> F@P`W_ExOepNbotHssHkFB`K_oqH\\IbHH_WWDxG_OVG{@Aold`DKCjGcRGX]aPAJkPGKOG@Z`w\ +> eF{MCg}JKLC_|JCKF`VcOz`O`FPT`G_IcGBww_wvIPn_o\\EpPLsDB`OLkZHxk_WrHpj_OXEPib\ +> C?H[UHSmKsSDhGKkRD`caPEaHDKSODHCKKND@BKCMNt]NkKCh?JkcFx[N[ICW}JXy`GaFhYNKGF\ +> `X_w_FXWM{EBwyIxu_g]FHUbhTMcBB_vI`r_OZEpRMS@BOtIPpbGsIHob?rI@nawqHxmaopHsTE\ +> @LLcSDxKLYKaXJLQJaOlHQIaGkHHgdXGK{NDQF`ohGqE`ggKaD`_fK[JCpa`OdGP`OSHC`@OKGJ\ +> {FCO~Jp~cG}Jh}fh[Ni___^JX{R{]FXYN[AFPX_G[FI[_?ZF@VR[YExUM{XEpTRKtIaWawsIYVa\ +> oragqQkpI@paWoHxoQ[QDxMLyQaGmHhmQKODhKLkND`JLaN`ojLYr`giHILUSKDHhPap`XFLAJ`\ +> OfGpfPQncpDKsGKiG_xBKaFTdAKYET[DCPa__`G@`Oah_W_KAg_O^JyAS{]Fi@Ss?F`\\OC[FX[\ +> NycbXZNqbbOxNkXF@{SKWExWSCuIxyR{UIpxWksIi\\WcrI`vRbBaXuRZAaPQMkPIIXa?nIAW`w\ +> mHxqQy}dhMMIUVkLD`LQkjH`nQdJQ[IDHlVKHD@HLaPVCGCxGL[FCpiUsEChELIMUkDC`DLALUf\ +> ");; +gap> M := DigraphMaximumMatching(D);; IsMaximalMatching(D, M); +true +gap> Length(M); +109 +gap> D := DigraphFromDiSparse6String("\ +> .~?B]`?C`OFc?B`kbBcd@cf@si@sXeWDCswCczE{|A{~?wGgGRgWeF|E?tJBs_DtP??HC?le_xi\ +> `DipFj?kctZEozd\\LkGNGdbDT\\kxAh|BlWdlgHlwME[CapkcpAm_ompin?JeD{DD]ap[jeAAO\ +> kDpcOK@FX\\KxsN{SooKA}GE?zK[@G@Mp_@?x?fqA`?~GeO?gOA?kk{^B|CIMT?xWcpyP}ZE[TI\ +> [Ps@QNdyc@}R[He@^mLYh|xc`gNtpQ[XCgxGi^tgnNIgnMoBimbXHhYAep\\Lq\\uoYQ[YNUE_I\ +> YiDFf@zNsoG]~BPLc}EwW{OcSTUIoB@s|lV[NAG~skIFPA`PedGiIAOu[ByP[LyKpL\\lJGivJi\ +> xePSzJ{}H`zPAmuAoap]_HxYN]`gJbOTc?BcgKcKMbsjBKm?[r?kyDoqe{~?wG@|@A\\BF|KCCh\ +> iG?DlS?wXGlUAXF`czIDYBCzkGNGdbDT\\e\\fGTNlWdlgHgcA@omE[Yapkm_`mpi`wUnHHkD|J\ +> sUJeADpc_GWKxsN|XnCap?[E@H_MK?x?fpD`?fF{FB{DADfbw^geT?xNJEN`MXCU[AgUs@QOTyc\ +> AP`KoK\\_gdN_HxNLgmKXCgxGi^tgCJHxTEoBimhKDOSuJhmRk]M}uBPfQ[YNUE_IYvXFf@zNso\ +> G]~BPLc}ER|wocSPQiwq?x@lV[NAIrskyGQ|kshGhOxxFyHDNaTj`ny`\\lJGf@UcDVfX^fpKN\\ +> \qUD]nJP");; +gap> M := DigraphMaximumMatching(D);; IsMaximalMatching(D, M); +true +gap> Length(M); +97 +gap> D := DigraphFromDiSparse6String("\ +> .~?B]_O?__B_S@`?E_kC_[A@[I_?H`CF_sD_cB@sA`c?@[IA{Y@CFAcE_gQ__Pc?A@{@BkLBcKB\ +> [J`SW`?VasEAge_gSCkC_WQC[AAGa_GOCK?CCp@g]eCJD{IBWm`Gl`?XDcwAwi_gUDKTDCBA_fa\ +> WeF[QCgy_?PCcOC[NCSMCK_`_^EcJBor`Oq`G[EKG_wn_om_gWDkCAwkG[BApA_OTDP@_GSDH?_\ +> ?RD?~cw}aGeFkO`wcF[MCWy`hQ`_w`W_E{IBxNbotHsGBhL_w[E[EBXJ_gYEHI__XECBB?nHCAA\ +> xFdhE_?TD`DKCSDXCJ{RDPBdHAJkPD@@JcOG@Z`{MCg}`gcFhW`_bF`V`WaF[y`KGBwwI[]ExQL\ +> {EBhPLsDEhO__ZE`NLcrHpj_OX_GWEHKLKVE@JLCnHPfdpHa_lH@dd`FKdbaGiKShG``dCMCxAJ\ +> {LCp|`_dJh{`W~J`z`ObFpZNSHCPx`?`F`X_w_J@vbwyIxuboxIptf@T_W[Exr_OZEpRMSYEhQM\ +> K?IHob?rI@nhyNhsoHhkPljPcmHXiP[QDhILIIaHHLAHhCiGxedHEKiE`ggGhcOlCKYCgXaO[IC\ +> hAKIA`GcKA@`?bG@^cP]_o`Fp\\_g|J`|SCCBw{JX{R{BNY]_O\\FPyRk@B_xNK?NAZbQYbKWEh\ +> SMkVE`RQ{UEXQQsqIHqQkSEHOMISaWoHxoQ[nHpnaHLLqPa?lHaO`xJLaNdXjPqr`hHLQLh@hPa\ +> p`WgLCICxfT{HGiHTsGChCKiGTkFC`BKak_obGPbT[aGHaOii__`G@`TKBC?~KABTC}JyAS{@Bo\ +> |Jq@_?{OAdb_zJ`~ScZFP}S[YFH|SSXF@XNa`exWNY_awuI{UIpxRrDe`TNBCa_rI`vRcRIXuRZ\ +> AaOpIPtWKPE@sRKODxOMYWV|NMQ}`olHqUVkkHhoQi{`_jH`nV[JDPJLsIDHlQQx`HHLaPVFWGx\ +> i_odGqMUkcLALUcbG`fPar_WaGXeURZgPdPQpZV]_O?__B_o@_CE_kK@[@@S?`CP?sDACC@{B@s\ +> A@k@@c?@[I`GU`?T_wS_oR_k^?WO_ONBs@@s?`cJBSIBKH`CFAof_oTCsDCkRCcBC[AAGa_K?@w\ +> _`o^bsKBgobcm`GY`?XDcFB?j_oVDSUDKCDCBC{AAWeF[@AOdFS?AGcFKOFCv`o`EsLC?t`_^Ec\ +> JE[\\b_p`?ZECYDxE_oXGkWDhC__kG[jGSAAgiGK@A_hGC?AWgaOffkOCg{c_zi[aFHQ`_`F@Pc\ +> @ObwuH{HBot`?sHlK_oZEPJbOpHTH_WnHCAAwm_GUDhEd`DKCSG`^dPBJsQDHAJkPD@@JcfG@Z`\ +> weFxY`odJKcFhW``V`WzIsICHT`G_FHS`?wI[FBovIPnbguIHmb_tLkCBWs_WYL[XEPLLS@B@KL\ +> K?AxJaonK{TKslKkRDcQDXEK[PDPDKSO`xBKCfGP^NsLCp@JsKG@\\NcJC_~J`z`ObFsHCO|JPx\ +> `?{JHw_w_F[EBxVMsDBoxIpt__\\IhsexSM\\R_GtISXE`oeXnawqHxmaopLiMahka_nH`jPcRH\ +> YJaOlPSPDcODXGKyG`wiGxeO{MGpdOtDKcKCxCOcJCpachAgH_OL^OCFCO~N{`Fp}_g_Fh|SCCF\ +> a^_W]FXYNY]bgyJLWRc?BWwIxwR[YExUMyYepTMqXb@SRCVE`RMcUIPrQsTEPPMSSe@NMARaPnQ\ +> SPDpLLqPdhKLiO`wkLcMHSLDPiUSKDHGPcJD@FLAJUCICxEKyIT{HCpeTsGChd_wcGYFTcEGPbO\ +> qj_gaGHaOii__`GACTKBC?~O[ABx^OS@Bp]OIe_?\\Ji?Sk[FX[NycbWyJ[YFHYNiaf@XNa`b?v\ +> JA_epVNQ^WstRrDagsIi\\WcrRbBePRMqZaOpRR@aHPMaXWCnMYWV{NDpNMQVVsMDhpVkLD`LMA\ +> TVcKHaSV[JDPmQYy`OhHPlVKHD@kQKGCxGLYOU{FCpFLQNUsEGphPsDC`DPkCKyKU[BPYqZ[ACH\ +> APRY");; +gap> M := DigraphMaximumMatching(D);; IsMaximalMatching(D, M); +true +gap> Length(M); +111 + # DIGRAPHS_UnbindVariables gap> Unbind(adj); gap> Unbind(adj1); diff --git a/tst/standard/oper.tst b/tst/standard/oper.tst index 3c40790d8..ce25eb6ce 100644 --- a/tst/standard/oper.tst +++ b/tst/standard/oper.tst @@ -1739,6 +1739,16 @@ gap> edges := [[1, 1], [2, 3]]; gap> IsMaximalMatching(gr, edges); true +# IsMaximumMatching +gap> D := Digraph([[1, 2], [1, 2], [2, 3, 4], [3, 5], [1]]); + +gap> IsMaximumMatching(D, [[1, 2], [3, 3], [4, 5]]); +false +gap> IsMaximumMatching(D, [[1, 1], [2, 2], [3, 3], [4, 5]]); +true +gap> IsMaximumMatching(D, [[1, 1], [1, 2], [2, 2], [3, 3], [4, 5]]); +false + # DigraphShortestPath gap> gr := Digraph([[1], [3, 4], [5, 6], [4, 2, 3], [4, 5], [1]]);; gap> DigraphShortestPath(gr, 1, 6);