diff --git a/src/types.jl b/src/types.jl index 8f8afbde..0e1eb123 100644 --- a/src/types.jl +++ b/src/types.jl @@ -303,6 +303,7 @@ Base.nameof(s::BasicSymbolic) = issym(s) ? s.name : error("None Sym BasicSymboli ## This is much faster than hash of an array of Any hashvec(xs, z) = foldr(hash, xs, init=z) +hashvec2(xs, z) = foldr(hash2, xs, init=z) const SYM_SALT = 0x4de7d7c66d41da43 % UInt const ADD_SALT = 0xaddaddaddaddadda % UInt const SUB_SALT = 0xaaaaaaaaaaaaaaaa % UInt @@ -350,9 +351,33 @@ includes the metadata and symtype in the hash calculation. This can be beneficia consing, allowing for more effective deduplication of symbolically equivalent expressions with different metadata or symtypes. """ +hash2(s, salt::UInt) = hash(s, salt) hash2(s::BasicSymbolic) = hash2(s, zero(UInt)) function hash2(s::BasicSymbolic{T}, salt::UInt)::UInt where {T} - hash(metadata(s), hash(T, hash(s, salt))) + E = exprtype(s) + h::UInt = 0 + if E === SYM + h = hash(nameof(s), salt ⊻ SYM_SALT) + elseif E === ADD || E === MUL + hashoffset = isadd(s) ? ADD_SALT : SUB_SALT + hv = Base.hasha_seed + for (k, v) in s.dict + hv ⊻= hash2(k, hash(v)) + end + h = hash(hv, salt) + h = hash(hashoffset, hash(s.coeff, h)) + elseif E === DIV + h = hash2(s.num, hash2(s.den, salt ⊻ DIV_SALT)) + elseif E === POW + h = hash2(s.exp, hash2(s.base, salt ⊻ POW_SALT)) + elseif E === TERM + op = operation(s) + oph = op isa Function ? nameof(op) : op + h = hashvec2(arguments(s), hash(oph, salt)) + else + error_on_type() + end + hash(metadata(s), hash(T, h)) end ###