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 3 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
82 changes: 81 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,80 @@ 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)

#ifndef SYS_IS_64_BIT

static inline uint32_t fmix4(uint32_t h) {
reiniscirpons marked this conversation as resolved.
Show resolved Hide resolved
h ^= h >> 16;
h *= 0x85ebca6b;
h ^= h >> 13;
h *= 0xc2b2ae35;
h ^= h >> 16;

return h;
}

#else

static inline uint64_t fmix8(uint64_t k) {
k ^= k >> 33;
k *= BIG_CONSTANT(0xff51afd7ed558ccd);
k ^= k >> 33;
k *= BIG_CONSTANT(0xc4ceb9fe1a85ec53);
k ^= k >> 33;

return k;
}

#endif

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

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

#ifndef SYS_IS_64_BIT
uint32_t* buf;
buf = safe_calloc(n, sizeof(uint32_t));
#else
uint64_t* buf;
buf = safe_calloc(n, sizeof(uint64_t));
reiniscirpons marked this conversation as resolved.
Show resolved Hide resolved
#endif

for (i = 1; i <= n; i++) {
a = ELM_PLIST(out, i);
PLAIN_LIST(a);
nr = LEN_PLIST(a);
for (j = 1; j <= nr; j++) {
#ifndef SYS_IS_64_BIT
buf[i - 1] += fmix4((uint32_t) INT_INTOBJ(ELM_PLIST(a, j)));
#else
buf[i - 1] += fmix8((uint64_t) INT_INTOBJ(ELM_PLIST(a, j)));
#endif
james-d-mitchell marked this conversation as resolved.
Show resolved Hide resolved
}
}
#ifndef SYS_IS_64_BIT
res = INTOBJ_INT(HASHKEY_MEM_NC(buf, (UInt4) n, n * sizeof(uint32_t)));
#else
res = INTOBJ_INT(HASHKEY_MEM_NC(buf, (UInt4) n, n * sizeof(uint64_t)));
#endif
free(buf);
return res;
}

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 +2273,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