Skip to content

Commit

Permalink
Introduce named graphs architecture (PR #404)
Browse files Browse the repository at this point in the history
* Intermediate progress

* Named Graphs: change tst file copyright date

* Outsource unpickler to DIGRAPHS_LoadNamedGraph6Strings

* I forgot to declare local variables

also added a lowercase bugfix

* Named Digraphs: Implement ListNamedDigraphs as search function

* Named Graphs: lint

* Named Graphs: choose better name for test database

* Named Graphs: add standard test and change error message

* Named Graphs: add placeholder databases

* More standard tests and ListNamed bugfix

* Create final database

* Rename files and variables Graph6 -> DiSparse6 since this is
  @reiniscirpons' format for the sporadic graphs

* Move all new functions to digraph.gi

* Delete tst/standard/named.tst and move tests to digraph.tst

* Remove some DeclareOperation lines

(A string is a list so no need to declare anything new)

* Named Digraphs: add flexibility level to ListNamedDigraphs

* Named Graphs: add test

* Named Digraphs: update error message and improve search speed

* Named Digraphs: documentation

* Apply suggestions from code review

Co-authored-by: Wilf Wilson <wilf@wilf-wilson.net>

* Named Digraphs: store records in uncompressed .g files

Also for naming consistency, change all variables, functions and
filenames to "named digraphs" and "named digraphs tests".

* Named Digraphs: rename graph -> digraph in comments

Co-authored-by: Murray Whyte <mw231@st-andrews.ac.uk>
Co-authored-by: Tom Conti-Leslie <tom.contileslie@gmail.com>
Co-authored-by: Wilf Wilson <wilf@wilf-wilson.net>
Co-authored-by: Tom Conti-Leslie <54725378+tomcontileslie@users.noreply.github.com>
  • Loading branch information
5 people authored Mar 26, 2021
1 parent 85ab060 commit 3026304
Show file tree
Hide file tree
Showing 8 changed files with 5,012 additions and 2 deletions.
527 changes: 527 additions & 0 deletions data/named-digraphs-main-database.g

Large diffs are not rendered by default.

4,177 changes: 4,177 additions & 0 deletions data/named-digraphs-test-database.g

Large diffs are not rendered by default.

47 changes: 46 additions & 1 deletion doc/digraph.xml
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,23 @@
and range <C>j</C> if and only if <C>[i,j]</C> is a pair in
the binary relation <A>obj</A>.
</Item>

<Mark>for a string naming a digraph</Mark>
<Item>
if <A>obj</A> is a non-empty string, then this function returns the
digraph that has name <A>obj</A>. &Digraphs; comes with a database
containing a few hundred common digraph names that can be loaded in this
way. Valid names include <C>"folkman"</C>, <C>"diamond"</C> and
<C>"brinkmann"</C>. If the name is commonly followed by the word
<C>"graph"</C>, then it is called without writing <C>"graph"</C> at the
end. You can explore the available graph names using
<Ref Oper="ListNamedDigraphs"/>. Digraph names are case and whitespace
insensitive. <P/>

Note that any undirected graphs in the database are stored as symmetric
digraphs, so the resulting digraph will have twice as many edges as its
undirected counterpart.
</Item>
</List>

<Example><![CDATA[
Expand All @@ -228,7 +245,9 @@ gap> Petersen := Graph(SymmetricGroup(5), [[1, 2]], OnSets,
gap> Digraph(Petersen);
<immutable digraph with 10 vertices, 30 edges>
gap> gr := Digraph([1 .. 10], ReturnTrue);
<immutable digraph with 10 vertices, 100 edges>]]></Example>
<immutable digraph with 10 vertices, 100 edges>
gap> Digraph("Diamond");
<immutable digraph with 4 vertices, 10 edges>]]></Example>

