1
0
mirror of https://github.com/kalmarek/Groups.jl.git synced 2024-12-25 02:05:30 +01:00

new hashing && bitflags

This commit is contained in:
Marek Kaluba 2021-05-07 18:11:11 +02:00
parent 44df0016bc
commit cdd36f680a
No known key found for this signature in database
GPG Key ID: 8BF1A3855328FC15
4 changed files with 57 additions and 37 deletions

View File

@ -23,6 +23,7 @@ include("findreplace.jl")
module New
include("new_types.jl")
include("new_hashing.jl")
include("normalform.jl")
end # module New

49
src/new_hashing.jl Normal file
View File

@ -0,0 +1,49 @@
## 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

View File

@ -132,38 +132,6 @@ function Base.show(io::IO, f::FPGroupElement)
print(io, KnuthBendix.string_repr(word(f), alphabet(f)))
end
## Hashing
# We store hash of a word in field `savedhash` to use it as cheap replacement
# for equality checking. In the last bit of `savehash` we store the information
# whether the word is already reduced (in normal form) or not. Hence
isnormalform(g::FPGroupElement) = Bool(g.savedhash & 1)
# To update hash use this internal method, possibly only after computing the
# normal form of `g`:
_update_savedhash!(g::FPGroupElement, h = hash(word(g))) =
(g.savedhash = h | 1; return g)
# If `g` has been mutated (e.g. `word(g)` has been modified, `_invalidate_hash`
# must be called.
_invalidate_hash!(g::FPGroupElement) = g.savedhash = g.savedhash & 0
# Accessor for the saved hash
@inline _savedhash(f::FPGroupElement) = f.savedhash
function Base.hash(g::FPGroupElement, h::UInt)
normalform!(g)
# compute the best approximation of the normal form
return hash(parent(g), _savedhash(g) h)
end
function Base.copyto!(res::FPGroupElement, g::FPGroupElement)
resize!(word(res), length(word(g)))
copyto!(word(res), word(g))
_invalidate_hash!(res)
return res
end
## GroupElement Interface for FPGroupElement
Base.parent(f::FPGroupElement) = f.parent
@ -171,13 +139,14 @@ GroupsCore.parent_type(::Type{<:FPGroupElement{G}}) where G = G
function Base.:(==)(g::FPGroupElement, h::FPGroupElement)
@boundscheck @assert parent(g) === parent(h)
normalform!(g)
normalform!(h)
hash(g) != hash(h) && return false
# hash reduces to normal form behind the scenes
return word(g) == word(h)
end
function Base.deepcopy_internal(g::FPGroupElement, stackdict::IdDict)
return FPGroupElement(copy(word(g)), _savedhash(g), parent(g))
return FPGroupElement(copy(word(g)), g.savedhash, parent(g))
end
Base.inv(g::FPGroupElement) =

View File

@ -11,7 +11,8 @@ Compute the normal form of `g`, possibly modifying `g` in-place.
copyto!(word(g), w)
end
g = _update_savedhash!(g)
_setnormalform!(g, true)
_setvalidhash!(g, false)
@assert isnormalform(g)
return g
end
@ -24,11 +25,11 @@ function normalform!(res::GEl, g::GEl) where GEl<:FPGroupElement
@boundscheck @assert parent(res) === parent(g)
if isnormalform(g)
copyto!(res, g)
_update_savedhash!(res, g.savedhash)
else
resize!(word(res), 0)
normalform!(word(res), g)
res = _update_savedhash!(res)
_setnormalform!(res, true)
_setvalidhash!(res, false)
end
return res
end