Skip to content

Commit

Permalink
Add Fixed basis (#52)
Browse files Browse the repository at this point in the history
* Add Fixed basis

* Fixes

* Fix format

* Add doc

* Clean up badges

* Fix format

* Fix
  • Loading branch information
blegat authored Dec 15, 2024
1 parent 37d9cf3 commit c3bdcab
Show file tree
Hide file tree
Showing 8 changed files with 147 additions and 19 deletions.
11 changes: 2 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
@@ -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] | [<img src="https://upload.wikimedia.org/wikipedia/commons/thumb/a/af/Discourse_logo.png/799px-Discourse_logo.png" width="64">][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`.
Expand All @@ -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
14 changes: 14 additions & 0 deletions docs/src/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,13 @@ maxdegree_basis
explicit_basis_covering
```

## Basis elements

```@docs
Polynomial
SemisimpleElement
```

## Monomial basis

```@docs
Expand All @@ -40,3 +47,10 @@ ChebyshevFirstKind
ChebyshevSecondKind
Trigonometric
```

## Additional basis

```@docs
FixedBasis
SemisimpleBasis
```
1 change: 1 addition & 0 deletions src/MultivariateBases.jl
Original file line number Diff line number Diff line change
Expand Up @@ -82,5 +82,6 @@ function MA.promote_operation(
end

include("arithmetic.jl")
include("fixed.jl")

end # module
12 changes: 12 additions & 0 deletions src/arithmetic.jl
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
65 changes: 65 additions & 0 deletions src/fixed.jl
Original file line number Diff line number Diff line change
@@ -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
24 changes: 15 additions & 9 deletions src/monomial.jl
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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)
Expand Down
12 changes: 11 additions & 1 deletion src/polynomial.jl
Original file line number Diff line number Diff line change
@@ -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}
Expand Down Expand Up @@ -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}
Expand Down
27 changes: 27 additions & 0 deletions test/fixed.jl
Original file line number Diff line number Diff line change
@@ -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

0 comments on commit c3bdcab

Please sign in to comment.