diff --git a/src/Perms/perm_images.jl b/src/Perms/perm_images.jl index 14888a6..5efe2ae 100644 --- a/src/Perms/perm_images.jl +++ b/src/Perms/perm_images.jl @@ -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) diff --git a/src/group_interface.jl b/src/group_interface.jl index f199a20..faf993e 100644 --- a/src/group_interface.jl +++ b/src/group_interface.jl @@ -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)) diff --git a/src/perm_group.jl b/src/perm_group.jl index e246d3f..98bd28a 100644 --- a/src/perm_group.jl +++ b/src/perm_group.jl @@ -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))