The next example illustrates the uses of the fourth and fifth variants of
this constructor. The resulting digraph is a strongly regular graph, and
Expand Down Expand Up @@ -396,6 +415,32 @@ gap> D := DigraphByInNeighbours(IsMutableDigraph,
</ManSection>
<#/GAPDoc>

<#GAPDoc Label="ListNamedDigraphs">
<ManSection>
<Oper Name="ListNamedDigraphs" Arg="s[, level]"/>
<Returns>A list of strings representing digraph names.</Returns>
<Description>
This function searches through the list of names that are
currently in the &Digraphs; database of named digraphs. The first argument
<A>s</A> should be a partially completed string; this function returns all
completions <C>str</C> of the string <A>s</A> such that <C>Digraph(str)</C>
will successfully return a digraph. <P/>

The optional second argument <A>level</A> controls the flexibility of the
search. If <C><A>level</A> = 1</C>, then only strings beginning exactly with
<A>s</A> are returned. If <C><A>level</A> = 2</C>, then all names containing
<A>s</A> as a substring are returned. If <C><A>level</A> = 3</C>, then
once again a substring search is carried out, but
characters that are not alphanumeric are ignored in the search. <P/>

If <A>level</A> is not specified, it is set by default to equal 2. <P/>

The search is always case and whitespace insensitive, and this is also the
case when applying <Ref Oper="Digraph"/> to a string.
</Description>
</ManSection>
<#/GAPDoc>

<#GAPDoc Label="AsDigraph">
<ManSection>
<Oper Name="AsDigraph" Arg="[filt, ]trans[, n]"/>
Expand Down
1 change: 1 addition & 0 deletions doc/z-chap2.xml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
<#Include Label="EdgeOrbitsDigraph">
<#Include Label="DigraphByInNeighbours">
<#Include Label="CayleyDigraph">
<#Include Label="ListNamedDigraphs">
</Section>

<Section><Heading>Changing representations</Heading>
Expand Down
3 changes: 3 additions & 0 deletions gap/digraph.gd
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,9 @@ DeclareOperation("Digraph", [IsList, IsFunction]);
DeclareOperation("Digraph", [IsInt, IsList, IsList]);
DeclareOperation("Digraph", [IsList, IsList, IsList]);

DeclareOperation("ListNamedDigraphs", [IsString]);
DeclareOperation("ListNamedDigraphs", [IsString, IsPosInt]);

# 8. Digraph by-something constructors . . .
DeclareConstructor("DigraphByAdjacencyMatrixCons",
[IsDigraph, IsHomogeneousList]);
Expand Down
98 changes: 97 additions & 1 deletion gap/digraph.gi
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#############################################################################
##
## digraph.gi
## Copyright (C) 2014-19 James D. Mitchell
## Copyright (C) 2014-21 James D. Mitchell
##
## Licensing information can be found in the README file of this package.
##
Expand All @@ -24,6 +24,38 @@
#
########################################################################

BindGlobal("DIGRAPHS_NamedDigraphs", fail);
BindGlobal("DIGRAPHS_NamedDigraphsTests", fail);

BindGlobal("DIGRAPHS_LoadNamedDigraphs", function()
# Check if the database has already been loaded
if DIGRAPHS_NamedDigraphs = fail then
MakeReadWriteGlobal("DIGRAPHS_NamedDigraphs");
UnbindGlobal("DIGRAPHS_NamedDigraphs");

# Initialise empty record
BindGlobal("DIGRAPHS_NamedDigraphs", rec());

# Populate record with entries from the named digraphs main database
Read(Concatenation(DIGRAPHS_Dir(), "/data/named-digraphs-main-database.g"));
fi;
end);

BindGlobal("DIGRAPHS_LoadNamedDigraphsTests", function()
# INTENDED ONLY FOR TESTING PURPOSES
# Check if the database has already been loaded
if DIGRAPHS_NamedDigraphsTests = fail then
MakeReadWriteGlobal("DIGRAPHS_NamedDigraphsTests");
UnbindGlobal("DIGRAPHS_NamedDigraphsTests");

# Initialise empty record
BindGlobal("DIGRAPHS_NamedDigraphsTests", rec());

# Populate record with entries from the named digraphs test database
Read(Concatenation(DIGRAPHS_Dir(), "/data/named-digraphs-test-database.g"));
fi;
end);

InstallMethod(DigraphMutabilityFilter, "for a digraph", [IsDigraph],
function(D)
if IsMutableDigraph(D) then
Expand Down Expand Up @@ -429,6 +461,70 @@ DigraphCons);
InstallMethod(Digraph, "for a list, list, and list", [IsList, IsList, IsList],
{dom, src, ran} -> DigraphCons(IsImmutableDigraph, dom, src, ran));

InstallMethod(Digraph, "for a string naming a digraph", [IsString],
function(name)
# edge case to avoid interfering with Digraph([])
if name = "" then
TryNextMethod();
fi;

# standardise string format to search database
name := LowercaseString(name);
RemoveCharacters(name, " \n\t\r");

# load database if not already done
DIGRAPHS_LoadNamedDigraphs();

if not name in RecNames(DIGRAPHS_NamedDigraphs) then
ErrorNoReturn("named digraph <name> not found; see ListNamedDigraphs,");
fi;
return DigraphFromDiSparse6String(DIGRAPHS_NamedDigraphs.(name));
end);

InstallMethod(ListNamedDigraphs,
"for a string and a pos int",
[IsString, IsPosInt],
function(s, level)
local l, cands, func;
# standardise request
s := LowercaseString(s);
RemoveCharacters(s, " \n\t\r");
l := Length(s);

# load database if not already done
DIGRAPHS_LoadNamedDigraphs();

# retrieve candidates
cands := RecNames(DIGRAPHS_NamedDigraphs);
if l = 0 then
return cands;
fi;

# print warning if level higher than ones here that have methods
if level > 3 then
Info(InfoWarning, 1, "ListNamedDigraphs: second argument <level> is");
Info(InfoWarning, 1, "greater than level of greatest flexibility.");
Info(InfoWarning, 1, "Using <level> = 3 instead.");
level := 3;
fi;

if level = 1 then
func := c -> Length(c) >= l and c{[1 .. l]} = s;
elif level = 2 then
func := c -> PositionSublist(c, s) <> fail;
else
s := Filtered(s, x -> IsDigitChar(x) or IsAlphaChar(x));
func := c -> PositionSublist(Filtered(c, x -> IsDigitChar(x) or
IsAlphaChar(x)), s) <> fail;
fi;
return Filtered(cands, func);
end);

# if search function called with no level, assume a substring search with
# special chars
InstallMethod(ListNamedDigraphs, "for a string", [IsString],
x -> ListNamedDigraphs(x, 2));

########################################################################
# 6. Printing, viewing, strings
########################################################################
Expand Down
55 changes: 55 additions & 0 deletions tst/extreme/named.tst
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
#############################################################################
##
#W extreme/named.tst
#Y Copyright (C) 2021 Tom D. Conti-Leslie
##
## Licensing information can be found in the README file of this package.
##
#############################################################################
##
## This tests attributes of all digraphs stored in the named digraphs main
## database against known values. Attributes tested are largely from House
## of Graphs at hog.grinvin.org.
##
gap> START_TEST("Digraphs package: extreme/named.tst");
gap> LoadPackage("digraphs", false);;

#
gap> DIGRAPHS_StartTest();

# Load the record of stored test values
gap> DIGRAPHS_LoadNamedDigraphsTests();
gap> r := DIGRAPHS_NamedDigraphsTests;;

# For each graph, test Digraphs-generated properties against stored values.
# "failed" is a list of pairs [name, prop] where the digraph called "name"
# did not coincide with the test record on property "prop". The test is
# passed if this list remains empty. If it contains digraphs, you should check
# those digraphs for errors.
gap> names := RecNames(r);;
gap> failed := [];;
gap> for name in names do
> D := Digraph(name);;
> properties := r.(name);;
> for prop in RecNames(properties) do
> if ValueGlobal(prop)(D) <> properties.(prop) then
> Add(failed, [name, prop]);;
> fi;
> od;
> od;
gap> failed;
[ ]

# DIGRAPHS_UnbindVariables
gap> Unbind(f);
gap> Unbind(r);
gap> Unbind(names);
gap> Unbind(name);
gap> Unbind(properties);
gap> Unbind(failed);
gap> Unbind(D);
gap> Unbind(prop);

#
gap> DIGRAPHS_StopTest();
gap> STOP_TEST("Digraphs package: extreme/named.tst", 0);
Loading

0 comments on commit 3026304

Please sign in to comment.