Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

C implementation of the Bron Kerbosch #313

Merged
merged 35 commits into from
Sep 17, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
6ba6627
add: initial set up for implementing Bron Kerbosch algorithm
jjonusas Feb 7, 2020
b1d113c
add: implemented BronKerbosch with pivoting
jjonusas Mar 3, 2020
21e6ab6
add: BronKerboch now uses a pivot
jjonusas Mar 19, 2020
4ceb7d4
add: only use the symmetric part of the graph in the search cliques
jjonusas Mar 19, 2020
754db7c
add: implemented the use of the addional parameters -- limit, max, size.
jjonusas Mar 25, 2020
a95a2c7
add: using the automorphism group in the computation
jjonusas Apr 3, 2020
c364380
add: now uses include parameter correctly
jjonusas Apr 6, 2020
21611e5
add: first draft
jjonusas Apr 22, 2020
b704a30
doc: added descriptions of the arguments of the main function
jjonusas Apr 23, 2020
36f6cc4
add: fixed small bug and now discard gens which act on the isolated
jjonusas Apr 29, 2020
7d94589
add: CliqueFinder uses C code when possible
jjonusas May 4, 2020
53ec307
add: implemented suggested technical changes
jjonusas May 13, 2020
7cc4ab2
add: initial set up for implementing Bron Kerbosch algorithm
jjonusas Feb 7, 2020
7ba60bf
add: implemented BronKerbosch with pivoting
jjonusas Mar 3, 2020
0d732c8
add: BronKerboch now uses a pivot
jjonusas Mar 19, 2020
bbb70b2
add: only use the symmetric part of the graph in the search cliques
jjonusas Mar 19, 2020
110cc14
add: implemented the use of the addional parameters -- limit, max, size.
jjonusas Mar 25, 2020
b4776b2
add: using the automorphism group in the computation
jjonusas Apr 3, 2020
0d9135f
add: now uses include parameter correctly
jjonusas Apr 6, 2020
59f33fd
add: first draft
jjonusas Apr 22, 2020
12de3df
doc: added descriptions of the arguments of the main function
jjonusas Apr 23, 2020
2fd6fa1
add: fixed small bug and now discard gens which act on the isolated
jjonusas Apr 29, 2020
f154029
add: CliqueFinder uses C code when possible
jjonusas May 4, 2020
ff2a268
add: implemented suggested technical changes
jjonusas May 13, 2020
18f4ded
Merge branch 'c-cliques' of github.com:jjonusas/Digraphs into c-cliques
jjonusas May 13, 2020
7da9791
fix: fixed an issue with limit not being used correctly
jjonusas May 26, 2020
2f76d12
formating/linting
jjonusas May 26, 2020
39a028b
more formatting
jjonusas May 26, 2020
94c2dbd
add: improved code coverage for DigraphsCliqueFinder
jjonusas May 26, 2020
3547812
Even more linting and code coverage
jjonusas May 27, 2020
a84a30b
Merge branch 'master' into c-cliques
james-d-mitchell Jun 27, 2020
53161ba
Merge branch 'master' into c-cliques
james-d-mitchell Aug 14, 2020
4f73cb9
fix memory leaks and assertion failure
MT-resource-bot Aug 19, 2020
27f5c08
Merge branch 'master' into c-cliques
flsmith Sep 16, 2020
007f384
Merge branch 'master' into c-cliques
flsmith Sep 17, 2020
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
2 changes: 2 additions & 0 deletions Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ pkginclude_HEADERS += src/digraphs-debug.h
pkginclude_HEADERS += src/digraphs.h
pkginclude_HEADERS += src/homos-graphs.h
pkginclude_HEADERS += src/homos.h
pkginclude_HEADERS += src/cliques.h
pkginclude_HEADERS += src/perms.h
pkginclude_HEADERS += src/planar.h
pkginclude_HEADERS += src/schreier-sims.h
Expand All @@ -50,6 +51,7 @@ digraphs_la_SOURCES = src/digraphs.c
digraphs_la_SOURCES += src/bitarray.c
digraphs_la_SOURCES += src/conditions.c
digraphs_la_SOURCES += src/homos.c
digraphs_la_SOURCES += src/cliques.c
digraphs_la_SOURCES += src/homos-graphs.c
digraphs_la_SOURCES += src/perms.c
digraphs_la_SOURCES += src/planar.c
Expand Down
173 changes: 148 additions & 25 deletions gap/cliques.gi
Original file line number Diff line number Diff line change
Expand Up @@ -541,12 +541,16 @@ function(arg)
return CliquesFinder(D, fail, [], limit, include, exclude, true, size, false);
end);

