Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 36 additions & 3 deletions gap/union-find.gd
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -38,11 +38,37 @@ BindGlobal("PartitionDSFamily", NewFamily(IsPartitionDS));
#! @Description
#! Returns the trivial partition of the set <C>[1..n]</C>.
#! @Arguments filter, n
DeclareConstructor("PartitionDS",[IsPartitionDS, IsPosInt]);
DeclareConstructor("PartitionDSCons",[IsPartitionDS, IsPosInt]);

#! @Description
#! Returns the union find structure of <A>partition</A>.
#! @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 <C>[1..n]</C>.
#! @Arguments filter, n
DeclareOperation("PartitionDS",[IsFunction, IsPosInt]);

#! @Description
#! Returns the trivial partition of the set <C>[1..n]</C>.
#! @Arguments n
DeclareOperation("PartitionDS",[IsPosInt]);

#! @Description
#! Returns the union find structure of <A>partition</A>.
#! @Arguments filter, partition
DeclareOperation("PartitionDS",[IsFunction, IsCyclotomicCollColl]);

#! @Description
#! Returns the union find structure of <A>partition</A>.
#! @Arguments partition
DeclareOperation("PartitionDS",[IsCyclotomicCollColl]);

#
# Key operations
Expand All @@ -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 <A>unionfind</A>.
#! @Arguments unionfind
#! @Returns A list.
DeclareOperation("RootsOfPartitionDS", [IsPartitionDS]);

#! @Description
#! Returns the number of parts of the partition <A>unionfind</A>.
#! @Arguments unionfind
Expand Down
109 changes: 42 additions & 67 deletions gap/union-find.gi
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand All @@ -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
Expand Down Expand Up @@ -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);

Expand Down Expand Up @@ -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;
Expand Down
44 changes: 24 additions & 20 deletions tst/uf.tst
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ gap> START_TEST("uf.tst");
# Test the union-find data structure
#
#
gap> u := PartitionDS(IsPartitionDS,10);
gap> u := PartitionDS(10);
<union find 10 parts on 10 points>
gap> NumberParts(u);
10
Expand Down Expand Up @@ -36,7 +36,7 @@ gap> Unite(u,1,3);
gap> u;
<union find 8 parts on 10 points>
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 ] ]);
Expand All @@ -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
Expand All @@ -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;
<union find 7 parts on 10 points>
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);
<union find 16 parts on 16 points>
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;
Expand All @@ -89,28 +91,30 @@ gap> Representative(u,1);
16
gap> Representative(u,15);
16
gap> u := PartitionDS(IsPartitionDS, 16);
gap> u := PartitionDS(16);
<union find 16 parts on 16 points>
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);