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

Fix hashing of permutation group elements #31236

Open
videlec opened this issue Jan 14, 2021 · 52 comments
Open

Fix hashing of permutation group elements #31236

videlec opened this issue Jan 14, 2021 · 52 comments

Comments

@videlec
Copy link
Contributor

videlec commented Jan 14, 2021

As noticed on this sage-devel thread the hash function of PermutationGroupElement does not behave coherently with respect to the natural inclusions SymmetricGroup(n) c SymmetricGroup(n+1).

We design a hash function:

  • whose value on the identity is 1
  • which does only depend on the support (ie ignores fixed points so that the hash is consistent with permutation restriction)
  • which is independent of the domain ordering

Component: group theory

Author: Vincent Delecroix

Branch/Commit: u/vdelecroix/31236 @ e2e4d1d

Reviewer: Dima Pasechnik, ​David Roe

Issue created by migration from https://trac.sagemath.org/ticket/31236

@videlec videlec added this to the sage-9.3 milestone Jan 14, 2021
@videlec

This comment has been minimized.

@dimpase
Copy link
Member

dimpase commented Jan 14, 2021

comment:2

GAP has a function LargestMovedPoint() for permutations, so instead of using self.n, where n is the degree of the permutation group, one can use this value to iterate over while computing the hash.

While this does not ignore all the fixed points, this is still OK in terms of the consistency.

@videlec
Copy link
Contributor Author

videlec commented Jan 14, 2021

Branch: u/vdelecroix/31236

@videlec
Copy link
Contributor Author

videlec commented Jan 14, 2021

Commit: 462fdb1

@videlec
Copy link
Contributor Author

videlec commented Jan 14, 2021

New commits:

462fdb131236: fix hash function of permutations

@dimpase
Copy link
Member

dimpase commented Jan 14, 2021

comment:5

What is 145623773L doing there?

Are you replacing something which looks to me as a perfect hash function (i.e. no collisions) with something that might have collisions?

@videlec
Copy link
Contributor Author

videlec commented Jan 14, 2021

comment:6

If you find a collision, I pay you a beer.

@dimpase
Copy link
Member

dimpase commented Jan 14, 2021

comment:7

I asked a theory question.

@videlec
Copy link
Contributor Author

videlec commented Jan 14, 2021

comment:8

145623773L is an offset to ensure bit shuffling. See https://en.wikipedia.org/wiki/Fowler%E2%80%93Noll%E2%80%93Vo_hash_function (though I might not have used the best constants).

@dimpase
Copy link
Member

dimpase commented Jan 14, 2021

comment:9

thanks. please add this info in the docs.

@sagetrac-git
Copy link
Mannequin

sagetrac-git mannequin commented Jan 14, 2021

Changed commit from 462fdb1 to ba9d62d

@sagetrac-git
Copy link
Mannequin

sagetrac-git mannequin commented Jan 14, 2021

Branch pushed to git repo; I updated commit sha1. New commits:

ba9d62d31326: reference for algorithm

@videlec
Copy link
Contributor Author

videlec commented Jan 14, 2021

comment:11

done

@dimpase
Copy link
Member

dimpase commented Jan 16, 2021

comment:12

OK, looks good, thanks.

@dimpase
Copy link
Member

dimpase commented Jan 16, 2021

Reviewer: Dima Pasechnik

@videlec
Copy link
Contributor Author

videlec commented Jan 17, 2021

comment:13
sage: S1 = SymmetricGroup(FiniteEnumeratedSet([1,2,3]))
sage: S2 = SymmetricGroup(FiniteEnumeratedSet([2,1,3]))
sage: S1("(1,3,2)") == S2("(1,3,2)")
True
sage: hash(S1("(1,3,2)")) == hash(S2("(1,3,2)"))
False

@sagetrac-git
Copy link
Mannequin

sagetrac-git mannequin commented Jan 17, 2021

Changed commit from ba9d62d to 3e29948

@sagetrac-git
Copy link
Mannequin

sagetrac-git mannequin commented Jan 17, 2021

Branch pushed to git repo; I updated commit sha1. New commits:

3e2994831326: change algorithm for consistency

@videlec
Copy link
Contributor Author

videlec commented Jan 17, 2021

comment:15

Consistent hashing with more tests.

@sagetrac-git
Copy link
Mannequin

sagetrac-git mannequin commented Jan 20, 2021

Branch pushed to git repo; I updated commit sha1. New commits:

e2e4d1d31236: use a hash array for non standard domains

@sagetrac-git
Copy link
Mannequin

sagetrac-git mannequin commented Jan 20, 2021

Changed commit from 3e29948 to e2e4d1d

@videlec
Copy link
Contributor Author

videlec commented Jan 20, 2021

comment:36

Better now

sage: S = SymmetricGroup(['a','b','c','d','e','f','g','h','i'])
sage: %timeit -r5 for s in S: h = hash(s)
159 ms ± 1.17 ms per loop (mean ± std. dev. of 5 runs, 10 loops each)

Computing a single hash of an element triggers the creation of an array in the parent

