Opened 6 years ago

Last modified 3 years ago

#14608 new defect

Symbolic functions break the __hash__ contract

Reported by: vbraun Owned by: burcin
Priority: major Milestone: sage-6.4
Component: symbolics Keywords:
Cc: Merged in:
Authors: Reviewers:
Report Upstream: N/A Work issues:
Branch: Commit:
Dependencies: Stopgaps:


Equal objects must have the same hash if they are hashable (

sage: my_func = function('func',nargs=1)
sage: f = my_func(0)
sage: bool(f == f.simplify())
sage: hash(f) == hash(f.simplify())

As reported on, hash lookup errors then leads to undesirable behavior:

sage: ex = my_func(0) + my_func(1)
sage: ex.subs(my_func(0)==1)
func(1) + 1
sage: ex.simplify().subs(my_func(0)==1)
func(0) + func(1)

Change History (9)

comment:1 follow-up: Changed 6 years ago by vdelecroix

Within Sage it is impossible to satisfy "equal objects must have the same hash if they are hashable" because equality is too laxist.

sage: RIF(2) == 2
sage: hash(RIF(2))
sage: hash(2)


sage: bool(pi == RR(pi))
sage: hash(pi)
sage: hash(RR(pi))

You can not hope to solve this problem with one ticket (because the Symbolic ring contains all Sage objects) !

comment:2 in reply to: ↑ 1 Changed 6 years ago by vdelecroix

comment:3 Changed 6 years ago by ncohen

(cc me)

comment:4 Changed 6 years ago by jdemeyer

  • Milestone changed from sage-5.11 to sage-5.12

comment:5 Changed 5 years ago by vbraun_spam

  • Milestone changed from sage-6.1 to sage-6.2

comment:6 Changed 5 years ago by vbraun_spam

  • Milestone changed from sage-6.2 to sage-6.3

comment:7 Changed 5 years ago by vbraun_spam

  • Milestone changed from sage-6.3 to sage-6.4

comment:8 Changed 3 years ago by rws

See also #18092.

The problem with simplify+substitute is probably another symptom of NewSymbolicFunctions not being preserved when going through Maxima and, if so, is restricted to user-defined functions. See e.g.

sage: ex = sin(x)+exp(pi)
sage: ex.subs(sin(x)==1)
e^pi + 1
sage: ex.simplify().subs(sin(x)==1)
e^pi + 1

comment:9 Changed 3 years ago by nbruin

Now that we've decided to sacrifice readability for reducing the chance of name collisions with variables in conversion from SR to maxima:

sage: x._maxima_()

we could ensure that name translation for functions from SR to maxima is injective as well. Theoretically, we could have

sage: function('f')._maxima_()
sage: function('f',nargs=1)._maxima_()

or something similar. Since LISP uses interned strings for symbols, it wouldn't even be inefficient in the "enhanced" interface to maxima_lib: once the dictionaries are seeded, the strings wouldn't be parsed. The strings-based interface would of course have a bit of a penalty, because it does all kind of regex stuff, so string length actually affects performance (but you'd probably have to work very hard to notice it)

Note that this issue came up again on ask sagemath.

Last edited 3 years ago by nbruin (previous) (diff)
Note: See TracTickets for help on using tickets.