1
0
mirror of https://github.com/kalmarek/Groups.jl.git synced 2024-07-12 01:35:30 +02:00
Groups.jl/src/new_hashing.jl

50 lines
1.7 KiB
Julia
Raw Normal View History

2021-05-07 18:11:11 +02:00
## Hashing
_hashing_data(g::FPGroupElement) = word(g)
bitget(h::UInt, n::Int) = Bool((h & (1 << n)) >> n)
bitclear(h::UInt, n::Int) = h & ~(1 << n)
bitset(h::UInt, n::Int) = h | (1 << n)
bitset(h::UInt, v::Bool, n::Int) = v ? bitset(h, n) : bitclear(h, n)
# We store hash of a word in field `savedhash` to use it as cheap proxy to
# determine non-equal words. Additionally bits of `savehash` store boolean
# information as follows
# * `savedhash & 1` (the first bit): is word in normal form?
# * `savedhash & 2` (the second bit): is the hash valid?
const __BITFLAGS_MASK = ~(~(UInt(0)) << 2)
isnormalform(g::FPGroupElement) = bitget(g.savedhash, 0)
_isvalidhash(g::FPGroupElement) = bitget(g.savedhash, 1)
_setnormalform(h::UInt, v::Bool) = bitset(h, v, 0)
_setvalidhash(h::UInt, v::Bool) = bitset(h, v, 1)
_setnormalform!(g::FPGroupElement, v::Bool) =
g.savedhash = _setnormalform(g.savedhash, v)
_setvalidhash!(g::FPGroupElement, v::Bool) =
g.savedhash = _setvalidhash(g.savedhash, v)
# To update hash use this internal method, possibly only after computing the
# normal form of `g`:
function _update_savedhash!(g::FPGroupElement, data=_hashing_data(g))
h = hash(data, hash(parent(g)))
h = (h << count_ones(__BITFLAGS_MASK)) | (__BITFLAGS_MASK & g.savedhash)
g.savedhash = _setvalidhash(h, true)
return g
end
function Base.hash(g::FPGroupElement, h::UInt)
normalform!(g)
_isvalidhash(g) || _update_savedhash!(g)
return hash(g.savedhash >> count_ones(__BITFLAGS_MASK) , h)
end
function Base.copyto!(res::FPGroupElement, g::FPGroupElement)
@assert parent(res) === parent(g)
resize!(word(res), length(word(g)))
copyto!(word(res), word(g))
res.savedhash = g.savedhash
return res
end