# A wrapper for DigraphsCliquesFinder
# This is very hacky at the moment, so we could test C code with GAP tests
InstallGlobalFunction(CliquesFinder,
function(D, hook, user_param, limit, include, exclude, max, size, reps)
local n, sub, group, invariant_include, invariant_exclude, include_variant,
exclude_variant, x, v, o, i, out;
function(digraph, hook, user_param, limit, include, exclude, max, size, reps)
local n, subgraph, group, vertices, include_variant, exclude_variant,
invariant_include, include_invariant, invariant_exclude,
exclude_invariant, x, v, o, i, out, found_orbits, num_found,
hook_wrapper;

if not IsDigraph(D) then
if not IsDigraph(digraph) then
ErrorNoReturn("the 1st argument <D> must be a digraph,");
fi;

Expand All @@ -565,7 +569,7 @@ function(D, hook, user_param, limit, include, exclude, max, size, reps)
"a positive integer,");
fi;

n := DigraphNrVertices(D);
n := DigraphNrVertices(digraph);
if not (IsHomogeneousList(include)
and ForAll(include, x -> IsPosInt(x) and x <= n)
and IsDuplicateFreeList(include))
Expand All @@ -591,29 +595,35 @@ function(D, hook, user_param, limit, include, exclude, max, size, reps)
ErrorNoReturn("the 9th argument <reps> must be true or false,");
fi;

# Investigate whether <include> and <exclude> are invariant under <grp>
sub := DigraphMutableCopyIfMutable(D);
sub := MaximalSymmetricSubdigraphWithoutLoops(sub);
group := AutomorphismGroup(sub);
subgraph := DigraphMutableCopyIfMutable(digraph);
subgraph := MaximalSymmetricSubdigraphWithoutLoops(subgraph);
group := AutomorphismGroup(subgraph);

# Investigate whether <include> and <exclude> are invariant under <group>
vertices := DigraphVertices(digraph);
include_variant := BlistList(vertices, []);
exclude_variant := BlistList(vertices, []);
invariant_include := true;
include_invariant := include;
invariant_exclude := true;
include_variant := [];
exclude_variant := [];
exclude_invariant := exclude;

if not IsTrivial(group)
and (not IsEmpty(include) or not IsEmpty(exclude)) then
if not ForAll(GeneratorsOfGroup(group),
x -> IsSubset(include, OnTuples(include, x))) then
invariant_include := false;
include_invariant := [];
if not reps then
x := ShallowCopy(include);
while not IsEmpty(x) do
v := x[1];
o := List(Orbit(group, v));
i := Intersection(x, o);
if not IsSubset(x, o) then
Append(include_variant, i);
UniteBlist(include_variant, BlistList(vertices, i));
else
Append(include_invariant, i);
fi;
x := Difference(x, i);
od;
Expand All @@ -622,14 +632,17 @@ function(D, hook, user_param, limit, include, exclude, max, size, reps)
if not ForAll(GeneratorsOfGroup(group),
x -> IsSubset(exclude, OnTuples(exclude, x))) then
invariant_exclude := false;
exclude_invariant := [];
if not reps then
x := ShallowCopy(exclude);
while not IsEmpty(x) do
v := x[1];
o := List(Orbit(group, v));
i := Intersection(x, o);
if not IsSubset(x, o) then
Append(exclude_variant, i);
UniteBlist(exclude_variant, BlistList(vertices, i));
else
Append(exclude_invariant, i);
fi;
x := Difference(x, i);
od;
Expand All @@ -644,18 +657,128 @@ function(D, hook, user_param, limit, include, exclude, max, size, reps)
fi;
fi;

out := DIGRAPHS_BronKerbosch(D,
hook,
user_param,
limit,
include,
exclude,
max,
size,
reps,
include_variant,
exclude_variant);
return MakeImmutable(out);
if DigraphNrVertices(digraph) < 512 then
if reps then

if hook = fail then
hook_wrapper := fail;
else
hook_wrapper := function(usr_param, clique)
hook(usr_param, clique);
return 1;
end;
fi;

