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

Add hash function for digraphs #675

Merged
merged 5 commits into from
Aug 28, 2024
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
13 changes: 13 additions & 0 deletions doc/attr.xml
Original file line number Diff line number Diff line change
Expand Up @@ -2548,3 +2548,16 @@ fail
</Description>
</ManSection>
<#/GAPDoc>

<#GAPDoc Label="DigraphHash">
<ManSection>
<Attr Name="DigraphHash" Arg="digraph"/>
<Returns>The hash of a digraph.</Returns>
<Description>
This function returns a hash of <A>digraph</A>. <P/>

Note that the underlying hashing function is system dependent, and so the
value of this attribute is not guaranteed to be the same on different systems.
</Description>
</ManSection>
<#/GAPDoc>
4 changes: 4 additions & 0 deletions doc/z-chap4.xml
Original file line number Diff line number Diff line change
Expand Up @@ -103,4 +103,8 @@
<#Include Label="SubdigraphHomeomorphicToK">
</Section>

<Section><Heading>Hashing</Heading>
<#Include Label="DigraphHash">
</Section>

</Chapter>
1 change: 1 addition & 0 deletions gap/attr.gd
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ DeclareAttribute("DigraphNrVertices", IsDigraph);
DeclareAttribute("DigraphEdges", IsDigraph);
DeclareAttribute("DigraphNrEdges", IsDigraph);
DeclareAttribute("DigraphNrLoops", IsDigraph);
DeclareAttribute("DigraphHash", IsDigraph);

DeclareAttribute("DigraphRange", IsDigraph);
DeclareAttribute("DigraphSource", IsDigraph);
Expand Down
7 changes: 7 additions & 0 deletions gap/attr.gi
Original file line number Diff line number Diff line change
Expand Up @@ -750,6 +750,13 @@ function(D)
return out;
end);

InstallMethod(DigraphHash, "for a digraph", [IsDigraph], DIGRAPH_HASH);

InstallMethod(SparseIntKey, "for an object and digraph",
[IsObject, IsDigraph],
{coll, D} -> DigraphHash
);

# attributes for digraphs . . .

InstallMethod(AsGraph, "for a digraph", [IsDigraph], Graph);
Expand Down
58 changes: 57 additions & 1 deletion src/digraphs.c
Original file line number Diff line number Diff line change
Expand Up @@ -1133,7 +1133,7 @@ static Obj FuncIS_MULTI_DIGRAPH(Obj self, Obj digraph) {
* - If true, for each vertex i, dist[i][i] is initially set to 0
* - If false, this step is skipped
*/
static Obj FLOYD_WARSHALL(Obj digraph,
static Obj FLOYD_WARSHALL(Obj digraph,
void (*func)(Int** dist, Int i, Int j, Int k, Int n),
Int val1,
Int val2,
Expand Down Expand Up @@ -1384,6 +1384,56 @@ static bool EqJumbledPlists(Obj l, Obj r, Int nr, Int* buf) {
return true;
}

//-----------------------------------------------------------------------------
// MurmurHash3 was written by Austin Appleby, and is placed in the public
// domain. The author hereby disclaims copyright to this source code.

/* Minor modifications to get it to compile in C rather than C++ and
integrate with GAP SL*/

/* Digraphs takes parts of this source from GAP. */

#define BIG_CONSTANT(x) (x##LLU)

static inline UInt fmix(UInt h) {
#ifndef SYS_IS_64_BIT
h ^= h >> 16;
h *= 0x85ebca6b;
h ^= h >> 13;
h *= 0xc2b2ae35;
h ^= h >> 16;
#else
h ^= h >> 33;
h *= BIG_CONSTANT(0xff51afd7ed558ccd);
h ^= h >> 33;
h *= BIG_CONSTANT(0xc4ceb9fe1a85ec53);
h ^= h >> 33;
#endif

return h;
}

static Obj FuncDIGRAPH_HASH(Obj self, Obj digraph) {
UInt n, i, h;
Obj out, a;
Int nr, j;

h = 0;
n = DigraphNrVertices(digraph);
out = FuncOutNeighbours(self, digraph);

for (i = 1; i <= n; i++) {
a = ELM_PLIST(out, i);
PLAIN_LIST(a);
nr = LEN_PLIST(a);
for (j = 1; j <= nr; j++)
h += fmix(INT_INTOBJ(ELM_PLIST(a, j)));
h = fmix(h + 0x9e3779b9);
}

return INTOBJ_INT(h);
}

static Obj FuncDIGRAPH_EQUALS(Obj self, Obj digraph1, Obj digraph2) {
UInt i, n1, n2, m1, m2;
Obj out1, out2, a, b;
Expand Down Expand Up @@ -2199,6 +2249,12 @@ static StructGVarFunc GVarFuncs[] = {
FuncRANDOM_MULTI_DIGRAPH,
"src/digraphs.c:FuncRANDOM_MULTI_DIGRAPH"},

{"DIGRAPH_HASH",
1,
"digraph",
FuncDIGRAPH_HASH,
"src/digraphs.c:FuncDIGRAPH_HASH"},

{"DIGRAPH_EQUALS",
2,
"digraph1, digraph2",
Expand Down
16 changes: 16 additions & 0 deletions tst/standard/attr.tst
Original file line number Diff line number Diff line change
Expand Up @@ -2973,6 +2973,22 @@ gap> DigraphHomomorphism(NullDigraph(1), NullDigraph(65555));
Error, the 2nd argument <digraph2> must have at most 65534 vertices, found 655\
55,

# Test Digraph hashing
# This has a small chance to randomly fail. Sorry if it does!
gap> D1 := RandomMultiDigraph(100);;
gap> D2 := Digraph(List(OutNeighbours(D1), x -> Shuffle(ShallowCopy(x))));;
gap> D1 = D2;
true
gap> OutNeighbours(D1) = OutNeighbours(D2);
false
gap> DigraphHash(D1) = DigraphHash(D2);
true
gap> while D1 = D2 do
> D2 := RandomMultiDigraph(100);
> od;;
gap> DigraphHash(D1) = DigraphHash(D2);
false

# Unbind local variables, auto-generated by etc/tst-unbind-local-vars.py
gap> Unbind(A);
gap> Unbind(B);
Expand Down
Loading