sage: S._domain_hash_array
array('l', [-5034579376873000338, 5819885834672024805, -1342306816048582247, 4154873981948319473, -9080196639829811986, 3487762170233258304, -4059262801740968994, -1410151844174446032, -7454342532774124322])

This solution is not ideal as the hash array could be made available on the domain itself and not on the symmetric group. It could end up with many duplications of this array (ie when constructing subgroups).

@videlec
Copy link
Contributor Author

videlec commented Jan 20, 2021

comment:37

See #31269

@videlec
Copy link
Contributor Author

videlec commented Jan 29, 2021

comment:38

ping

@roed314
Copy link
Contributor

roed314 commented Feb 8, 2021

comment:39

I'm happy giving this ticket positive review. Since Dima originally reviewed it, I'll give him a couple days to respond with an objection and suggestions for how he'd like to proceed.

@videlec
Copy link
Contributor Author

videlec commented Feb 8, 2021

Changed reviewer from Dima Pasechnik to Dima Pasechnik, ​David Roe

@dimpase
Copy link
Member

dimpase commented Feb 8, 2021

comment:41

My objection is only on the level of documentation. Where the hell these huge constants come from, and why? It's totally unclear.

@videlec
Copy link
Contributor Author

videlec commented Feb 8, 2021

comment:42

As their names indicate mult1, mult2 are multipliers (for bit shuffling) and mask1, mask2 are masks so that the hasing of the pair (i, j) is non commutative (ie different from the hash of (j, i)). These numbers are not big, they are 64 bit integers.

@videlec
Copy link
Contributor Author

videlec commented Feb 17, 2021

comment:43

ping

@roed314
Copy link
Contributor

roed314 commented Mar 4, 2021

comment:44

Sorry, I've been busy. This looks good to me.

@vbraun
Copy link
Member

vbraun commented Mar 8, 2021

comment:45

I got this on Ubuntu 18.04 32 bit

**********************************************************************
File "src/sage/groups/perm_gps/permgroup_element.pyx", line 1485, in sage.groups.perm_gps.permgroup_element.PermutationGroupElement.__hash__
Failed example:
    for n in range(1, 10):
       G = SymmetricGroup(n)
       assert hash(G.one()) == 1
       assert len(set(map(hash, G))) == factorial(n)
Exception raised:
    Traceback (most recent call last):
      File "/var/lib/buildbot/slave/sage_git/build/local/lib/python3.9/site-packages/sage/doctest/forker.py", line 714, in _run
        self.compile_and_execute(example, compiler, test.globs)
      File "/var/lib/buildbot/slave/sage_git/build/local/lib/python3.9/site-packages/sage/doctest/forker.py", line 1133, in compile_and_execute
        exec(compiled, globs)
      File "<doctest sage.groups.perm_gps.permgroup_element.PermutationGroupElement.__hash__[3]>", line 4, in <module>
        assert len(set(map(hash, G))) == factorial(n)
    AssertionError
**********************************************************************
File "src/sage/groups/perm_gps/permgroup_element.pyx", line 1493, in sage.groups.perm_gps.permgroup_element.PermutationGroupElement.__hash__
Failed example:
    assert len(set(map(hash, A))) == A.cardinality()
Exception raised:
    Traceback (most recent call last):
      File "/var/lib/buildbot/slave/sage_git/build/local/lib/python3.9/site-packages/sage/doctest/forker.py", line 714, in _run
        self.compile_and_execute(example, compiler, test.globs)
      File "/var/lib/buildbot/slave/sage_git/build/local/lib/python3.9/site-packages/sage/doctest/forker.py", line 1133, in compile_and_execute
        exec(compiled, globs)
      File "<doctest sage.groups.perm_gps.permgroup_element.PermutationGroupElement.__hash__[7]>", line 1, in <module>
        assert len(set(map(hash, A))) == A.cardinality()
    AssertionError
**********************************************************************
1 item had failures:
   2 of  35 in sage.groups.perm_gps.permgroup_element.PermutationGroupElement.__hash__
    [426 tests, 2 failures, 3.64 s]

as a general bit of advice, consider using assert condition, message so you learn whats wrong from tracebacks...

@mkoeppe
Copy link
Member

mkoeppe commented Apr 2, 2021

comment:46

Moving this ticket to 9.4, as it seems unlikely that it will be merged in 9.3, which is in the release candidate stage

@mkoeppe mkoeppe modified the milestones: sage-9.3, sage-9.4 Apr 2, 2021
@mkoeppe
Copy link
Member

mkoeppe commented Jul 19, 2021

comment:47

Setting a new milestone for this ticket based on a cursory review.

@mkoeppe mkoeppe modified the milestones: sage-9.4, sage-9.5 Jul 19, 2021
@mkoeppe mkoeppe modified the milestones: sage-9.5, sage-9.6 Dec 18, 2021
@mkoeppe mkoeppe modified the milestones: sage-9.6, sage-9.7 May 3, 2022
@mkoeppe mkoeppe modified the milestones: sage-9.7, sage-9.8 Sep 19, 2022
@mkoeppe mkoeppe removed this from the sage-9.8 milestone Jan 29, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

5 participants