From c3bdcab7f176dc1695d8921f96bfe5dd768c0156 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20Legat?= Date: Sun, 15 Dec 2024 10:20:51 +0100 Subject: [PATCH] Add Fixed basis (#52) * Add Fixed basis * Fixes * Fix format * Add doc * Clean up badges * Fix format * Fix --- README.md | 11 ++----- docs/src/index.md | 14 +++++++++ src/MultivariateBases.jl | 1 + src/arithmetic.jl | 12 ++++++++ src/fixed.jl | 65 ++++++++++++++++++++++++++++++++++++++++ src/monomial.jl | 24 +++++++++------ src/polynomial.jl | 12 +++++++- test/fixed.jl | 27 +++++++++++++++++ 8 files changed, 147 insertions(+), 19 deletions(-) create mode 100644 src/fixed.jl create mode 100644 test/fixed.jl diff --git a/README.md b/README.md index 4cfb40e..85a9105 100644 --- a/README.md +++ b/README.md @@ -1,15 +1,12 @@ # Multivariate Bases -| **Documentation** | **Build Status** | **Social** | -|:-----------------:|:----------------:|:----------:| -| [![][docs-stable-img]][docs-stable-url] | [![Build Status][build-img]][build-url] | [![Gitter][gitter-img]][gitter-url] | -| [![][docs-latest-img]][docs-latest-url] | [![Codecov branch][codecov-img]][codecov-url] | [][discourse-url] | +[![][docs-stable-img]][docs-stable-url] [![][docs-latest-img]][docs-latest-url] [![Build Status][build-img]][build-url] [![Codecov branch][codecov-img]][codecov-url] This package provides a standardized API for multivariate polynomial bases based on the [MultivariatePolynomials](https://github.com/JuliaAlgebra/MultivariatePolynomials.jl) API. It defines the following basis: -* `FixedPolynomialBasis`: A polynomial basis described by a list of polynomials. +* `FixedBasis`: A polynomial basis described by a list of polynomials. * Monomial bases: `MonomialBasis` and `ScaledMonomialBasis`. * Orthogonal bases: - Hermite bases: `ProbabilistsHermiteBasis` and `PhysicistsHermiteBasis`. @@ -34,7 +31,3 @@ See the documentation for more details. [build-url]: https://github.com/JuliaAlgebra/MultivariateBases.jl/actions?query=workflow%3ACI [codecov-img]: http://codecov.io/github/JuliaAlgebra/MultivariateBases.jl/coverage.svg?branch=master [codecov-url]: http://codecov.io/github/JuliaAlgebra/MultivariateBases.jl?branch=master - -[gitter-url]: https://gitter.im/JuliaAlgebra/Lobby?utm_source=share-link&utm_medium=link&utm_campaign=share-link -[gitter-img]: https://badges.gitter.im/JuliaAlgebra/Lobby.svg -[discourse-url]: https://discourse.julialang.org/c/domain/opt diff --git a/docs/src/index.md b/docs/src/index.md index bcc9504..05cfe11 100644 --- a/docs/src/index.md +++ b/docs/src/index.md @@ -15,6 +15,13 @@ maxdegree_basis explicit_basis_covering ``` +## Basis elements + +```@docs +Polynomial +SemisimpleElement +``` + ## Monomial basis ```@docs @@ -40,3 +47,10 @@ ChebyshevFirstKind ChebyshevSecondKind Trigonometric ``` + +## Additional basis + +```@docs +FixedBasis +SemisimpleBasis +``` diff --git a/src/MultivariateBases.jl b/src/MultivariateBases.jl index bd23b67..1ff3ba6 100644 --- a/src/MultivariateBases.jl +++ b/src/MultivariateBases.jl @@ -82,5 +82,6 @@ function MA.promote_operation( end include("arithmetic.jl") +include("fixed.jl") end # module diff --git a/src/arithmetic.jl b/src/arithmetic.jl index e64a2e2..d94e626 100644 --- a/src/arithmetic.jl +++ b/src/arithmetic.jl @@ -76,6 +76,18 @@ for op in [:+, :-] end end +function term_element(α, p::Polynomial{B,M}) where {B,M} + return algebra_element( + sparse_coefficients(MP.term(α, p.monomial)), + FullBasis{B,M}(), + ) +end + +# Needed by `SymbolicWedderburn` which multiplies elements of the basis by `Int` +# We'll see if `::Number` is too restrictive +# Should be able to remove once https://github.com/kalmarek/SymbolicWedderburn.jl/issues/88 is closed +Base.:*(α::Number, p::Polynomial) = term_element(α, p) + function MA.operate!(op::Union{typeof(+),typeof(-),typeof(*)}, p::_APL, q::_AE) return MA.operate!(op, p, MP.polynomial(q)) end diff --git a/src/fixed.jl b/src/fixed.jl new file mode 100644 index 0000000..e836fc9 --- /dev/null +++ b/src/fixed.jl @@ -0,0 +1,65 @@ +""" + struct FixedBasis{B,M,T,V} <: + SA.ExplicitBasis{SA.AlgebraElement{Algebra{FullBasis{B,M},B,M},T,V},Int} + elements::Vector{SA.AlgebraElement{Algebra{FullBasis{B,M},B,M},T,V}} + end + +Fixed basis with polynomials `elements`. +""" +struct FixedBasis{B,M,T,V} <: + SA.ExplicitBasis{SA.AlgebraElement{Algebra{FullBasis{B,M},B,M},T,V},Int} + elements::Vector{SA.AlgebraElement{Algebra{FullBasis{B,M},B,M},T,V}} +end + +Base.length(b::FixedBasis) = length(b.elements) +Base.getindex(b::FixedBasis, i::Integer) = b.elements[i] + +function Base.show(io::IO, b::FixedBasis) + print(io, "FixedBasis(") + _show_vector(io, MIME"text/plain"(), b.elements) + print(io, ")") + return +end + +""" + struct SemisimpleBasis{T,I,B<:SA.ExplicitBasis{T,I}} <: SA.ExplicitBasis{T,I} + bases::Vector{B} + end + +Semisimple basis for use with [SymbolicWedderburn](https://github.com/kalmarek/SymbolicWedderburn.jl/). +Its elements are of [`SemisimpleElement`](@ref)s. +""" +struct SemisimpleBasis{T,I,B<:SA.ExplicitBasis{T,I}} <: SA.ExplicitBasis{T,I} + bases::Vector{B} +end + +Base.length(b::SemisimpleBasis) = length(first(b.bases)) + +""" + struct SemisimpleElement{P} + polynomials::Vector{P} + end + +Elements of [`SemisimpleBasis`](@ref). +""" +struct SemisimpleElement{P} + elements::Vector{P} +end +SA.star(p::SemisimpleElement) = SemisimpleElement(SA.star.(p.elements)) + +function Base.getindex(b::SemisimpleBasis, i::Integer) + return SemisimpleElement(getindex.(b.bases, i)) +end + +function Base.show(io::IO, b::SemisimpleBasis) + if length(b.bases) == 1 + print(io, "Simple basis:") + else + print(io, "Semisimple basis with $(length(b.bases)) simple sub-bases:") + end + for basis in b.bases + println(io) + print(io, " ") + print(io, basis) + end +end diff --git a/src/monomial.jl b/src/monomial.jl index a181c3d..a6d3d23 100644 --- a/src/monomial.jl +++ b/src/monomial.jl @@ -258,20 +258,26 @@ function constant_algebra_element(::Type{<:SubBasis{B,M}}, α) where {B,M} ) end -function _show(io::IO, mime::MIME, basis::SubBasis{B}) where {B} - print(io, "SubBasis{$(nameof(B))}") - print(io, "([") +# TODO use Base.show_vector here, maybe by wrapping the `generator` vector +# into something that spits objects wrapped with the `mime` type +function _show_vector(io::IO, mime::MIME, v) + print(io, '[') first = true - # TODO use Base.show_vector here, maybe by wrapping the `generator` vector - # into something that spits objects wrapped with the `mime` type - for mono in basis.monomials + for el in v if !first print(io, ", ") end first = false - show(io, mime, mono) + show(io, mime, el) end - return print(io, "])") + return print(io, ']') +end + +function _show(io::IO, mime::MIME, basis::SubBasis{B}) where {B} + print(io, "SubBasis{$(nameof(B))}(") + _show_vector(io, mime, basis.monomials) + print(io, ')') + return end function Base.show(io::IO, mime::MIME"text/plain", basis::SubBasis) @@ -449,7 +455,7 @@ function SA.coeffs( return SA.SparseCoefficients(_vec(source.monomials), _vec(cfs)) else res = SA.zero_coeffs( - _promote_coef(_promote_coef(valtype(cfs), B1), B2), + _promote_coef(_promote_coef(SA.value_type(cfs), B1), B2), target, ) return SA.coeffs!(res, cfs, source, target) diff --git a/src/polynomial.jl b/src/polynomial.jl index ecadb9e..879cfcf 100644 --- a/src/polynomial.jl +++ b/src/polynomial.jl @@ -1,7 +1,7 @@ # TODO Add to MultivariatePolynomials MP.variables(p::SA.AlgebraElement) = MP.variables(explicit_basis(p)) Base.keytype(p::MP.AbstractPolynomialLike) = MP.monomial_type(p) -Base.valtype(p::MP.AbstractPolynomialLike) = MP.coefficient_type(p) +SA.value_type(p::MP.AbstractPolynomialLike) = MP.coefficient_type(p) #Base.keys(p::MP.AbstractPolynomial) = MP.monomials(p) SA.nonzero_pairs(p::MP.AbstractPolynomialLike) = MP.terms(p) function Base.similar(p::PT, ::Type{T}) where {PT<:MP.AbstractPolynomial,T} @@ -41,6 +41,16 @@ end abstract type AbstractMonomialIndexed end +""" + struct Polynomial{B<:AbstractMonomialIndexed,M<:MP.AbstractMonomial} + monomial::M + function Polynomial{B}(mono::MP.AbstractMonomial) where {B} + return new{B,typeof(mono)}(mono) + end + end + +Polynomial of basis `FullBasis{B,M}()` at index `monomial`. +""" struct Polynomial{B<:AbstractMonomialIndexed,M<:MP.AbstractMonomial} monomial::M function Polynomial{B}(mono::MP.AbstractMonomial) where {B} diff --git a/test/fixed.jl b/test/fixed.jl new file mode 100644 index 0000000..e7b5ab9 --- /dev/null +++ b/test/fixed.jl @@ -0,0 +1,27 @@ +using Test +import StarAlgebras as SA +using MultivariateBases +const MB = MultivariateBases +using DynamicPolynomials + +@testset "FixedBasis" begin + @polyvar x y + x_term = MB.term_element(1, MB.Polynomial{MB.Monomial}(x)) + y_term = MB.term_element(1, MB.Polynomial{MB.Monomial}(y)) + p1 = x_term + im * y_term + p2 = x_term - im * y_term + fixed = MB.FixedBasis([p1, p2]) + @test length(fixed) == 2 + @test fixed[1] ≈ p1 + @test fixed[2] ≈ p2 + @test sprint(show, fixed) == "FixedBasis([$p1, $p2])" + + semi = MB.SemisimpleBasis([MB.FixedBasis([p1]), MB.FixedBasis([p2])]) + @test length(semi) == 1 + @test sprint(show, semi) == + "Semisimple basis with 2 simple sub-bases:\n FixedBasis([$p1])\n FixedBasis([$p2])" + mult = semi[1] + @test all(mult.elements .≈ [p1, p2]) + smult = SA.star(mult) + @test all(smult.elements .≈ [p2, p1]) +end