Skip to content

Commit 0f99b3a

Browse files
cliques: some perf improvements
This commit includes some performance improvements for the clique finding code. The example in the newly added extreme/cliques.tst file takes approx. 4s with the modified code, versus at least 3 minutes previously (I never ran it to completion previously because it was taking too long). If we do: List(DigraphCliquesReps(D), x -> Orbit(AutomorphismGroup(D), x, OnSets)); for the same example, then this takes about 12s, doing the same with List(DigraphCliquesReps(D), x -> Orb(AutomorphismGroup(D), x, OnSets)); instead runs out of memory repeatedly (and takes longer than 12s). Note that the automorphism group is of size 16, and so the orbits are relatively small in comparison to the number of cliques.
1 parent f4c601e commit 0f99b3a

File tree

4 files changed

+87
-47
lines changed

4 files changed

+87
-47
lines changed

doc/cliques.xml

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020

2121
A <E>clique</E> of a digraph is a set of mutually adjacent vertices of the
2222
digraph. Loops and multiple edges are ignored for the purpose of
23-
determining the clique number of a digraph.
23+
determining the clique number of a digraph.
2424
<Example><![CDATA[
2525
gap> D := CompleteDigraph(4);;
2626
gap> CliqueNumber(D);
@@ -285,8 +285,8 @@ gap> IsSymmetricDigraph(D);
285285
true
286286
gap> G := AutomorphismGroup(D);
287287
Group([ (5,6), (1,2), (1,5)(2,6)(3,4) ])
288-
gap> DigraphMaximalCliques(D);
289-
[ [ 1, 2, 3 ], [ 4, 5, 6 ], [ 3, 4 ] ]
288+
gap> AsSet(DigraphMaximalCliques(D));
289+
[ [ 1, 2, 3 ], [ 3, 4 ], [ 4, 5, 6 ] ]
290290
gap> DigraphMaximalCliquesReps(D);
291291
[ [ 1, 2, 3 ], [ 3, 4 ] ]
292292
gap> Orbit(G, [1, 2, 3], OnSets);
@@ -306,8 +306,8 @@ gap> IsSymmetricDigraph(D);
306306
true
307307
gap> G := AutomorphismGroup(D);
308308
Group([ (5,6), (1,2), (1,5)(2,6)(3,4) ])
309-
gap> DigraphMaximalCliques(D);
310-
[ [ 1, 2, 3 ], [ 4, 5, 6 ], [ 3, 4 ] ]]]></Example>
309+
gap> AsSet(DigraphMaximalCliques(D));
310+
[ [ 1, 2, 3 ], [ 3, 4 ], [ 4, 5, 6 ] ]]]></Example>
311311
</Description>
312312
</ManSection>
313313
<#/GAPDoc>

gap/cliques.gi

Lines changed: 31 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,26 @@
1010
#############################################################################
1111
##
1212

13+
BindGlobal("AddOrbitToHashMap",
14+
function(G, set, hashmap)
15+
local gens, o, im, pt, g;
16+
17+
gens := GeneratorsOfGroup(G);
18+
o := [set];
19+
Assert(1, not set in hashmap);
20+
hashmap[set] := true;
21+
for pt in o do
22+
for g in gens do
23+
im := OnSets(pt, g);
24+
if not im in hashmap then
25+
hashmap[im] := true;
26+
Add(o, im);
27+
fi;
28+
od;
29+
od;
30+
return o;
31+
end);
32+
1333
InstallMethod(CliqueNumber, "for a digraph", [IsDigraph],
1434
D -> Maximum(List(DigraphMaximalCliquesReps(D), Length)));
1535

@@ -474,7 +494,7 @@ DigraphMaximalCliques);
474494