out := DigraphsCliquesFinder(subgraph,
hook_wrapper,
user_param,
limit,
include,
exclude,
max,
size);
return MakeImmutable(out);
else

# Function to find the valid cliques of an orbit given an orbit rep
found_orbits := [];
num_found := 0;
if hook = fail then
hook := Add;
fi;

hook_wrapper := function(usr_param, clique)
local orbit, n, new_found, i;

new_found := 0;
if not ForAny(found_orbits, x -> clique in x) then
orbit := Orb(group, clique, OnSets);
Enumerate(orbit);
Add(found_orbits, orbit);
n := Length(orbit);

if invariant_include and invariant_exclude then
# we're not just looking for orbit reps, but inc and exc are
# invariant so there is nothing extra to check
new_found := Minimum(limit - num_found, n);
for clique in orbit{[1 .. new_found]} do
hook(usr_param, clique);
od;
num_found := num_found + new_found;
return new_found;
fi;

if invariant_include then
# Cliques in the orbit might contain forbidden vertices
i := 0;
while i < n and num_found < limit do
i := i + 1;
clique := BlistList(vertices, orbit[i]);
if SizeBlist(IntersectionBlist(exclude_variant, clique)) = 0 then
hook(usr_param, orbit[i]);
num_found := num_found + 1;
new_found := new_found + 1;
fi;
od;
elif invariant_exclude then
# Cliques in the orbit might not contain all required vertices
i := 0;
while i < n and num_found < limit do
i := i + 1;
clique := BlistList(vertices, orbit[i]);
if IsSubsetBlist(clique, include_variant) then
hook(usr_param, orbit[i]);
num_found := num_found + 1;
new_found := new_found + 1;
fi;
od;
else
# Cliques in the orbit might contain forbidden vertices and
# might not contain all required vertices
i := 0;
while i < n and num_found < limit do
i := i + 1;
clique := BlistList(vertices, orbit[i]);
if SizeBlist(IntersectionBlist(exclude_variant, clique)) = 0
and IsSubsetBlist(clique, include_variant) then
hook(usr_param, orbit[i]);
num_found := num_found + 1;
new_found := new_found + 1;
fi;
od;
fi;
fi;
return new_found;
end;

DigraphsCliquesFinder(subgraph,
hook_wrapper,
user_param,
limit,
include_invariant,
exclude_invariant,
max,
size);

return MakeImmutable(user_param);
fi;
else
include_variant := ListBlist(vertices, include_variant);
exclude_variant := ListBlist(vertices, exclude_variant);

out := DIGRAPHS_BronKerbosch(digraph,
hook,
user_param,
limit,
include,
exclude,
max,
size,
reps,
include_variant,
exclude_variant);
return MakeImmutable(out);
fi;
end);

InstallGlobalFunction(DIGRAPHS_BronKerbosch,
Expand Down
17 changes: 17 additions & 0 deletions src/bitarray.h
Original file line number Diff line number Diff line change
Expand Up @@ -339,6 +339,23 @@ static inline void intersect_bit_arrays(BitArray* const bit_array1,
}
}

//! Union the BitArray's pointed to by \p bit_array1 and \p bit_array2. The
//! BitArray pointed to by \p bit_array1 is changed in place!
static inline void union_bit_arrays(BitArray* const bit_array1,
BitArray const* const bit_array2,
uint16_t const nr_bits) {
DIGRAPHS_ASSERT(bit_array1 != NULL);
DIGRAPHS_ASSERT(bit_array2 != NULL);
DIGRAPHS_ASSERT(bit_array1->nr_bits == bit_array2->nr_bits);
DIGRAPHS_ASSERT(bit_array1->nr_blocks == bit_array2->nr_blocks);
DIGRAPHS_ASSERT(nr_bits <= bit_array1->nr_bits);
DIGRAPHS_ASSERT(nr_bits <= bit_array2->nr_bits);
uint16_t const nr_blocks = NR_BLOCKS_LOOKUP[nr_bits];
for (uint16_t i = 0; i < nr_blocks; i++) {
bit_array1->blocks[i] |= bit_array2->blocks[i];
}
}

//! Sets \p bit_array1 to be 0 in every position that \p bit_array2 is 1.
static inline void complement_bit_arrays(BitArray* const bit_array1,
BitArray const* const bit_array2,
Expand Down
Loading