mirror of
https://github.com/kalmarek/Groups.jl.git
synced 2024-11-19 06:30:29 +01:00
new hashing && bitflags
This commit is contained in:
parent
44df0016bc
commit
cdd36f680a
@ -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
49
src/new_hashing.jl
Normal 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
|
@ -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) =
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user