475495
InstallGlobalFunction(DigraphMaximalCliques,
476496
function(arg)
477-
local D, include, exclude, limit, size, cliques, sub, G, out, orbits, orb, c;
497+
local D, include, exclude, limit, size, cliques, sub, G, out, orbits, c;
478498

479499
if IsEmpty(arg) then
480500
ErrorNoReturn("there must be at least 1 argument,");
@@ -519,16 +539,13 @@ function(arg)
519539
out := cliques;
520540
else
521541
# Act on the representatives to find all
522-
orbits := [];
523-
out := [];
542+
orbits := HashMap();
524543
for c in cliques do
525-
if not ForAny(orbits, x -> c in x) then
526-
orb := Orb(G, c, OnSets);
527-
Enumerate(orb);
528-
Add(orbits, orb);
529-
Append(out, orb);
544+
if not c in orbits then
545+
AddOrbitToHashMap(G, c, orbits);
530546
fi;
531547
od;
548+
out := Keys(orbits);
532549
fi;
533550
if IsImmutableDigraph(D) then
534551
SetDigraphMaximalCliquesAttr(D, out);
@@ -673,7 +690,7 @@ function(digraph, hook, user_param, limit, include, exclude, max, size, reps)
673690
else
674691

675692
# Function to find the valid cliques of an orbit given an orbit rep
676-
found_orbits := [];
693+
found_orbits := HashMap();
677694
num_found := 0;
678695
if hook = fail then
679696
hook := Add;
@@ -683,10 +700,8 @@ function(digraph, hook, user_param, limit, include, exclude, max, size, reps)
683700
local orbit, n, new_found, i;
684701

685702
new_found := 0;
686-
if not ForAny(found_orbits, x -> clique in x) then
687-
orbit := Orb(group, clique, OnSets);
688-
Enumerate(orbit);
689-
Add(found_orbits, orbit);
703+
if not clique in found_orbits then
704+
orbit := AddOrbitToHashMap(group, clique, found_orbits);
690705
n := Length(orbit);
691706

692707
if invariant_include and invariant_exclude then
@@ -860,7 +875,7 @@ function(D, hook, param, lim, inc, exc, max, size, reps, inc_var, exc_var)
860875
grp := AutomorphismGroup(D);
861876
fi;
862877

863-
found_orbits := [];
878+
found_orbits := HashMap();
864879

865880
# Function to find the valid cliques of an orbit given an orbit rep
866881
add := function(c)
@@ -871,10 +886,8 @@ function(D, hook, param, lim, inc, exc, max, size, reps, inc_var, exc_var)
871886
hook(param, c);
872887
num := num + 1;
873888
return;
874-
elif not ForAny(found_orbits, x -> c in x) then
875-
orb := Orb(grp, c, OnSets);
876-
Enumerate(orb);
877-
Add(found_orbits, orb);
889+
elif not c in found_orbits then
890+
orb := AddOrbitToHashMap(grp, c, found_orbits);
878891
n := Length(orb);
879892

880893
if invariant then # we're not just looking for orbit reps, but inc and

tst/extreme/cliques.tst

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
#############################################################################
2+
##
3+
#W extreme/cliques.tst
4+
#Y Copyright (C) 2024 James D. Mitchell
5+
##
6+
## Licensing information can be found in the README file of this package.
7+
##
8+
#############################################################################
9+
##
10+
gap> START_TEST("Digraphs package: extreme/cliques.tst");
11+
gap> LoadPackage("digraphs", false);;
12+
13+
#
14+
gap> DIGRAPHS_StartTest();
15+
gap> D :=
16+
> DigraphFromGraph6String("hJ\\zz{vJw~jvV^]^mvz\\~N^|{~xt~zJ~|N~~Y~~yf\
17+
> ~~m~~~]~~~HR|nbmm~w^N}~Rmzv{inlnwcezjyBx{F{w}p~~VM]~~zH}T~~mvz~^~Lv~\
18+
> }~~Y~~z^~nNv~n~yf~~n~~???????");
19+
<immutable symmetric digraph with 41 vertices, 1212 edges>
20+
gap> Length(DigraphCliques(D));
21+
1651734
22+
23+
# DIGRAPHS_UnbindVariables
24+
gap> Unbind(D);
25+
26+
#
27+
gap> DIGRAPHS_StopTest();
28+
gap> STOP_TEST("Digraphs package: standard/cliques.tst", 0);

tst/standard/cliques.tst

Lines changed: 23 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -191,15 +191,15 @@ gap> DigraphIndependentSets(gr, [], [], 1, 1);
191191
gap> gr := CompleteDigraph(10);;
192192
gap> DigraphMaximalIndependentSetsRepsAttr(gr);
193193
[ [ 1 ] ]
194-
gap> DigraphMaximalIndependentSetsAttr(gr);
194+
gap> Set(DigraphMaximalIndependentSetsAttr(gr));
195195
[ [ 1 ], [ 2 ], [ 3 ], [ 4 ], [ 5 ], [ 6 ], [ 7 ], [ 8 ], [ 9 ], [ 10 ] ]
196196

