diff --git a/gap/union-find.gd b/gap/union-find.gd index acecc3f..dfda1a2 100644 --- a/gap/union-find.gd +++ b/gap/union-find.gd @@ -28,7 +28,7 @@ DeclareCategory("IsPartitionDS", IsObject); #! @Description #! Family containing all partition data structures -BindGlobal("PartitionDSFamily", NewFamily(IsPartitionDS)); +BindGlobal("PartitionDSFamily", NewFamily("PartitionDSFamily", IsPartitionDS)); # # Constructors. Given an integer return the trivial partition (n parts of size 1) @@ -38,11 +38,37 @@ BindGlobal("PartitionDSFamily", NewFamily(IsPartitionDS)); #! @Description #! Returns the trivial partition of the set [1..n]. #! @Arguments filter, n -DeclareConstructor("PartitionDS",[IsPartitionDS, IsPosInt]); +DeclareConstructor("PartitionDSCons",[IsPartitionDS, IsPosInt]); + #! @Description #! Returns the union find structure of partition. #! @Arguments filter, partition -DeclareConstructor("PartitionDS",[IsPartitionDS, IsCyclotomicCollColl]); +DeclareConstructor("PartitionDSCons",[IsPartitionDS, IsCyclotomicCollColl]); + +# +# Operations. Given an integer return the trivial partition (n parts of size 1) +# Given a list of disjoint sets, return that partition. Any points up to the maximum +# of any of the sets not included in a set are in singleton parts. +# +#! @Description +#! Returns the trivial partition of the set [1..n]. +#! @Arguments filter, n +DeclareOperation("PartitionDS",[IsFunction, IsPosInt]); + +#! @Description +#! Returns the trivial partition of the set [1..n]. +#! @Arguments n +DeclareOperation("PartitionDS",[IsPosInt]); + +#! @Description +#! Returns the union find structure of partition. +#! @Arguments filter, partition +DeclareOperation("PartitionDS",[IsFunction, IsCyclotomicCollColl]); + +#! @Description +#! Returns the union find structure of partition. +#! @Arguments partition +DeclareOperation("PartitionDS",[IsCyclotomicCollColl]); # # Key operations @@ -69,6 +95,13 @@ DeclareOperation("Unite",[IsPartitionDS and IsMutable, IsPosInt, IsPosInt]); #! @Returns an iterator DeclareOperation("RootsIteratorOfPartitionDS", [IsPartitionDS]); +#! @Description +#! Returns a list of the canonical representatives of the parts +#! of the partition unionfind. +#! @Arguments unionfind +#! @Returns A list. +DeclareOperation("RootsOfPartitionDS", [IsPartitionDS]); + #! @Description #! Returns the number of parts of the partition unionfind. #! @Arguments unionfind diff --git a/gap/union-find.gi b/gap/union-find.gi index 5161b83..7007e25 100644 --- a/gap/union-find.gi +++ b/gap/union-find.gi @@ -25,7 +25,7 @@ UF.setRank := UF.Bitfields.setters[1]; UF.setParent := UF.Bitfields.setters[2]; -InstallMethod(PartitionDS, [IsPartitionDSRep and IsPartitionDS and IsMutable, IsPosInt], +InstallMethod(PartitionDSCons, [IsPartitionDSRep and IsPartitionDS and IsMutable, IsPosInt], function(filt, n) local r; r := rec(); @@ -37,7 +37,7 @@ InstallMethod(PartitionDS, [IsPartitionDSRep and IsPartitionDS and IsMutable, Is end); -InstallMethod(PartitionDS, [IsPartitionDSRep and IsPartitionDS and IsMutable, IsCyclotomicCollColl], +InstallMethod(PartitionDSCons, [IsPartitionDSRep and IsPartitionDS and IsMutable, IsCyclotomicCollColl], function(filt, parts) local r, n, seen, sp, sr, p, x; if not (ForAll(parts, IsSet) and @@ -66,76 +66,31 @@ InstallMethod(PartitionDS, [IsPartitionDSRep and IsPartitionDS and IsMutable, Is return r; end); +InstallMethod(PartitionDS, [IsPosInt], +n -> PartitionDSCons(IsPartitionDSRep, n)); +InstallMethod(PartitionDS, [IsCyclotomicCollColl], +parts -> PartitionDSCons(IsPartitionDSRep, parts)); -UF.RepresentativeTarjan := - function(uf, x) - local gp, sp, p, y, z; - gp := UF.getParent; - sp := UF.setParent; - p := uf!.data; - while true do - y := gp(p[x]); - if y = x then - return x; - fi; - z := gp(p[y]); - if y = z then - return y; - fi; - p[x] := sp(p[x],z); - x := z; - od; -end; +InstallMethod(PartitionDS, [IsFunction, IsPosInt], +{filt, n} -> PartitionDSCons(filt, n)); -if IsBound(DS_UF_FIND) then - UF.RepresentativeKernel := function(uf, x) - return DS_UF_FIND(x, uf!.data); - end; - InstallMethod(Representative, [IsPartitionDSRep and IsPartitionDS, IsPosInt], - UF.RepresentativeKernel); -else - InstallMethod(Representative, [IsPartitionDSRep and IsPartitionDS, IsPosInt], - UF.RepresentativeTarjan); -fi; +InstallMethod(PartitionDS, [IsFunction, IsCyclotomicCollColl], +{filt, parts} -> PartitionDSCons(filt, parts)); -UF.UniteGAP := function(uf, x, y) - local r, rx, ry; - x := Representative(uf, x); - y := Representative(uf, y); - if x = y then - return; - fi; - r := uf!.data; - rx := UF.getRank(r[x]); - ry := UF.getRank(r[y]); - if rx > ry then - r[y] := UF.setParent(r[y],x); - elif ry > rx then - r[x] := UF.setParent(r[x],y); - else - r[x] := UF.setParent(r[x],y); - r[y] := UF.setRank(r[y],ry+1); - fi; - uf!.nparts := uf!.nparts -1; - return; +UF.RepresentativeKernel := function(uf, x) + return DS_UF_FIND(x, uf!.data); end; - - -if IsBound(DS_UF_UNITE) then - InstallMethod(Unite, [IsPartitionDSRep and IsMutable and IsPartitionDS, - IsPosInt, IsPosInt], - function(uf, x, y) - if DS_UF_UNITE(x, y, uf!.data) then - uf!.nparts := uf!.nparts -1; - fi; - end); -else - InstallMethod(Unite, [IsPartitionDSRep and IsMutable and IsPartitionDS, - IsPosInt, IsPosInt], - UF.UniteGAP); -fi; - +InstallMethod(Representative, [IsPartitionDSRep and IsPartitionDS, IsPosInt], + UF.RepresentativeKernel); + +InstallMethod(Unite, [IsPartitionDSRep and IsMutable and IsPartitionDS, + IsPosInt, IsPosInt], + function(uf, x, y) + if DS_UF_UNITE(x, y, uf!.data) then + uf!.nparts := uf!.nparts -1; + fi; +end); InstallMethod(\=, [IsPartitionDSRep and IsPartitionDS, IsPartitionDSRep and IsPartitionDS], IsIdenticalObj); @@ -193,6 +148,26 @@ InstallMethod(RootsIteratorOfPartitionDS, [IsPartitionDSRep and IsPartitionDS], end)); end); +InstallMethod(RootsOfPartitionDS, [IsPartitionDSRep and IsPartitionDS], +function(uf) + local pt, gp, data, n, result; + pt := 0; + gp := UF.getParent; + data := uf!.data; + n := SizeUnderlyingSetDS(uf); + result := []; + while pt <= n do + pt := pt + 1; + while pt <= n and gp(data[pt]) <> pt do + pt := pt + 1; + od; + if pt <= n then + Add(result, pt); + fi; + od; + return result; +end); + InstallMethod(PartsOfPartitionDS, [IsPartitionDS], function(u) local p, i, r, x; diff --git a/tst/uf.tst b/tst/uf.tst index 41c9e85..29a4a88 100644 --- a/tst/uf.tst +++ b/tst/uf.tst @@ -5,7 +5,7 @@ gap> START_TEST("uf.tst"); # Test the union-find data structure # # -gap> u := PartitionDS(IsPartitionDS,10); +gap> u := PartitionDS(10); gap> NumberParts(u); 10 @@ -36,7 +36,7 @@ gap> Unite(u,1,3); gap> u; gap> Print(u,"\n"); -PartitionDS( IsPartitionDS, [ [ 1, 2, 3 ], [ 4 ], [ 5 ], [ 6 ], [ 7 ], [ 8 ], \ +PartitionDS(IsPartitionDS, [ [ 1, 2, 3 ], [ 4 ], [ 5 ], [ 6 ], [ 7 ], [ 8 ], \ [ 9 ], [ 10 ] ]) gap> PartitionDS( IsPartitionDS, [ [ 1, 2, 3 ], [ 4 ], [ 5 ], [ 6 ], [ 7 ], [ 8 ], > [ 9 ], [ 10 ] ]); @@ -57,6 +57,8 @@ gap> for x in i do Print(x,"\n"); od; 8 9 10 +gap> RootsOfPartitionDS(u); +[ 2, 4, 5, 6, 7, 8, 9, 10 ] gap> for x in i2 do Print(x,"\n"); od; 4 5 @@ -65,21 +67,21 @@ gap> for x in i2 do Print(x,"\n"); od; 8 9 10 -gap> UF.RepresentativeTarjan(u,3); +gap> Representative(u,3); 2 -gap> UF.UniteGAP(u,4,5); +gap> Unite(u,4,5); gap> u; -gap> PartitionDS(IsPartitionDS,[[2,1]]); +gap> PartitionDS([[2,1]]); Error, PartitionDS: supplied partition must be a list of disjoint sets of posi\ tive integers -gap> PartitionDS(IsPartitionDS,[[-2,1]]); +gap> PartitionDS([[-2,1]]); Error, PartitionDS: supplied partition must be a list of disjoint sets of posi\ tive integers -gap> PartitionDS(IsPartitionDS,[[1,2,3],[3,4,5]]); +gap> PartitionDS([[1,2,3],[3,4,5]]); Error, PartitionDS: supplied partition must be a list of disjoint sets of posi\ tive integers -gap> u := PartitionDS(IsPartitionDS, 16); +gap> u := PartitionDS(16); gap> for i in [1,3..15] do Unite(u,i, i+1); od; gap> for i in [1,5..13] do Unite(u,i, i+2); od; @@ -89,28 +91,30 @@ gap> Representative(u,1); 16 gap> Representative(u,15); 16 -gap> u := PartitionDS(IsPartitionDS, 16); +gap> u := PartitionDS(16); -gap> for i in [1,3..15] do UF.UniteGAP(u,i, i+1); od; -gap> for i in [1,5..13] do UF.UniteGAP(u,i, i+2); od; -gap> for i in [1,9] do UF.UniteGAP(u,i, i+4); od; -gap> UF.UniteGAP(u,1,9); -gap> UF.RepresentativeTarjan(u,1); +gap> for i in [1,3..15] do Unite(u,i, i+1); od; +gap> for i in [1,5..13] do Unite(u,i, i+2); od; +gap> for i in [1,9] do Unite(u,i, i+4); od; +gap> Unite(u,1,9); +gap> Representative(u,1); 16 -gap> UF.RepresentativeTarjan(u,15); +gap> Representative(u,15); 16 -gap> u := PartitionDS(IsPartitionDS, 16);; +gap> u := PartitionDS(16);; gap> Unite(u,1,2); gap> Unite(u,2,3); gap> Unite(u,4,2); gap> Unite(u,5,5); -gap> UF.UniteGAP(u,9,10); -gap> UF.UniteGAP(u,10,11); -gap> UF.UniteGAP(u,12,10); -gap> UF.UniteGAP(u,9,12); +gap> Unite(u,9,10); +gap> Unite(u,10,11); +gap> Unite(u,12,10); +gap> Unite(u,9,12); gap> PartsOfPartitionDS(u); [ [ 1, 2, 3, 4 ], [ 5 ], [ 6 ], [ 7 ], [ 8 ], [ 9, 10, 11, 12 ], [ 13 ], [ 14 ], [ 15 ], [ 16 ] ] +gap> RootsOfPartitionDS(u); +[ 2, 5, 6, 7, 8, 10, 13, 14, 15, 16 ] # gap> STOP_TEST( "uf.tst", 1);