#15931: Implement a proper hash function for (combinatorial) free module 
elements
-------------------------------------+-------------------------------------
       Reporter:  nthiery            |        Owner:
           Type:  defect             |       Status:  needs_work
       Priority:  major              |    Milestone:  sage-6.2
      Component:  linear algebra     |   Resolution:
       Keywords:                     |    Merged in:
        Authors:  Nicolas M. Thiéry  |    Reviewers:  Florent Hivert
Report Upstream:  N/A                |  Work issues:
         Branch:                     |       Commit:
  u/nthiery/ticket/15931             |  a2bbe7f297caeb73bda1f8ce31af9ee21b90a26b
   Dependencies:                     |     Stopgaps:
-------------------------------------+-------------------------------------
Changes (by nthiery):

 * cc: tscrim, aschilling, bump (added)
 * status:  positive_review => needs_work


Old description:

> Up to now, CombinatorialFreeModule elements used the (horrible)
> default implementation of __hash__ provided by Element which uses the
> string representation. This was slow! And further fragile! Indeed, the
> string representation depends on a sorting of the support of the
> elements.  In #14102 we got bitten by this with elements whose support
> mixed int's, Integer's and string. The result of:
> {{{
>     sage: sorted([int(0), 'delta', 1])
>     [0, 1, 'delta']
> }}}
> depends on the platform (that's ok) but also on which of 0 and 1 are
> int's or Integer, whereas the corresponding lists test as equal.
> This led to equal element with distinct hash values.
>
> This ticket adds an implementation of `__hash__` inspired from that
> proposed for frozendicts in PEP 0416. In particular this
> implementation does not rely on sorting.
>
> Some timings:
> {{{
>     sage: F = CombinatorialFreeModule(QQ, ['a','b','c'])
>     sage: B = F.basis()
>     sage: f = B['a'] + 3*B['c']
>     sage: %timeit hash(f)                         # new hash function
>     100000 loops, best of 3: 3.57 µs per loop
>     sage: %timeit hash(f._repr_())                # equivalent to the
> previous one
>     10000 loops, best of 3: 85 µs per loop
> }}}
>
> There used to be a custom hash function for ambient space elements in
> root systems, but this is not needed anymore:
> {{{
>     sage: F = RootSystem(['A',2]).ambient_space()
>     sage: f = F.simple_root(0)
>     sage: %timeit hash(f)                         # new hash function
>     100000 loops, best of 3: 3.63 µs per loop
>     sage: %timeit hash(f._repr_())                # equivalent to the
> previous one
>     10000 loops, best of 3: 42.3 µs per loop
> }}}

New description:

 Up to now, CombinatorialFreeModule elements used the (horrible)
 default implementation of __hash__ provided by Element which uses the
 string representation. This was slow! And further fragile! Indeed, the
 string representation depends on a sorting of the support of the
 elements.  In #14102 we got bitten by this with elements whose support
 mixed int's, Integer's and string. The result of:
 {{{
     sage: sorted([int(0), 'delta', 1])
     [0, 1, 'delta']
 }}}
 depends on the platform (that's ok) but also on which of 0 and 1 are
 int's or Integer, whereas the corresponding lists test as equal.
 This led to equal element with distinct hash values.

 This ticket adds an implementation of `__hash__` inspired from that
 proposed for frozendicts in PEP 0416. In particular this
 implementation does not rely on sorting.

 Some timings:
 {{{
     sage: F = CombinatorialFreeModule(QQ, ['a','b','c'])
     sage: B = F.basis()
     sage: f = B['a'] + 3*B['c']
     sage: %timeit hash(f)                         # new hash function
     100000 loops, best of 3: 3.57 µs per loop
     sage: %timeit hash(f._repr_())                # equivalent to the
 previous one
     10000 loops, best of 3: 85 µs per loop
 }}}

 There used to be a custom hash function for ambient space elements in
 root systems, but this is not needed anymore:
 {{{
     sage: F = RootSystem(['A',2]).ambient_space()
     sage: f = F.simple_root(0)
     sage: %timeit hash(f)                         # new hash function
     100000 loops, best of 3: 3.63 µs per loop
     sage: %timeit hash(f._repr_())                # equivalent to the
 previous one
     10000 loops, best of 3: 42.3 µs per loop
 }}}

 See #15959 for a follow up.

--

Comment:

 Changing the hash value of combinatorial free module elements changes the
 order in which they get sorted when printing, e.g., sets. This causes a
 bunch of trivial doctest failures that are not deterministic, in
 particular in crystals and weyl character rings. I am in the process of
 fixing those, trying at this occasion to make the tests more deterministic
 when easy. Further work on making those tests deterministic would be
 desirable in later tickets.

 Also, for now, I removed the hash value of the parent from the hash value
 of the elements. See #15959. Travis: please check it out!

 Cheers,

--
Ticket URL: <http://trac.sagemath.org/ticket/15931#comment:14>
Sage <http://www.sagemath.org>
Sage: Creating a Viable Open Source Alternative to Magma, Maple, Mathematica, 
and MATLAB

-- 
You received this message because you are subscribed to the Google Groups 
"sage-trac" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To post to this group, send email to [email protected].
Visit this group at http://groups.google.com/group/sage-trac.
For more options, visit https://groups.google.com/d/optout.

Reply via email to