197197
# DigraphMaximalIndependentSets and DigraphIndependentSets
198198
gap> gr := ChainDigraph(2);;
199-
gap> DigraphMaximalIndependentSets(gr);
199+
gap> Set(DigraphMaximalIndependentSets(gr));
200200
[ [ 1 ], [ 2 ] ]
201201
gap> gr := CompleteDigraph(2);;
202-
gap> DigraphMaximalIndependentSets(gr);
202+
gap> Set(DigraphMaximalIndependentSets(gr));
203203
[ [ 1 ], [ 2 ] ]
204204
gap> gr := DigraphFromDigraph6String("&FWsK?WSKC?");
205205
<immutable digraph with 7 vertices, 14 edges>
@@ -269,11 +269,11 @@ gap> DigraphMaximalCliquesReps();
269269
Error, there must be at least 1 argument,
270270
gap> DigraphMaximalCliquesReps(gr);
271271
[ [ 1 ] ]
272-
gap> DigraphMaximalCliquesAttr(gr);
272+
gap> Set(DigraphMaximalCliquesAttr(gr));
273273
[ [ 1 ], [ 2 ], [ 3 ], [ 4 ], [ 5 ] ]
274274
gap> DigraphMaximalCliques();
275275
Error, there must be at least 1 argument,
276-
gap> DigraphMaximalCliques(gr);
276+
gap> Set(DigraphMaximalCliques(gr));
277277
[ [ 1 ], [ 2 ], [ 3 ], [ 4 ], [ 5 ] ]
278278
gap> gr := EmptyDigraph(1);;
279279
gap> DigraphMaximalCliques(gr);
@@ -455,18 +455,18 @@ gap> gr := DigraphFromSparse6String(":~?@c__EC?_F");
455455
<immutable symmetric digraph with 100 vertices, 6 edges>
456456
gap> DigraphMaximalCliquesReps(gr);
457457
[ [ 1 ], [ 2, 3, 5 ] ]
458-
gap> DigraphMaximalCliques(gr);
459-
[ [ 1 ], [ 4 ], [ 6 ], [ 7 ], [ 8 ], [ 9 ], [ 10 ], [ 11 ], [ 12 ], [ 13 ],
460-
[ 14 ], [ 15 ], [ 16 ], [ 17 ], [ 18 ], [ 19 ], [ 20 ], [ 21 ], [ 22 ],
461-
[ 23 ], [ 24 ], [ 25 ], [ 26 ], [ 27 ], [ 28 ], [ 29 ], [ 30 ], [ 31 ],
462-
[ 32 ], [ 33 ], [ 34 ], [ 35 ], [ 36 ], [ 37 ], [ 38 ], [ 39 ], [ 40 ],
463-
[ 41 ], [ 42 ], [ 43 ], [ 44 ], [ 45 ], [ 46 ], [ 47 ], [ 48 ], [ 49 ],
464-
[ 50 ], [ 51 ], [ 52 ], [ 53 ], [ 54 ], [ 55 ], [ 56 ], [ 57 ], [ 58 ],
465-
[ 59 ], [ 60 ], [ 61 ], [ 62 ], [ 63 ], [ 64 ], [ 65 ], [ 66 ], [ 67 ],
466-
[ 68 ], [ 69 ], [ 70 ], [ 71 ], [ 72 ], [ 73 ], [ 74 ], [ 75 ], [ 76 ],
467-
[ 77 ], [ 78 ], [ 79 ], [ 80 ], [ 81 ], [ 82 ], [ 83 ], [ 84 ], [ 85 ],
468-
[ 86 ], [ 87 ], [ 88 ], [ 89 ], [ 90 ], [ 91 ], [ 92 ], [ 93 ], [ 94 ],
469-
[ 95 ], [ 96 ], [ 97 ], [ 98 ], [ 99 ], [ 100 ], [ 2, 3, 5 ] ]
458+
gap> Set(DigraphMaximalCliques(gr));
459+
[ [ 1 ], [ 2, 3, 5 ], [ 4 ], [ 6 ], [ 7 ], [ 8 ], [ 9 ], [ 10 ], [ 11 ],
460+
[ 12 ], [ 13 ], [ 14 ], [ 15 ], [ 16 ], [ 17 ], [ 18 ], [ 19 ], [ 20 ],
461+
[ 21 ], [ 22 ], [ 23 ], [ 24 ], [ 25 ], [ 26 ], [ 27 ], [ 28 ], [ 29 ],
462+
[ 30 ], [ 31 ], [ 32 ], [ 33 ], [ 34 ], [ 35 ], [ 36 ], [ 37 ], [ 38 ],
463+
[ 39 ], [ 40 ], [ 41 ], [ 42 ], [ 43 ], [ 44 ], [ 45 ], [ 46 ], [ 47 ],
464+
[ 48 ], [ 49 ], [ 50 ], [ 51 ], [ 52 ], [ 53 ], [ 54 ], [ 55 ], [ 56 ],
465+
[ 57 ], [ 58 ], [ 59 ], [ 60 ], [ 61 ], [ 62 ], [ 63 ], [ 64 ], [ 65 ],
466+
[ 66 ], [ 67 ], [ 68 ], [ 69 ], [ 70 ], [ 71 ], [ 72 ], [ 73 ], [ 74 ],
467+
[ 75 ], [ 76 ], [ 77 ], [ 78 ], [ 79 ], [ 80 ], [ 81 ], [ 82 ], [ 83 ],
468+
[ 84 ], [ 85 ], [ 86 ], [ 87 ], [ 88 ], [ 89 ], [ 90 ], [ 91 ], [ 92 ],
469+
[ 93 ], [ 94 ], [ 95 ], [ 96 ], [ 97 ], [ 98 ], [ 99 ], [ 100 ] ]
470470

