From 1151ac7bd34ae6b3297049481c3c62d41a6c34f8 Mon Sep 17 00:00:00 2001 From: Marek Kaluba Date: Sat, 19 Jun 2021 00:59:35 +0200 Subject: [PATCH] StarAlgebras (+their elements) based on Basis and MStructures --- src/GroupRings.jl | 6 +++ src/algebra_elts.jl | 44 ++++++++++++++++ src/show.jl | 35 +++++++++++++ src/types.jl | 116 ++++++++++++++++++++++++++++++++++++++++++ test/cachedmtables.jl | 30 +++++++++++ test/constructors.jl | 47 +++++++++++++++++ test/runtests.jl | 1 + 7 files changed, 279 insertions(+) create mode 100644 src/algebra_elts.jl create mode 100644 src/show.jl create mode 100644 src/types.jl create mode 100644 test/constructors.jl diff --git a/src/GroupRings.jl b/src/GroupRings.jl index 28df494..f2d3b7b 100644 --- a/src/GroupRings.jl +++ b/src/GroupRings.jl @@ -565,12 +565,18 @@ end module New +using SparseArrays +import LinearAlgebra include("bases.jl") include("mstructures.jl") include("mtables.jl") +include("types.jl") +include("algebra_elts.jl") +include("show.jl") + end end # of module GroupRings diff --git a/src/algebra_elts.jl b/src/algebra_elts.jl new file mode 100644 index 0000000..d4febc7 --- /dev/null +++ b/src/algebra_elts.jl @@ -0,0 +1,44 @@ +function Base.hash(a::AlgebraElement, h::UInt) + return hash(coeffs(a), hash(parent(a), hash(typeof(a), h))) +end +function Base.:(==)(X::AlgebraElement, Y::AlgebraElement) + parent(X) === parent(Y) || return false + return coeffs(X) == coeffs(Y) +end + +Base.getindex(a::AlgebraElement, i::Integer) = coeffs(a)[i] +Base.getindex(a::AlgebraElement{<:StarAlgebra{O,T}}, x::T) where {O,T} = + (b = basis(parent(a)); a[b[x]]) + +# call overload: +(a::AlgebraElement)(x) = a[x] + +Base.setindex!(a::AlgebraElement, v, i::Integer) = a.coeffs[i] = v + +function Base.setindex!(a::AlgebraElement{<:StarAlgebra{O,T}}, v, t::T) where {O,T} + b = basis(parent(a)) + return a[b[t]] = v +end + + +# AlgebraElement specific functions + +supp_ind(a::AlgebraElement) = findall(!iszero, coeffs(a)) +supp_ind(a::AlgebraElement{A,T,<:SparseVector}) where {A,T} = coeffs(a).nzind +supp(a::AlgebraElement) = (b = basis(parent(a)); [b[i] for i in supp_ind(a)]) + +function star(X::AlgebraElement) + A = parent(X) + b = basis(A) + supp_X = supp_ind(X) + idcs = similar(supp_X) + vals = similar(idcs, eltype(X)) + for (i, idx) in enumerate(supp_X) + idcs[i] = b[star(b[idx])] + vals[i] = X[idx] + end + return AlgebraElement(sparsevec(idcs, vals, length(b)), A) +end + +LinearAlgebra.norm(a::AlgebraElement, p) = LinearAlgebra.norm(coeffs(a), p) +aug(a::AlgebraElement) = sum(coeffs(a)) diff --git a/src/show.jl b/src/show.jl new file mode 100644 index 0000000..0caf218 --- /dev/null +++ b/src/show.jl @@ -0,0 +1,35 @@ +Base.show(io::IO, A::AbstractStarAlgebra) = print(io, "*-Algebra of $(object(A))") + +__prints_with_minus(x) = false +__prints_with_minus(x::Real) = x < 0 + +function Base.show(io::IO, a::AlgebraElement) + A = parent(a) + if iszero(a) + T = eltype(a) + print(io, "$(zero(T))*$(one(object(A)))") + elseif hasbasis(A) + elts = String[] + nzeros = findall(!iszero, coeffs(a)) + for (counter, idx) in enumerate(nzeros) + c, elt = coeffs(a)[idx], basis(A)[idx] + if counter == 1 + print(io, c, '·', elt) + length(nzeros) > 1 && print(io, ' ') + else + __prints_with_minus(c) || print(io, '+') + print(io, c, '·', elt) + counter == length(nzeros) || print(io, ' ') + end + end + else + println(io, "Algebra element without defined basis") + show(io, MIME("text/plain"), a.coeffs) + end +end + +function Base.show(io::IO, ::MIME"text/plain", mstr::TrivialMStructure) + Tw = _istwisted(mstr) + l = length(basis(mstr)) + print(io, "TrivialMStructure{$Tw} over basis with $l elements") +end diff --git a/src/types.jl b/src/types.jl new file mode 100644 index 0000000..cf4eeca --- /dev/null +++ b/src/types.jl @@ -0,0 +1,116 @@ +abstract type AbstractStarAlgebra end + +struct StarAlgebra{O,T,M<:MultiplicativeStructure,B<:AbstractBasis{T}} <: + AbstractStarAlgebra + object::O + mstructure::M + basis::B + + function StarAlgebra(obj, basis::AbstractBasis, mstr::MultiplicativeStructure) + O = typeof(obj) + T = eltype(basis) + M = typeof(mstr) + B = typeof(basis) + + return new{O,T,M,B}(obj, mstr, basis) + end + + function StarAlgebra(obj, mstr::MultiplicativeStructure) + O = typeof(obj) + T = Symbol + M = typeof(mstr) + B = Basis{T,Int} + + return new{O,T,M,B}(obj, mstr) + end +end + +# TrivialMStructure: +StarAlgebra(obj, basis::AbstractBasis) = StarAlgebra{false}(obj, basis) + +function StarAlgebra{Tw}(obj, basis::AbstractBasis) where {Tw} + mstr = TrivialMStructure{Tw}(basis) + return StarAlgebra(obj, basis, mstr) +end + +# CachedMStructure: +StarAlgebra(obj, basis::AbstractBasis, cache_size::Tuple{<:Integer,Integer}) = + StarAlgebra{false}(obj, basis, cache_size) + +function StarAlgebra{Tw}( + obj, + basis::AbstractBasis, + cache_size::Tuple{<:Integer,Integer}, +) where {Tw} + mstr = CachedMTable{Tw}(basis, table_size = cache_size) + return StarAlgebra(obj, basis, mstr) +end + +hasbasis(A::StarAlgebra) = isdefined(A, :basis) + +basis(A::StarAlgebra) = A.basis +object(A::StarAlgebra) = A.object +# Base.eltype(A::StarAlgebra{O,B}) where {O,B} = eltype(B) + + +struct AlgebraElement{A,T,V<:AbstractVector{T}} + coeffs::V + parent::A + + function AlgebraElement(coeffs::AbstractVector, A::AbstractStarAlgebra) + if hasbasis(A) + @assert length(coeffs) == length(basis(A)) + end + return new{typeof(A),eltype(coeffs),typeof(coeffs)}(coeffs, A) + end +end + +coeffs(a::AlgebraElement) = a.coeffs +Base.parent(a::AlgebraElement) = a.parent +Base.eltype(a::AlgebraElement) = eltype(coeffs(a)) + + +### constructing elements + +function Base.zero(A::AbstractStarAlgebra, T = Int) + if hasbasis(A) + return AlgebraElement(spzeros(T, length(basis(A))), A) + else + return AlgebraElement(spzeros(T, maximum(A.mstructure))) + end +end + +Base.one(A::AbstractStarAlgebra, T = Int) = A(one(object(A)), T) + +Base.zero(a::AlgebraElement) = zero(parent(a)) +Base.one(a::AlgebraElement) = one(parent(a)) + +Base.iszero(a::AlgebraElement) = iszero(coeffs(a)) + +function Base.isone(a::AlgebraElement, T = Int) + b = basis(parent(a)) + k = findfirst(!iszero, coeffs(a)) + k === nothing && return false + isone(a[k]) || return false + return isone(b[k]) +end + +function (A::AbstractStarAlgebra)(elt, T = Int) + if hasbasis(A) + b = basis(A) + i = b[elt] + return AlgebraElement(sparsevec([i], [one(T)], length(b)), A) + else + throw("Cannot coerce $elt to an algebra without defined basis") + end +end + +function (A::AbstractStarAlgebra)(x::Number) + g = one(object(A)) + res = A(g, typeof(x)) + res = mul!(res, res, x) + return res +end + +Base.similar(X::AlgebraElement, ::Type{T} = eltype(X)) where {T} = + AlgebraElement(similar(coeffs(X), T), parent(X)) diff --git a/test/cachedmtables.jl b/test/cachedmtables.jl index 7a08398..6da5d1e 100644 --- a/test/cachedmtables.jl +++ b/test/cachedmtables.jl @@ -30,3 +30,33 @@ @test tmstr[3, 2] == b[inv(b[3])*b[2]] end +@testset "Group Algebra caching" begin + G = SymmetricGroup(3) + b = New.Basis{UInt8}(collect(G)) + l = length(b) + + RG = New.StarAlgebra(G, b, (l, l)) + @test RG isa New.StarAlgebra + + D = ((l + 1) * one(RG) - sum(RG(g) for g in b)) // 6 + @test D isa New.AlgebraElement + g = RG(b[1]) + @test isone(g) + @test one(RG) == g + @test iszero(zero(RG)) + @test 0 * g == zero(RG) + @test iszero(0 * g) + + h = RG(b[3]) + + @test D * one(RG) == D + + @test all(New.supp(D) .== b) + + @test one(RG) * D == D + @test any(iszero, RG.mstructure.table) + + @test D * D isa New.AlgebraElement + + @test all(!iszero, RG.mstructure.table) +end diff --git a/test/constructors.jl b/test/constructors.jl new file mode 100644 index 0000000..359d58b --- /dev/null +++ b/test/constructors.jl @@ -0,0 +1,47 @@ +@testset "Algebra and Elements Constructors" begin + G = SymmetricGroup(3) + b = New.Basis{UInt8}(collect(G)) + l = length(b) + + RG = New.StarAlgebra(G, b, (l, l)) + + a = rand(6) + + @test New.AlgebraElement(a, RG) isa New.AlgebraElement + @test all(RG(g) isa New.AlgebraElement{typeof(RG)} for g in G) + + @test_throws AssertionError New.AlgebraElement([1,2,3], RG) + @test New.AlgebraElement([1,2,3,0,0,0], RG) isa New.AlgebraElement + + p = G([2,3,1]) + a = RG(p) + @test New.coeffs(a) isa SparseVector + @test New.coeffs(a)[5] == 1 + @test all(New.coeffs(a)[i] == 0 for i in 1:6 if i ≠ 5) + @test a(p) == 1 + @test all(a(g) == 0 for g in G if g != p) + + @test sprint(show, a) == "1·(1,2,3)" + @test sprint(show, -a) == "-1·(1,2,3)" + + @test New.AlgebraElement([0,0,0,0,1,0], RG) == a + + @test New.supp(a) == [p] + @test New.supp_ind(a) == [5] + + s = one(G) + @test a(s) == 0 + + a[s] = 2 + + @test New.coeffs(a)[1] == 2 + @test a[1] == 2 + @test a(s) == 2 + + @test New.supp(a) == [s, p] + @test New.supp_ind(a) == [1, 5] + + @test sprint(show, a) == "2·() +1·(1,2,3)" + @test sprint(show, -a) == "-2·() -1·(1,2,3)" + @test sprint(show, New.AlgebraElement([2,0,0,0,-1,0], RG)) == "2·() -1·(1,2,3)" +end diff --git a/test/runtests.jl b/test/runtests.jl index 5e7a718..f607795 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -10,6 +10,7 @@ using GroupRings.New New.star(p::Generic.Perm) = inv(p) + include("constructors.jl") include("cachedmtables.jl") end