Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
97 changes: 68 additions & 29 deletions src/Perms/perm_images.jl
Original file line number Diff line number Diff line change
Expand Up @@ -41,41 +41,80 @@ AP.inttype(::Type{Perm{T}}) where {T} = T
AP.inttype(::Type{Perm}) = UInt16
AP.__unsafe_image(n::Integer, σ::Perm) = oftype(n, @inbounds σ.images[n])

function Base.copy(p::Perm)
imgs = copy(p.images)
q = typeof(p)(imgs; check = false)
if isdefined(p, :inv, :acquire)
inv_imgs = copy(p.inv.images)
q⁻¹ = typeof(p)(inv_imgs; check = false)
@atomic :release q⁻¹.inv = q
@atomiconce :release :acquire q.inv = q⁻¹
@static if VERSION < v"1.11"
function Base.copy(p::Perm)
imgs = copy(p.images)
q = typeof(p)(imgs; check = false)
if isdefined(p, :inv, :sequentially_consistent)
inv_imgs = copy(@atomic(p.inv).images)
q⁻¹ = typeof(p)(inv_imgs; check = false)
@atomic q.inv = q⁻¹
@atomic q⁻¹.inv = q
end
return q
end
return q
end

function Base.inv(σ::Perm)
if !isdefined(σ, :inv, :acquire)
if isone(σ)
@atomiconce :release :acquire σ.inv = σ
else
σ⁻¹ = typeof(σ)(invperm(σ.images); check = false)
# this order is important:
# fuly initialize the "local" inverse first and only then
# update σ to make the local inverse visible globally
@atomic :release σ⁻¹.inv = σ
@atomiconce :release :acquire σ.inv = σ⁻¹
function Base.inv(σ::Perm)
if !isdefined(σ, :inv, :sequentially_consistent)
if isone(σ)
@atomic σ.inv = σ
else
σ⁻¹ = typeof(σ)(invperm(σ.images); check = false)
# we don't want to end up with two copies of inverse σ floating around
if !isdefined(σ, :inv, :sequentially_consistent)
@atomic σ.inv = σ⁻¹
@atomic σ⁻¹.inv = σ
end
end
end
return σ.inv
end

function AP.cycles(σ::Perm)
if !isdefined(σ, :cycles, :sequentially_consistent)
cdec = AP.CycleDecomposition(σ)
# we can afford producing more than one cycle decomposition
@atomic σ.cycles = cdec
end
return σ.cycles
end
else
function Base.copy(p::Perm)
imgs = copy(p.images)
q = typeof(p)(imgs; check = false)
if isdefined(p, :inv, :acquire)
inv_imgs = copy(p.inv.images)
q⁻¹ = typeof(p)(inv_imgs; check = false)
@atomic :release q⁻¹.inv = q
@atomiconce :release :acquire q.inv = q⁻¹
end
return q
end

function Base.inv(σ::Perm)
if !isdefined(σ, :inv, :acquire)
if isone(σ)
@atomiconce :release :acquire σ.inv = σ
else
σ⁻¹ = typeof(σ)(invperm(σ.images); check = false)
# this order is important:
# fuly initialize the "local" inverse first and only then
# update σ to make the local inverse visible globally
@atomic :release σ⁻¹.inv = σ
@atomiconce :release :acquire σ.inv = σ⁻¹
end
end
return σ.inv
end
return σ.inv
end

function AP.cycles(σ::Perm)
if !isdefined(σ, :cycles, :acquire)
cdec = AP.CycleDecomposition(σ)
# we can afford producing more than one cycle decomposition
@atomiconce :release :acquire σ.cycles = cdec
function AP.cycles(σ::Perm)
if !isdefined(σ, :cycles, :acquire)
cdec = AP.CycleDecomposition(σ)
# we can afford producing more than one cycle decomposition
@atomiconce :release :acquire σ.cycles = cdec
end
return σ.cycles
end
return σ.cycles
end

function Base.isodd(σ::Perm)
Expand Down
20 changes: 15 additions & 5 deletions src/group_interface.jl
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,22 @@

Base.one(G::PermGroup{P}) where {P} = Permutation(one(P), G)

function GroupsCore.order(::Type{T}, G::AbstractPermutationGroup) where {T}
if !isdefined(G, :order, :acquire)
ord = order(BigInt, StabilizerChain(G))
@atomiconce :release :acquire G.order = ord
@static if VERSION < v"1.11"
function GroupsCore.order(::Type{T}, G::AbstractPermutationGroup) where {T}
if !isdefined(G, :order, :sequentially_consistent)
ord = order(StabilizerChain(G))
@atomic G.order = ord
end
return convert(T, G.order)
end
else
function GroupsCore.order(::Type{T}, G::AbstractPermutationGroup) where {T}
if !isdefined(G, :order, :acquire)
ord = order(BigInt, StabilizerChain(G))
@atomiconce :release :acquire G.order = ord
end
return convert(T, G.order)
end
return convert(T, G.order)
end

GroupsCore.gens(G::PermGroup) = Permutation.(G.__gens_raw, Ref(G))
Expand Down
24 changes: 18 additions & 6 deletions src/perm_group.jl
Original file line number Diff line number Diff line change
Expand Up @@ -88,13 +88,25 @@ The first call on a particular group `G` will construct the chain from `gens(G)`
and complete it by the deterministic Schreier-Sims algorithm.
The subsequent calls just return the cached data structure.
"""

function StabilizerChain(G::PermGroup{P,T}) where {P,T}
if !isdefined(G, :stabchain, :acquire)
stabchain = schreier_sims(T, __gens_raw(G))
@atomiconce :release :acquire G.stabchain = stabchain
@static if VERSION < v"1.11"
function StabilizerChain(G::PermGroup{P,T}) where {P,T}
if !isdefined(G, :stabchain, :sequentially_consistent)
stabchain = schreier_sims(T, __gens_raw(G))
# this may take some time, so let's check again
if !isdefined(G, :stabchain, :sequentially_consistent)
@atomic G.stabchain = stabchain
end
end
return G.stabchain
end
else
function StabilizerChain(G::PermGroup{P,T}) where {P,T}
if !isdefined(G, :stabchain, :acquire)
stabchain = schreier_sims(T, __gens_raw(G))
@atomiconce :release :acquire G.stabchain = stabchain
end
return G.stabchain
end
return G.stabchain
end

basis(G::AbstractPermutationGroup) = basis(StabilizerChain(G))
Expand Down