471471
# Test CliqueNumber
472472
gap> CliqueNumber(NullDigraph(10));
@@ -497,8 +497,7 @@ gap> cliques := DigraphMaximalCliquesReps(D);
497497
[ [ 1, 2, 3 ], [ 3, 4 ] ]
498498
gap> IsMutable(cliques) or ForAny(cliques, IsMutable);
499499
false
500-
gap> cliques := DigraphMaximalCliques(D);
501-
[ [ 1, 2, 3 ], [ 4, 5, 6 ], [ 3, 4 ] ]
500+
gap> cliques := DigraphMaximalCliques(D);;
502501
gap> IsMutable(cliques) or ForAny(cliques, IsMutable);
503502
false
504503
gap> cliques := DigraphMaximalCliques(D, [1]);
@@ -512,17 +511,17 @@ gap> CliquesFinder(
512511
[ [ 1 ] ]
513512
gap> gr := DigraphSymmetricClosure(ChainDigraph(513));
514513
<immutable symmetric digraph with 513 vertices, 1024 edges>
515-
gap> CliquesFinder(gr, fail, [], 4, [], [], true, fail, false);
514+
gap> CliquesFinder(gr, fail, [], 4, [], [], true, fail, false);
516515
[ [ 1, 2 ], [ 512, 513 ], [ 2, 3 ], [ 511, 512 ] ]
517-
gap> CliquesFinder(gr, fail, [], 4, [1], [], true, fail, false);
516+
gap> CliquesFinder(gr, fail, [], 4, [1], [], true, fail, false);
518517
[ [ 1, 2 ] ]
519-
gap> CliquesFinder(gr, fail, [], 4, [], [1], true, fail, false);
518+
gap> CliquesFinder(gr, fail, [], 4, [], [1], true, fail, false);
520519
[ [ 512, 513 ], [ 2, 3 ], [ 511, 512 ], [ 3, 4 ] ]
521520
gap> CliquesFinder(gr, fail, [], 4, [1], [2], true, fail, false);
522521
[ ]
523522
gap> CliquesFinder(gr, fail, [], 4, [1], [3], true, fail, false);
524523
[ [ 1, 2 ] ]
525-
gap> CliquesFinder(gr, fail, [], 4, [1, 2], [], false, 1, false);
524+
gap> CliquesFinder(gr, fail, [], 4, [1, 2], [], false, 1, false);
526525
[ ]
527526
gap> CliquesFinder(gr, fail, [], 4, [1, 513], [], false, 1, false);
528527
[ ]
@@ -590,7 +589,7 @@ nteger,
590589
gap> DigraphsCliquesFinder(NullDigraph(1), fail, [], 4, [], [], true, fail, 0);
591590
Error, the 9th argument <aut_grp> must be a permutation group or fail, not int\
592591
eger,
593-
gap> DigraphsCliquesFinder(NullDigraph(3), fail, [], 4, [], [], true, fail,
592+
gap> DigraphsCliquesFinder(NullDigraph(3), fail, [], 4, [], [], true, fail,
594593
> Group((1, 2, 3), (1, 2), (1, 3)));
595594
Error, expected at most 2 generators in the 9th argument but got 3,
596595
gap> DigraphsCliquesFinder(NullDigraph(2), fail, [], 4, [], [], true, fail, SymmetricGroup(3));

0 commit comments

Comments
 (0)