From 638f7541469eb43c84d666b9b02b21a44ff45119 Mon Sep 17 00:00:00 2001 From: Marek Kaluba Date: Thu, 7 Nov 2024 12:16:04 +0100 Subject: [PATCH 01/16] implement SubBasis and SubMStructure --- src/bases_fixed.jl | 83 +++++++++++++++++++++++++++++++++------- test/perm_grp_algebra.jl | 28 ++++++++++++++ 2 files changed, 97 insertions(+), 14 deletions(-) diff --git a/src/bases_fixed.jl b/src/bases_fixed.jl index 309d110b..054af965 100644 --- a/src/bases_fixed.jl +++ b/src/bases_fixed.jl @@ -1,9 +1,36 @@ # This file is a part of StarAlgebras.jl. License is MIT: https://github.com/JuliaAlgebra/StarAlgebras.jl/blob/main/LICENSE # Copyright (c) 2021-2025: Marek Kaluba, Benoît Legat -mutable struct FixedBasis{T,I,V<:AbstractVector{T}} <: - ExplicitBasis{T,I} - elts::V +abstract type FiniteSupportBasis{T,I} <: ExplicitBasis{T,I} end + +""" + supp(fb::FiniteSupportBasis) +Return the supporting elements of `fb` as an indexable vector +""" +function supp end + +Base.IteratorSize(::Type{<:FiniteSupportBasis}) = Base.HasLength() +Base.IteratorEltype(::Type{<:FiniteSupportBasis{T}}) where {T} = T +Base.length(b::FiniteSupportBasis) = length(supp(b)) + +Base.iterate(b::FiniteSupportBasis) = iterate(supp(b)) +Base.iterate(b::FiniteSupportBasis, state) = iterate(supp(b), state) +# function Base.IndexStyle(::Type{<:FiniteSupportBasis{T,I,V}}) where {T,I,V} +# return Base.IndexStyle(V) +# end + +# To break ambiguity +# ?? +Base.@propagate_inbounds function Base.getindex( + b::FiniteSupportBasis, + i::Integer, +) + return supp(b)[i] +end + +mutable struct FixedBasis{T,I,V<:AbstractVector{T},M<:MTable{T,I}} <: + FiniteSupportBasis{T,I} + supporting_elts::V relts::Dict{T,I} starof::Vector{I} end @@ -21,20 +48,48 @@ function FixedBasis{T,I}(basis::AbstractBasis{T}; n::Integer) where {T,I} end FixedBasis(basis::AbstractBasis{T}; n::Integer) where {T} = FixedBasis{T,typeof(n)}(basis; n) - +supp(fb::FixedBasis) = fb.supporting_elts Base.in(x, b::FixedBasis) = haskey(b.relts, x) Base.getindex(b::FixedBasis{T}, x::T) where {T} = b.relts[x] Base.getindex(b::FixedBasis, i::Integer) = b.elts[i] -Base.IteratorSize(::Type{<:FixedBasis}) = Base.HasLength() -Base.length(b::FixedBasis) = length(b.elts) +struct SubBasis{T,I,V,B<:AbstractBasis{T,I}} <: FiniteSupportBasis{T,I} + supporting_elts::V + parent_basis::B +end -Base.iterate(b::FixedBasis) = iterate(b.elts) -Base.iterate(b::FixedBasis, state) = iterate(b.elts, state) -Base.IndexStyle(::Type{<:FixedBasis{T,I,V}}) where {T,I,V} = Base.IndexStyle(V) +supp(sb::SubBasis) = sb.supporting_elts +Base.parent(sub::SubBasis) = sub.parent_basis -# To break ambiguity -Base.@propagate_inbounds Base.getindex( - b::FixedBasis{T,I}, - i::I, -) where {T,I<:Integer} = b.elts[i] +Base.in(x, b::SubBasis) = x in supp(b) +function Base.getindex(b::SubBasis{T,I}, x::T) where {T,I<:Integer} + k = findfirst(==(x), supp(b)) + isnothing(k) && throw("x=$x is not supported on SubBasis") + @info T I + return convert(I, k) +end + +function Base.getindex(b::SubBasis{T,T}, x::T) where {T} + x in supp(b) && return x + throw("x=$x is not supported on SubBasis") +end + +struct SubMStructure{SB<:SubBasis,MS} <: MultiplicativeStructure + basis::SB + mstructure::MS +end + +function mstructure(b::SubBasis) + pb = b.parent_basis + return SubMStructure(b, mstructure(pb)) +end + +function (mstr::SubMStructure)(x::T, y::T) where {T} + b = mstr.basis + xy = mstr.mstructure(b[x], b[y]) + return xy +end + +# this is used for key-lookup in mstructures.jl +# MA.operate!(op::UnsafeAddMul, …) +_key(mstr::SubMStructure, k) = findfirst(==(k), supp(mstr.basis)) diff --git a/test/perm_grp_algebra.jl b/test/perm_grp_algebra.jl index 6d245cb2..2bbf5f11 100644 --- a/test/perm_grp_algebra.jl +++ b/test/perm_grp_algebra.jl @@ -99,4 +99,32 @@ end @test a ≤ b end + + @testset "FiniteSupportBasis" begin + S1 = unique!(rand(G, 7)) + S = unique!([S1; [a * b for a in S1 for b in S1]]) + subb = SA.SubBasis(S, db) + smstr = SA.mstructure(subb) + @test smstr(1, 2).basis_elements[1] == subb[1] * subb[2] + + sbRG = SA.StarAlgebra(G, subb) + + x = let z = zeros(Int, length(SA.basis(sbRG))) + z[1:length(S1)] .= rand(-1:1, length(S1)) + SA.AlgebraElement(z, sbRG) + end + + y = let z = zeros(Int, length(SA.basis(sbRG))) + z[1:length(S1)] .= rand(-1:1, length(S1)) + SA.AlgebraElement(z, sbRG) + end + + dx = SA.AlgebraElement(SA.coeffs(x, basis(RG)), RG) + dy = SA.AlgebraElement(SA.coeffs(y, basis(RG)), RG) + + @test dx + dy == SA.AlgebraElement(SA.coeffs(x + y, basis(RG)), RG) + + @test dx * dy == SA.AlgebraElement(SA.coeffs(x * y, basis(RG)), RG) + end end + From 5d8c7636719748291c9b09d9ebd134ed35e3a00d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20Legat?= Date: Thu, 7 Nov 2024 17:05:00 +0100 Subject: [PATCH 02/16] Add broken tests --- test/perm_grp_algebra.jl | 32 +++++++++++++++++++++++++------- 1 file changed, 25 insertions(+), 7 deletions(-) diff --git a/test/perm_grp_algebra.jl b/test/perm_grp_algebra.jl index 2bbf5f11..51c3b32b 100644 --- a/test/perm_grp_algebra.jl +++ b/test/perm_grp_algebra.jl @@ -1,6 +1,9 @@ # This file is a part of StarAlgebras.jl. License is MIT: https://github.com/JuliaAlgebra/StarAlgebras.jl/blob/main/LICENSE # Copyright (c) 2021-2025: Marek Kaluba, Benoît Legat +using Test +using PermutationGroups +import StarAlgebras as SA @testset "POC: group algebra" begin G = PermGroup(perm"(1,2,3,4,5,6)", perm"(1,2)") g = Permutation(perm"(1,4,3,6)(2,5)", G) @@ -119,12 +122,27 @@ SA.AlgebraElement(z, sbRG) end - dx = SA.AlgebraElement(SA.coeffs(x, basis(RG)), RG) - dy = SA.AlgebraElement(SA.coeffs(y, basis(RG)), RG) - - @test dx + dy == SA.AlgebraElement(SA.coeffs(x + y, basis(RG)), RG) - - @test dx * dy == SA.AlgebraElement(SA.coeffs(x * y, basis(RG)), RG) + dx = SA.AlgebraElement(SA.coeffs(x, SA.basis(RG)), RG) + dy = SA.AlgebraElement(SA.coeffs(y, SA.basis(RG)), RG) + + @test dx + dy == SA.AlgebraElement(SA.coeffs(x + y, SA.basis(RG)), RG) + + @test dx * dy == SA.AlgebraElement(SA.coeffs(x * y, SA.basis(RG)), RG) + + a = SA.AlgebraElement([2], SA.StarAlgebra(G, SA.SubBasis([g], db))) + b = SA.AlgebraElement([-3], SA.StarAlgebra(G, SA.SubBasis([h], db))) + # `Base.+` assumes that using the basis of the first argument will suffice + # We should redefine `Base.:+(a::SubBasis, b::SubBasis)` to first + # convert `a` and `b` to their implicit basis equivalent and then + # do `+` and then convert the result back + # `MultivariateBases` defines an `implicit` function. + # Why not having an `explicit` as well ? + # My dream implementation would be + # Base.:+(a::SubBasis, b::SubBasis) = explicit(implicit(a) + implicit(b)) + # so we just need to implement `implicit` and `explicit` 👼 + @test_broken SA.explicit(SA.implicit(a)) == a + @test_broken SA.explicit(SA.implicit(b)) == b + @test_broken a + b == SA.explicit(SA.implicit(a) + SA.implicit(b)) + @test_broken a * b == SA.explicit(SA.implicit(a) * SA.implicit(b)) end end - From d76bb235dcd63f1d866fdb31181c4d96cd347ae9 Mon Sep 17 00:00:00 2001 From: Marek Kaluba Date: Sun, 1 Dec 2024 23:07:09 +0100 Subject: [PATCH 03/16] store indicies instead of elts But this makes the abstraction useless... --- src/bases_fixed.jl | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/src/bases_fixed.jl b/src/bases_fixed.jl index 054af965..ffee72af 100644 --- a/src/bases_fixed.jl +++ b/src/bases_fixed.jl @@ -19,8 +19,6 @@ Base.iterate(b::FiniteSupportBasis, state) = iterate(supp(b), state) # return Base.IndexStyle(V) # end -# To break ambiguity -# ?? Base.@propagate_inbounds function Base.getindex( b::FiniteSupportBasis, i::Integer, @@ -53,25 +51,22 @@ Base.in(x, b::FixedBasis) = haskey(b.relts, x) Base.getindex(b::FixedBasis{T}, x::T) where {T} = b.relts[x] Base.getindex(b::FixedBasis, i::Integer) = b.elts[i] -struct SubBasis{T,I,V,B<:AbstractBasis{T,I}} <: FiniteSupportBasis{T,I} - supporting_elts::V +struct SubBasis{T,I,V<:AbstractVector{I},B<:AbstractBasis{T,I}} <: + FiniteSupportBasis{T,I} + supporting_idcs::V parent_basis::B end -supp(sb::SubBasis) = sb.supporting_elts +supp(sb::SubBasis) = sb.supporting_idcs Base.parent(sub::SubBasis) = sub.parent_basis Base.in(x, b::SubBasis) = x in supp(b) function Base.getindex(b::SubBasis{T,I}, x::T) where {T,I<:Integer} - k = findfirst(==(x), supp(b)) - isnothing(k) && throw("x=$x is not supported on SubBasis") - @info T I - return convert(I, k) + return convert(I, parent(b)[supp(b)[x]]) end function Base.getindex(b::SubBasis{T,T}, x::T) where {T} - x in supp(b) && return x - throw("x=$x is not supported on SubBasis") + parent(b)[x] in supp(b) && return x end struct SubMStructure{SB<:SubBasis,MS} <: MultiplicativeStructure From 79d8a0cb976a1c04ba1107e420be293c69814b12 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20Legat?= Date: Mon, 28 Apr 2025 16:43:39 +0200 Subject: [PATCH 04/16] Fix tests --- src/bases_fixed.jl | 43 ++++++++++------------------------------ test/perm_grp_algebra.jl | 6 ++++-- 2 files changed, 15 insertions(+), 34 deletions(-) diff --git a/src/bases_fixed.jl b/src/bases_fixed.jl index ffee72af..a9e60e6f 100644 --- a/src/bases_fixed.jl +++ b/src/bases_fixed.jl @@ -8,6 +8,7 @@ abstract type FiniteSupportBasis{T,I} <: ExplicitBasis{T,I} end Return the supporting elements of `fb` as an indexable vector """ function supp end +supp(fb::FiniteSupportBasis) = fb.supporting_elts Base.IteratorSize(::Type{<:FiniteSupportBasis}) = Base.HasLength() Base.IteratorEltype(::Type{<:FiniteSupportBasis{T}}) where {T} = T @@ -26,7 +27,7 @@ Base.@propagate_inbounds function Base.getindex( return supp(b)[i] end -mutable struct FixedBasis{T,I,V<:AbstractVector{T},M<:MTable{T,I}} <: +mutable struct FixedBasis{T,I,V<:AbstractVector{T}} <: FiniteSupportBasis{T,I} supporting_elts::V relts::Dict{T,I} @@ -46,45 +47,23 @@ function FixedBasis{T,I}(basis::AbstractBasis{T}; n::Integer) where {T,I} end FixedBasis(basis::AbstractBasis{T}; n::Integer) where {T} = FixedBasis{T,typeof(n)}(basis; n) -supp(fb::FixedBasis) = fb.supporting_elts Base.in(x, b::FixedBasis) = haskey(b.relts, x) Base.getindex(b::FixedBasis{T}, x::T) where {T} = b.relts[x] -Base.getindex(b::FixedBasis, i::Integer) = b.elts[i] +Base.getindex(b::FixedBasis, i::Integer) = b.supporting_elts[i] -struct SubBasis{T,I,V<:AbstractVector{I},B<:AbstractBasis{T,I}} <: +struct SubBasis{T,I,K,V<:AbstractVector{K},B<:AbstractBasis{T,K}} <: FiniteSupportBasis{T,I} supporting_idcs::V parent_basis::B + function SubBasis(supporting_idcs::AbstractVector{K}, parent_basis::AbstractBasis{T,K}) where {T,K} + return new{T,keytype(supporting_idcs),K,typeof(supporting_idcs),typeof(parent_basis)}(supporting_idcs, parent_basis) + end end supp(sb::SubBasis) = sb.supporting_idcs Base.parent(sub::SubBasis) = sub.parent_basis -Base.in(x, b::SubBasis) = x in supp(b) -function Base.getindex(b::SubBasis{T,I}, x::T) where {T,I<:Integer} - return convert(I, parent(b)[supp(b)[x]]) -end - -function Base.getindex(b::SubBasis{T,T}, x::T) where {T} - parent(b)[x] in supp(b) && return x -end - -struct SubMStructure{SB<:SubBasis,MS} <: MultiplicativeStructure - basis::SB - mstructure::MS -end - -function mstructure(b::SubBasis) - pb = b.parent_basis - return SubMStructure(b, mstructure(pb)) -end - -function (mstr::SubMStructure)(x::T, y::T) where {T} - b = mstr.basis - xy = mstr.mstructure(b[x], b[y]) - return xy -end - -# this is used for key-lookup in mstructures.jl -# MA.operate!(op::UnsafeAddMul, …) -_key(mstr::SubMStructure, k) = findfirst(==(k), supp(mstr.basis)) +Base.in(x, b::SubBasis) = b.parent_basis[x] in supp(b) +function Base.getindex(b::SubBasis{T,I}, x::T) where {T,I} + return convert(I, findfirst(isequal(b.parent_basis[x]), supp(b))) +end \ No newline at end of file diff --git a/test/perm_grp_algebra.jl b/test/perm_grp_algebra.jl index 51c3b32b..351ed5c0 100644 --- a/test/perm_grp_algebra.jl +++ b/test/perm_grp_algebra.jl @@ -107,8 +107,9 @@ import StarAlgebras as SA S1 = unique!(rand(G, 7)) S = unique!([S1; [a * b for a in S1 for b in S1]]) subb = SA.SubBasis(S, db) - smstr = SA.mstructure(subb) - @test smstr(1, 2).basis_elements[1] == subb[1] * subb[2] + smstr = SA.DiracMStructure(subb, *) + @test only(smstr(1, 2).basis_elements) == subb[subb[1] * subb[2]] + @test only(smstr(1, 2, eltype(subb)).basis_elements) == subb[1] * subb[2] sbRG = SA.StarAlgebra(G, subb) @@ -141,6 +142,7 @@ import StarAlgebras as SA # Base.:+(a::SubBasis, b::SubBasis) = explicit(implicit(a) + implicit(b)) # so we just need to implement `implicit` and `explicit` 👼 @test_broken SA.explicit(SA.implicit(a)) == a + @test_broken SA.explicit(SA.implicit(a)) == a @test_broken SA.explicit(SA.implicit(b)) == b @test_broken a + b == SA.explicit(SA.implicit(a) + SA.implicit(b)) @test_broken a * b == SA.explicit(SA.implicit(a) * SA.implicit(b)) From 1eae2473ce1600d206c085ed7928c765a66aa652 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20Legat?= Date: Mon, 28 Apr 2025 16:44:00 +0200 Subject: [PATCH 05/16] Remove implicit/explicit --- test/perm_grp_algebra.jl | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/test/perm_grp_algebra.jl b/test/perm_grp_algebra.jl index 351ed5c0..b1cc0290 100644 --- a/test/perm_grp_algebra.jl +++ b/test/perm_grp_algebra.jl @@ -129,22 +129,5 @@ import StarAlgebras as SA @test dx + dy == SA.AlgebraElement(SA.coeffs(x + y, SA.basis(RG)), RG) @test dx * dy == SA.AlgebraElement(SA.coeffs(x * y, SA.basis(RG)), RG) - - a = SA.AlgebraElement([2], SA.StarAlgebra(G, SA.SubBasis([g], db))) - b = SA.AlgebraElement([-3], SA.StarAlgebra(G, SA.SubBasis([h], db))) - # `Base.+` assumes that using the basis of the first argument will suffice - # We should redefine `Base.:+(a::SubBasis, b::SubBasis)` to first - # convert `a` and `b` to their implicit basis equivalent and then - # do `+` and then convert the result back - # `MultivariateBases` defines an `implicit` function. - # Why not having an `explicit` as well ? - # My dream implementation would be - # Base.:+(a::SubBasis, b::SubBasis) = explicit(implicit(a) + implicit(b)) - # so we just need to implement `implicit` and `explicit` 👼 - @test_broken SA.explicit(SA.implicit(a)) == a - @test_broken SA.explicit(SA.implicit(a)) == a - @test_broken SA.explicit(SA.implicit(b)) == b - @test_broken a + b == SA.explicit(SA.implicit(a) + SA.implicit(b)) - @test_broken a * b == SA.explicit(SA.implicit(a) * SA.implicit(b)) end end From 03658f3e1a850271a9d45b42e0701ba0a37f64e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20Legat?= Date: Mon, 28 Apr 2025 17:17:51 +0200 Subject: [PATCH 06/16] Remove FiniteSupportBasis --- src/bases.jl | 7 +++- src/bases_fixed.jl | 83 ++++++++++++++++++++++++---------------- test/perm_grp_algebra.jl | 3 +- 3 files changed, 58 insertions(+), 35 deletions(-) diff --git a/src/bases.jl b/src/bases.jl index 8665bcf5..dde1763a 100644 --- a/src/bases.jl +++ b/src/bases.jl @@ -39,6 +39,8 @@ Implicit bases are not stored in memory and can be potentially infinite. """ abstract type ImplicitBasis{T,I} <: AbstractBasis{T,I} end +Base.IteratorEltype(::Type{<:ImplicitBasis{T}}) where {T} = T + function zero_coeffs(::Type{S}, ::ImplicitBasis{T,I}) where {S,T,I} return SparseCoefficients(I[], S[]) end @@ -50,6 +52,7 @@ Explicit bases are stored e.g. in an `AbstractVector` and hence immutable """ abstract type ExplicitBasis{T,I} <: AbstractBasis{T,I} end +Base.IteratorSize(::Type{<:ExplicitBasis}) = Base.HasLength() Base.keys(eb::ExplicitBasis) = Base.OneTo(length(eb)) Base.size(eb::ExplicitBasis) = (length(eb),) @@ -57,8 +60,8 @@ function zero_coeffs(::Type{S}, eb::ExplicitBasis{T,I}) where {S,T,I} return spzeros(S, I, length(eb)) end -function Base.getindex(eb::ExplicitBasis, range::AbstractRange{<:Integer}) - return [eb[i] for i in range] +function Base.getindex(eb::ExplicitBasis{T}, range::AbstractRange{<:Integer}) where {T} + return T[eb[i] for i in range] end """ diff --git a/src/bases_fixed.jl b/src/bases_fixed.jl index a9e60e6f..516869b3 100644 --- a/src/bases_fixed.jl +++ b/src/bases_fixed.jl @@ -1,34 +1,14 @@ # This file is a part of StarAlgebras.jl. License is MIT: https://github.com/JuliaAlgebra/StarAlgebras.jl/blob/main/LICENSE # Copyright (c) 2021-2025: Marek Kaluba, Benoît Legat -abstract type FiniteSupportBasis{T,I} <: ExplicitBasis{T,I} end - """ - supp(fb::FiniteSupportBasis) -Return the supporting elements of `fb` as an indexable vector + mutable struct FixedBasis{T,I,V<:AbstractVector{T}} <: ExplicitBasis{T,I} + supporting_elts::V + relts::Dict{T,I} + starof::Vector{I} + end """ -function supp end -supp(fb::FiniteSupportBasis) = fb.supporting_elts - -Base.IteratorSize(::Type{<:FiniteSupportBasis}) = Base.HasLength() -Base.IteratorEltype(::Type{<:FiniteSupportBasis{T}}) where {T} = T -Base.length(b::FiniteSupportBasis) = length(supp(b)) - -Base.iterate(b::FiniteSupportBasis) = iterate(supp(b)) -Base.iterate(b::FiniteSupportBasis, state) = iterate(supp(b), state) -# function Base.IndexStyle(::Type{<:FiniteSupportBasis{T,I,V}}) where {T,I,V} -# return Base.IndexStyle(V) -# end - -Base.@propagate_inbounds function Base.getindex( - b::FiniteSupportBasis, - i::Integer, -) - return supp(b)[i] -end - -mutable struct FixedBasis{T,I,V<:AbstractVector{T}} <: - FiniteSupportBasis{T,I} +mutable struct FixedBasis{T,I,V<:AbstractVector{T}} <: ExplicitBasis{T,I} supporting_elts::V relts::Dict{T,I} starof::Vector{I} @@ -49,21 +29,60 @@ end FixedBasis(basis::AbstractBasis{T}; n::Integer) where {T} = FixedBasis{T,typeof(n)}(basis; n) Base.in(x, b::FixedBasis) = haskey(b.relts, x) Base.getindex(b::FixedBasis{T}, x::T) where {T} = b.relts[x] -Base.getindex(b::FixedBasis, i::Integer) = b.supporting_elts[i] +Base.@propagate_inbounds Base.getindex(b::FixedBasis, i::Integer) = b.supporting_elts[i] + +Base.iterate(b::FixedBasis) = iterate(b.supporting_elts) +Base.iterate(b::FixedBasis, state) = iterate(b.supporting_elts, state) +function Base.IndexStyle(::Type{<:FixedBasis{T,I,V}}) where {T,I,V} + return Base.IndexStyle(V) +end struct SubBasis{T,I,K,V<:AbstractVector{K},B<:AbstractBasis{T,K}} <: - FiniteSupportBasis{T,I} + ExplicitBasis{T,I} supporting_idcs::V parent_basis::B + is_sorted::Bool function SubBasis(supporting_idcs::AbstractVector{K}, parent_basis::AbstractBasis{T,K}) where {T,K} - return new{T,keytype(supporting_idcs),K,typeof(supporting_idcs),typeof(parent_basis)}(supporting_idcs, parent_basis) + return new{T,keytype(supporting_idcs),K,typeof(supporting_idcs),typeof(parent_basis)}(supporting_idcs, parent_basis, issorted(supporting_idcs)) end end -supp(sb::SubBasis) = sb.supporting_idcs Base.parent(sub::SubBasis) = sub.parent_basis -Base.in(x, b::SubBasis) = b.parent_basis[x] in supp(b) +Base.length(b::SubBasis) = length(b.supporting_idcs) +function _iterate(b::SubBasis, elem_state) + if isnothing(elem_state) + return + end + elem, state = elem_state + return parent(b)[elem], state +end +Base.iterate(b::SubBasis) = _iterate(b, iterate(b.supporting_idcs)) +Base.iterate(b::SubBasis, st) = _iterate(b, iterate(b.supporting_idcs, st)) + +function Base.get(b::SubBasis{T,I}, x::T, default) where {T,I} + key = b.parent_basis[x] + if b.is_sorted + i = searchsortedfirst(b.supporting_idcs, key) + if i in eachindex(b.supporting_idcs) && b.supporting_idcs[i] == key + return convert(I, i) + end + else + i = findfirst(isequal(key), b.supporting_idcs) + if !isnothing(i) + return convert(I, i) + end + end + return default +end + +Base.in(x::T, b::SubBasis{T}) where T = !isnothing(get(b, x, nothing)) + +Base.getindex(b::SubBasis, i::Integer) = parent(b)[b.supporting_idcs[i]] function Base.getindex(b::SubBasis{T,I}, x::T) where {T,I} - return convert(I, findfirst(isequal(b.parent_basis[x]), supp(b))) + i = get(b, x, nothing) + if isnothing(i) + throw(BoundsError(b, x)) + end + return i::I end \ No newline at end of file diff --git a/test/perm_grp_algebra.jl b/test/perm_grp_algebra.jl index b1cc0290..3f813217 100644 --- a/test/perm_grp_algebra.jl +++ b/test/perm_grp_algebra.jl @@ -103,10 +103,11 @@ import StarAlgebras as SA @test a ≤ b end - @testset "FiniteSupportBasis" begin + @testset "SubBasis" begin S1 = unique!(rand(G, 7)) S = unique!([S1; [a * b for a in S1 for b in S1]]) subb = SA.SubBasis(S, db) + collect(subb) smstr = SA.DiracMStructure(subb, *) @test only(smstr(1, 2).basis_elements) == subb[subb[1] * subb[2]] @test only(smstr(1, 2, eltype(subb)).basis_elements) == subb[1] * subb[2] From abffaec232470ce6cec13879ef4c6206a8849f77 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20Legat?= Date: Mon, 28 Apr 2025 17:23:43 +0200 Subject: [PATCH 07/16] Fixes --- src/bases.jl | 2 -- src/bases_fixed.jl | 3 ++- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/bases.jl b/src/bases.jl index dde1763a..3c155469 100644 --- a/src/bases.jl +++ b/src/bases.jl @@ -39,8 +39,6 @@ Implicit bases are not stored in memory and can be potentially infinite. """ abstract type ImplicitBasis{T,I} <: AbstractBasis{T,I} end -Base.IteratorEltype(::Type{<:ImplicitBasis{T}}) where {T} = T - function zero_coeffs(::Type{S}, ::ImplicitBasis{T,I}) where {S,T,I} return SparseCoefficients(I[], S[]) end diff --git a/src/bases_fixed.jl b/src/bases_fixed.jl index 516869b3..0f2d7700 100644 --- a/src/bases_fixed.jl +++ b/src/bases_fixed.jl @@ -31,6 +31,7 @@ Base.in(x, b::FixedBasis) = haskey(b.relts, x) Base.getindex(b::FixedBasis{T}, x::T) where {T} = b.relts[x] Base.@propagate_inbounds Base.getindex(b::FixedBasis, i::Integer) = b.supporting_elts[i] +Base.length(b::FixedBasis) = length(b.supporting_elts) Base.iterate(b::FixedBasis) = iterate(b.supporting_elts) Base.iterate(b::FixedBasis, state) = iterate(b.supporting_elts, state) function Base.IndexStyle(::Type{<:FixedBasis{T,I,V}}) where {T,I,V} @@ -78,7 +79,7 @@ end Base.in(x::T, b::SubBasis{T}) where T = !isnothing(get(b, x, nothing)) -Base.getindex(b::SubBasis, i::Integer) = parent(b)[b.supporting_idcs[i]] +Base.@propagate_inbounds Base.getindex(b::SubBasis, i::Integer) = parent(b)[b.supporting_idcs[i]] function Base.getindex(b::SubBasis{T,I}, x::T) where {T,I} i = get(b, x, nothing) if isnothing(i) From 6f836904cc266ae37e62fb6917cab285f5b5d677 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20Legat?= Date: Mon, 28 Apr 2025 17:24:41 +0200 Subject: [PATCH 08/16] Rename fields --- src/bases_fixed.jl | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/src/bases_fixed.jl b/src/bases_fixed.jl index 0f2d7700..6e312119 100644 --- a/src/bases_fixed.jl +++ b/src/bases_fixed.jl @@ -3,13 +3,13 @@ """ mutable struct FixedBasis{T,I,V<:AbstractVector{T}} <: ExplicitBasis{T,I} - supporting_elts::V + elts::V relts::Dict{T,I} starof::Vector{I} end """ mutable struct FixedBasis{T,I,V<:AbstractVector{T}} <: ExplicitBasis{T,I} - supporting_elts::V + elts::V relts::Dict{T,I} starof::Vector{I} end @@ -29,28 +29,28 @@ end FixedBasis(basis::AbstractBasis{T}; n::Integer) where {T} = FixedBasis{T,typeof(n)}(basis; n) Base.in(x, b::FixedBasis) = haskey(b.relts, x) Base.getindex(b::FixedBasis{T}, x::T) where {T} = b.relts[x] -Base.@propagate_inbounds Base.getindex(b::FixedBasis, i::Integer) = b.supporting_elts[i] +Base.@propagate_inbounds Base.getindex(b::FixedBasis, i::Integer) = b.elts[i] -Base.length(b::FixedBasis) = length(b.supporting_elts) -Base.iterate(b::FixedBasis) = iterate(b.supporting_elts) -Base.iterate(b::FixedBasis, state) = iterate(b.supporting_elts, state) +Base.length(b::FixedBasis) = length(b.elts) +Base.iterate(b::FixedBasis) = iterate(b.elts) +Base.iterate(b::FixedBasis, state) = iterate(b.elts, state) function Base.IndexStyle(::Type{<:FixedBasis{T,I,V}}) where {T,I,V} return Base.IndexStyle(V) end struct SubBasis{T,I,K,V<:AbstractVector{K},B<:AbstractBasis{T,K}} <: ExplicitBasis{T,I} - supporting_idcs::V + keys::V parent_basis::B is_sorted::Bool - function SubBasis(supporting_idcs::AbstractVector{K}, parent_basis::AbstractBasis{T,K}) where {T,K} - return new{T,keytype(supporting_idcs),K,typeof(supporting_idcs),typeof(parent_basis)}(supporting_idcs, parent_basis, issorted(supporting_idcs)) + function SubBasis(keys::AbstractVector{K}, parent_basis::AbstractBasis{T,K}) where {T,K} + return new{T,keytype(keys),K,typeof(keys),typeof(parent_basis)}(keys, parent_basis, issorted(keys)) end end Base.parent(sub::SubBasis) = sub.parent_basis -Base.length(b::SubBasis) = length(b.supporting_idcs) +Base.length(b::SubBasis) = length(b.keys) function _iterate(b::SubBasis, elem_state) if isnothing(elem_state) return @@ -58,18 +58,18 @@ function _iterate(b::SubBasis, elem_state) elem, state = elem_state return parent(b)[elem], state end -Base.iterate(b::SubBasis) = _iterate(b, iterate(b.supporting_idcs)) -Base.iterate(b::SubBasis, st) = _iterate(b, iterate(b.supporting_idcs, st)) +Base.iterate(b::SubBasis) = _iterate(b, iterate(b.keys)) +Base.iterate(b::SubBasis, st) = _iterate(b, iterate(b.keys, st)) function Base.get(b::SubBasis{T,I}, x::T, default) where {T,I} key = b.parent_basis[x] if b.is_sorted - i = searchsortedfirst(b.supporting_idcs, key) - if i in eachindex(b.supporting_idcs) && b.supporting_idcs[i] == key + i = searchsortedfirst(b.keys, key) + if i in eachindex(b.keys) && b.keys[i] == key return convert(I, i) end else - i = findfirst(isequal(key), b.supporting_idcs) + i = findfirst(isequal(key), b.keys) if !isnothing(i) return convert(I, i) end @@ -79,7 +79,7 @@ end Base.in(x::T, b::SubBasis{T}) where T = !isnothing(get(b, x, nothing)) -Base.@propagate_inbounds Base.getindex(b::SubBasis, i::Integer) = parent(b)[b.supporting_idcs[i]] +Base.@propagate_inbounds Base.getindex(b::SubBasis, i::Integer) = parent(b)[b.keys[i]] function Base.getindex(b::SubBasis{T,I}, x::T) where {T,I} i = get(b, x, nothing) if isnothing(i) From f29dc5e7929c6140738ba11ea9169a638268fe12 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20Legat?= Date: Mon, 28 Apr 2025 17:27:01 +0200 Subject: [PATCH 09/16] Adding docstrings --- src/bases_fixed.jl | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/bases_fixed.jl b/src/bases_fixed.jl index 6e312119..cb7ec63c 100644 --- a/src/bases_fixed.jl +++ b/src/bases_fixed.jl @@ -7,6 +7,11 @@ relts::Dict{T,I} starof::Vector{I} end + +Represents a fixed basis of a star algebra, where `elts` is a vector of elements +of type `T`, `relts` is a dictionary mapping elements to their indices, and +`starof` is a vector of indices caching the indices in `elts` of the result of +the star operation on the basis elements. """ mutable struct FixedBasis{T,I,V<:AbstractVector{T}} <: ExplicitBasis{T,I} elts::V @@ -38,6 +43,19 @@ function Base.IndexStyle(::Type{<:FixedBasis{T,I,V}}) where {T,I,V} return Base.IndexStyle(V) end +""" + struct SubBasis{T,I,K,V<:AbstractVector{K},B<:AbstractBasis{T,K}} <: + ExplicitBasis{T,I} + keys::V + parent_basis::B + is_sorted::Bool + end + +Represents a sub-basis of a given basis, where `keys` is a vector of keys +representing the sub-basis elements, `parent_basis` is the parent basis from +which the sub-basis is derived, and `is_sorted` indicates whether the keys are +sorted. +""" struct SubBasis{T,I,K,V<:AbstractVector{K},B<:AbstractBasis{T,K}} <: ExplicitBasis{T,I} keys::V From b448ad9cd7d20f150fea3878f493a39c7dd3a5da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20Legat?= Date: Mon, 28 Apr 2025 17:29:48 +0200 Subject: [PATCH 10/16] Remove unrelated changes --- src/bases_fixed.jl | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/bases_fixed.jl b/src/bases_fixed.jl index cb7ec63c..293abc32 100644 --- a/src/bases_fixed.jl +++ b/src/bases_fixed.jl @@ -13,7 +13,8 @@ of type `T`, `relts` is a dictionary mapping elements to their indices, and `starof` is a vector of indices caching the indices in `elts` of the result of the star operation on the basis elements. """ -mutable struct FixedBasis{T,I,V<:AbstractVector{T}} <: ExplicitBasis{T,I} +mutable struct FixedBasis{T,I,V<:AbstractVector{T}} <: + ExplicitBasis{T,I} elts::V relts::Dict{T,I} starof::Vector{I} @@ -32,16 +33,15 @@ function FixedBasis{T,I}(basis::AbstractBasis{T}; n::Integer) where {T,I} end FixedBasis(basis::AbstractBasis{T}; n::Integer) where {T} = FixedBasis{T,typeof(n)}(basis; n) + Base.in(x, b::FixedBasis) = haskey(b.relts, x) Base.getindex(b::FixedBasis{T}, x::T) where {T} = b.relts[x] -Base.@propagate_inbounds Base.getindex(b::FixedBasis, i::Integer) = b.elts[i] +Base.getindex(b::FixedBasis, i::Integer) = b.elts[i] Base.length(b::FixedBasis) = length(b.elts) Base.iterate(b::FixedBasis) = iterate(b.elts) Base.iterate(b::FixedBasis, state) = iterate(b.elts, state) -function Base.IndexStyle(::Type{<:FixedBasis{T,I,V}}) where {T,I,V} - return Base.IndexStyle(V) -end +Base.IndexStyle(::Type{<:FixedBasis{T,I,V}}) where {T,I,V} = Base.IndexStyle(V) """ struct SubBasis{T,I,K,V<:AbstractVector{K},B<:AbstractBasis{T,K}} <: @@ -97,11 +97,11 @@ end Base.in(x::T, b::SubBasis{T}) where T = !isnothing(get(b, x, nothing)) -Base.@propagate_inbounds Base.getindex(b::SubBasis, i::Integer) = parent(b)[b.keys[i]] +Base.getindex(b::SubBasis, i::Integer) = parent(b)[b.keys[i]] function Base.getindex(b::SubBasis{T,I}, x::T) where {T,I} i = get(b, x, nothing) if isnothing(i) throw(BoundsError(b, x)) end return i::I -end \ No newline at end of file +end From dfa6a7930e6b09f6c3ba5a37063d8fdcbe4f37bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20Legat?= Date: Mon, 28 Apr 2025 17:36:43 +0200 Subject: [PATCH 11/16] Fill in docstrings --- src/bases.jl | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/bases.jl b/src/bases.jl index 3c155469..b506be51 100644 --- a/src/bases.jl +++ b/src/bases.jl @@ -24,7 +24,6 @@ still be infinite). [`FixedBasis`](@ref) implements `AbstractVector`-type storage for elements. This can be used e.g. for representing polynomials as (sparse) vectors of coefficients w.r.t. a given `FixedBasis`. -expressed in it. """ abstract type AbstractBasis{T,I} end @@ -34,8 +33,11 @@ key_type(::Type{<:AbstractBasis{T,I}}) where {T,I} = I key_type(b::AbstractBasis) = key_type(typeof(b)) """ - ImplicitBasis{T,I} -Implicit bases are not stored in memory and can be potentially infinite. + abstract type ImplicitBasis{T,I} <: AbstractBasis{T,I} end + +Implicit bases are bases that contains the product of all its elements. +This makes these bases particularly appropriate as bases of [`AlgebraElement`](@ref)s. +Note that these bases may not explictly store its elements in memory as they may be potentially infinite. """ abstract type ImplicitBasis{T,I} <: AbstractBasis{T,I} end @@ -44,11 +46,11 @@ function zero_coeffs(::Type{S}, ::ImplicitBasis{T,I}) where {S,T,I} end """ - ExplicitBasis{T,I} -Explicit bases are stored e.g. in an `AbstractVector` and hence immutable -(in particular of well defined and fixed length). + abstract type ExplicitBasis{T,I<:Integer} <: AbstractBasis{T,I} end + +Explicit bases are bases of finite length for which the keys are integers. """ -abstract type ExplicitBasis{T,I} <: AbstractBasis{T,I} end +abstract type ExplicitBasis{T,I<:Integer} <: AbstractBasis{T,I} end Base.IteratorSize(::Type{<:ExplicitBasis}) = Base.HasLength() Base.keys(eb::ExplicitBasis) = Base.OneTo(length(eb)) From 3234af59c41b1349638008fa493ef0c90f2e24c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20Legat?= Date: Mon, 28 Apr 2025 17:48:56 +0200 Subject: [PATCH 12/16] Add tests --- src/bases_fixed.jl | 3 ++- test/perm_grp_algebra.jl | 8 +++++++- test/quadratic_form.jl | 20 +++++--------------- 3 files changed, 14 insertions(+), 17 deletions(-) diff --git a/src/bases_fixed.jl b/src/bases_fixed.jl index 293abc32..a8fea009 100644 --- a/src/bases_fixed.jl +++ b/src/bases_fixed.jl @@ -96,12 +96,13 @@ function Base.get(b::SubBasis{T,I}, x::T, default) where {T,I} end Base.in(x::T, b::SubBasis{T}) where T = !isnothing(get(b, x, nothing)) +Base.haskey(b::SubBasis, i::Integer) = i in eachindex(b.keys) Base.getindex(b::SubBasis, i::Integer) = parent(b)[b.keys[i]] function Base.getindex(b::SubBasis{T,I}, x::T) where {T,I} i = get(b, x, nothing) if isnothing(i) - throw(BoundsError(b, x)) + throw(KeyError(x)) end return i::I end diff --git a/test/perm_grp_algebra.jl b/test/perm_grp_algebra.jl index 3f813217..bcc21347 100644 --- a/test/perm_grp_algebra.jl +++ b/test/perm_grp_algebra.jl @@ -107,7 +107,13 @@ import StarAlgebras as SA S1 = unique!(rand(G, 7)) S = unique!([S1; [a * b for a in S1 for b in S1]]) subb = SA.SubBasis(S, db) - collect(subb) + a = S1[1] + @test subb[a] == 1 + @test a in subb + @test isnothing(get(subb, a^3, nothing)) + @test_throws KeyError(a^3) subb[a^3] + @test !(a^3 in subb) + @test collect(subb) == S smstr = SA.DiracMStructure(subb, *) @test only(smstr(1, 2).basis_elements) == subb[subb[1] * subb[2]] @test only(smstr(1, 2, eltype(subb)).basis_elements) == subb[1] * subb[2] diff --git a/test/quadratic_form.jl b/test/quadratic_form.jl index 2dfaf8ac..a775b091 100644 --- a/test/quadratic_form.jl +++ b/test/quadratic_form.jl @@ -74,19 +74,6 @@ @test A(Q) == π * b[3] * b[2] + b[4] * b[3] end -struct SubBasis{T,I,V<:AbstractVector{I},B<:SA.ImplicitBasis{T,I}} <: SA.ExplicitBasis{Float64,Int} - implicit::B - indices::V -end -Base.length(b::SubBasis) = length(b.indices) -function Base.iterate(b::SubBasis, args...) - elem_state = iterate(b.indices, args...) - if isnothing(elem_state) - return - end - return b.implicit[elem_state[1]], elem_state[2] -end - @testset "Int -> Float basis" begin limited = SA.MappedBasis(1:2, float, Int) @test !(3.0 in limited) @@ -95,7 +82,10 @@ end implicit = SA.MappedBasis(NaturalNumbers(), float, Int) @test 3.0 in implicit @test haskey(implicit, 3) - explicit = SubBasis(implicit, 1:3) + explicit = SA.SubBasis(1:3, implicit) + @test 3.0 in explicit + @test collect(explicit) == [1.0, 2.0, 3.0] + @test haskey(explicit, 3) m = Bool[ true false true false true false @@ -119,7 +109,7 @@ end implicit = cheby_basis() mstr = ChebyMStruct(implicit) mt = SA.MTable(implicit, mstr, (0, 0)) - sub = SubBasis(implicit, 1:3) + sub = SA.SubBasis(1:3, implicit) fixed = SA.FixedBasis(implicit; n = 3) a = ChebyPoly(2) b = ChebyPoly(3) From 8c57f1e35c8c42263f9c0a48579b39567aa717ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20Legat?= Date: Mon, 28 Apr 2025 17:59:58 +0200 Subject: [PATCH 13/16] Swap fields order --- src/bases_fixed.jl | 12 ++++++------ test/perm_grp_algebra.jl | 4 +++- test/quadratic_form.jl | 4 ++-- 3 files changed, 11 insertions(+), 9 deletions(-) diff --git a/src/bases_fixed.jl b/src/bases_fixed.jl index a8fea009..9e76261f 100644 --- a/src/bases_fixed.jl +++ b/src/bases_fixed.jl @@ -44,10 +44,10 @@ Base.iterate(b::FixedBasis, state) = iterate(b.elts, state) Base.IndexStyle(::Type{<:FixedBasis{T,I,V}}) where {T,I,V} = Base.IndexStyle(V) """ - struct SubBasis{T,I,K,V<:AbstractVector{K},B<:AbstractBasis{T,K}} <: + struct SubBasis{T,I,K,B<:AbstractBasis{T,K},V<:AbstractVector{K}} <: ExplicitBasis{T,I} - keys::V parent_basis::B + keys::V is_sorted::Bool end @@ -56,13 +56,13 @@ representing the sub-basis elements, `parent_basis` is the parent basis from which the sub-basis is derived, and `is_sorted` indicates whether the keys are sorted. """ -struct SubBasis{T,I,K,V<:AbstractVector{K},B<:AbstractBasis{T,K}} <: +struct SubBasis{T,I,K,B<:AbstractBasis{T,K},V<:AbstractVector{K}} <: ExplicitBasis{T,I} - keys::V parent_basis::B + keys::V is_sorted::Bool - function SubBasis(keys::AbstractVector{K}, parent_basis::AbstractBasis{T,K}) where {T,K} - return new{T,keytype(keys),K,typeof(keys),typeof(parent_basis)}(keys, parent_basis, issorted(keys)) + function SubBasis(parent_basis::AbstractBasis{T,K}, keys::AbstractVector{K}) where {T,K} + return new{T,keytype(keys),K,typeof(parent_basis),typeof(keys)}(parent_basis, keys, issorted(keys)) end end diff --git a/test/perm_grp_algebra.jl b/test/perm_grp_algebra.jl index bcc21347..d395fa7e 100644 --- a/test/perm_grp_algebra.jl +++ b/test/perm_grp_algebra.jl @@ -3,6 +3,7 @@ using Test using PermutationGroups +import Random import StarAlgebras as SA @testset "POC: group algebra" begin G = PermGroup(perm"(1,2,3,4,5,6)", perm"(1,2)") @@ -104,9 +105,10 @@ import StarAlgebras as SA end @testset "SubBasis" begin + Random.seed!(0) S1 = unique!(rand(G, 7)) S = unique!([S1; [a * b for a in S1 for b in S1]]) - subb = SA.SubBasis(S, db) + subb = SA.SubBasis(db, S) a = S1[1] @test subb[a] == 1 @test a in subb diff --git a/test/quadratic_form.jl b/test/quadratic_form.jl index a775b091..2d152790 100644 --- a/test/quadratic_form.jl +++ b/test/quadratic_form.jl @@ -82,7 +82,7 @@ end implicit = SA.MappedBasis(NaturalNumbers(), float, Int) @test 3.0 in implicit @test haskey(implicit, 3) - explicit = SA.SubBasis(1:3, implicit) + explicit = SA.SubBasis(implicit, 1:3) @test 3.0 in explicit @test collect(explicit) == [1.0, 2.0, 3.0] @test haskey(explicit, 3) @@ -109,7 +109,7 @@ end implicit = cheby_basis() mstr = ChebyMStruct(implicit) mt = SA.MTable(implicit, mstr, (0, 0)) - sub = SA.SubBasis(1:3, implicit) + sub = SA.SubBasis(implicit, 1:3) fixed = SA.FixedBasis(implicit; n = 3) a = ChebyPoly(2) b = ChebyPoly(3) From c3e76b5aeba05286196bf5a9a9a532471fad94e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20Legat?= Date: Tue, 29 Apr 2025 13:36:26 +0200 Subject: [PATCH 14/16] Update src/bases.jl Co-authored-by: Marek Kaluba --- src/bases.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bases.jl b/src/bases.jl index b506be51..aa6e6b93 100644 --- a/src/bases.jl +++ b/src/bases.jl @@ -36,7 +36,7 @@ key_type(b::AbstractBasis) = key_type(typeof(b)) abstract type ImplicitBasis{T,I} <: AbstractBasis{T,I} end Implicit bases are bases that contains the product of all its elements. -This makes these bases particularly appropriate as bases of [`AlgebraElement`](@ref)s. +This makes these bases particularly useful to work with [`AlgebraElement`](@ref)s with supports that can not be reasonably bounded. Note that these bases may not explictly store its elements in memory as they may be potentially infinite. """ abstract type ImplicitBasis{T,I} <: AbstractBasis{T,I} end From c6d6c34e074943483ed367f30debf41ee2796d72 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20Legat?= Date: Tue, 29 Apr 2025 13:43:30 +0200 Subject: [PATCH 15/16] Improve FixedBasis docstring --- src/bases_fixed.jl | 68 ++++++++++++++++++++++++++++++++++++---------- 1 file changed, 54 insertions(+), 14 deletions(-) diff --git a/src/bases_fixed.jl b/src/bases_fixed.jl index 9e76261f..52732795 100644 --- a/src/bases_fixed.jl +++ b/src/bases_fixed.jl @@ -1,18 +1,6 @@ # This file is a part of StarAlgebras.jl. License is MIT: https://github.com/JuliaAlgebra/StarAlgebras.jl/blob/main/LICENSE # Copyright (c) 2021-2025: Marek Kaluba, Benoît Legat -""" - mutable struct FixedBasis{T,I,V<:AbstractVector{T}} <: ExplicitBasis{T,I} - elts::V - relts::Dict{T,I} - starof::Vector{I} - end - -Represents a fixed basis of a star algebra, where `elts` is a vector of elements -of type `T`, `relts` is a dictionary mapping elements to their indices, and -`starof` is a vector of indices caching the indices in `elts` of the result of -the star operation on the basis elements. -""" mutable struct FixedBasis{T,I,V<:AbstractVector{T}} <: ExplicitBasis{T,I} elts::V @@ -20,14 +8,66 @@ mutable struct FixedBasis{T,I,V<:AbstractVector{T}} <: starof::Vector{I} end +""" + FixedBasis(elts::AbstractVector) + +Represents a linear basis which is fixed of length (given by `elts`). +The elements of `elts` are assumed to be _linearly independent_ and (as a set) invariant under `star`. +Due to its finiteness, `b::FixedBasis` can be indexed like a vector (by positive integers) and therefore elements expressed in `b` can be represented by simple (sparse) Vectors. + +## Examples + +```julia +julia> import StarAlgebras as SA; + +julia> SA.star(s::String) = reverse(s) # identity is also fine + +julia> b = SA.FixedBasis(["", "a", "b", "aa", "ab", "ba", "bb"]); + +julia> b["a"] +1 + +julia> b["ab"] +4 + +julia> b[4] +"ab" + +julia> b["abc"] +ERROR: KeyError: key "abc" not found +[...] + +julia> A = SA.StarAlgebra(String, SA.DiracMStructure(b, *)) +*-algebra of String + +julia> c = A("a") + A("b") +1·"a" + 1·"b" + +julia> c*A("a") +1·"aa" + 1·"ba" + +julia> A("a")*c +1·"aa" + 1·"ab" + +julia> c*c +1·"aa" + 1·"ab" + 1·"ba" + 1·"bb" + +julia> SA.coeffs(c*c) +7-element SparseArrays.SparseVector{Int64, Int64} with 4 stored entries: + [4] = 1 + [5] = 1 + [6] = 1 + [7] = 1 +``` +""" +FixedBasis(elts::AbstractVector{T}) where {T} = FixedBasis{T,keytype(elts)}(elts) + function FixedBasis{T,I}(elts::AbstractVector{T}) where {T,I} relts = Dict(b => I(idx) for (idx, b) in pairs(elts)) starof = [relts[star(x)] for x in elts] return FixedBasis{T,I,typeof(elts)}(elts, relts, starof) end -FixedBasis(elts::AbstractVector{T}) where {T} = FixedBasis{T,keytype(elts)}(elts) - function FixedBasis{T,I}(basis::AbstractBasis{T}; n::Integer) where {T,I} return FixedBasis{T,I}(collect(Iterators.take(basis, n))) end From 1a2d3665d6a5dc83bbf69be886504cb426df02d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20Legat?= Date: Tue, 29 Apr 2025 13:44:56 +0200 Subject: [PATCH 16/16] Explain why we fix the seed --- test/perm_grp_algebra.jl | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/perm_grp_algebra.jl b/test/perm_grp_algebra.jl index d395fa7e..250e8aac 100644 --- a/test/perm_grp_algebra.jl +++ b/test/perm_grp_algebra.jl @@ -105,6 +105,8 @@ import StarAlgebras as SA end @testset "SubBasis" begin + # If we're unlucky, `a^3` might belong to the basis. + # We fix the seed to be sure we are never in that case. Random.seed!(0) S1 = unique!(rand(G, 7)) S = unique!([S1; [a * b for a in S1 for b in S1]])