Skip to content

Commit 04dc4bb

Browse files
authored
Add orthonormal basis (#22)
* Add orthonormal basis * Fix format
1 parent a0a7e4d commit 04dc4bb

File tree

8 files changed

+161
-16
lines changed

8 files changed

+161
-16
lines changed

docs/src/index.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ AbstractPolynomialBasis
1515
maxdegree_basis
1616
basis_covering_monomials
1717
FixedPolynomialBasis
18+
OrthonormalCoefficientsBasis
1819
```
1920

2021
## Monomial basis

src/MultivariateBases.jl

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ include("monomial.jl")
1313
include("scaled.jl")
1414

1515
export FixedPolynomialBasis,
16+
OrthonormalCoefficientsBasis,
1617
AbstractMultipleOrthogonalBasis,
1718
ProbabilistsHermiteBasis,
1819
PhysicistsHermiteBasis,
@@ -31,6 +32,7 @@ export generators,
3132
include("fixed.jl")
3233

3334
import LinearAlgebra
35+
include("orthonormal.jl")
3436
include("orthogonal.jl")
3537
include("hermite.jl")
3638
include("laguerre.jl")

src/orthogonal.jl

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -209,16 +209,10 @@ function _integral(
209209
return sum([_integral(t, basis_type) for t in MP.terms(p)])
210210
end
211211

212-
function MP.coefficients(
213-
p,
214-
basis::AbstractMultipleOrthogonalBasis;
215-
check = true,
216-
)
212+
function MP.coefficients(p, basis::AbstractMultipleOrthogonalBasis)
217213
B = typeof(basis)
218-
coeffs = [
214+
return [
219215
LinearAlgebra.dot(p, el, B) / LinearAlgebra.dot(el, el, B) for
220216
el in basis
221217
]
222-
idx = findall(c -> !isapprox(c, 0; atol = 1e-10), coeffs)
223-
return coeffs[idx]
224218
end

src/orthonormal.jl

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
"""
2+
struct OrthonormalCoefficientsBasis{PT<:MP.AbstractPolynomialLike, PV<:AbstractVector{PT}} <: AbstractPolynomialBasis
3+
polynomials::PV
4+
end
5+
6+
Polynomial basis with the polynomials of the vector `polynomials` that are
7+
orthonormal with respect to the inner produce derived from the inner product
8+
of their coefficients.
9+
For instance, `FixedPolynomialBasis([1, x, 2x^2-1, 4x^3-3x])` is the Chebyshev
10+
polynomial basis for cubic polynomials in the variable `x`.
11+
"""
12+
struct OrthonormalCoefficientsBasis{
13+
PT<:MP.AbstractPolynomialLike,
14+
PV<:AbstractVector{PT},
15+
} <: AbstractPolynomialVectorBasis{PT,PV}
16+
polynomials::PV
17+
end
18+
19+
function LinearAlgebra.dot(
20+
p::MP.AbstractPolynomialLike{S},
21+
q::MP.AbstractPolynomialLike{T},
22+
::Type{<:OrthonormalCoefficientsBasis},
23+
) where {S,T}
24+
s = zero(MA.promote_operation(*, S, T))
25+
terms_p = MP.terms(p)
26+
terms_q = MP.terms(q)
27+
tsp = iterate(terms_p)
28+
tsq = iterate(terms_q)
29+
while !isnothing(tsp) && !isnothing(tsq)
30+
tp, sp = tsp
31+
tq, sq = tsq
32+
cmp = MP.compare(MP.monomial(tp), MP.monomial(tq))
33+
if iszero(cmp)
34+
s += conj(MP.coefficient(tp)) * MP.coefficient(tq)
35+
tsp = iterate(terms_p, sp)
36+
tsq = iterate(terms_q, sq)
37+
elseif cmp < 0
38+
tsp = iterate(terms_p, sp)
39+
else
40+
tsq = iterate(terms_q, sq)
41+
end
42+
end
43+
return s
44+
end
45+
46+
function MP.coefficients(p, basis::OrthonormalCoefficientsBasis)
47+
return [LinearAlgebra.dot(q, p, typeof(basis)) for q in generators(basis)]
48+
end

test/fixed.jl

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,6 @@ using DynamicPolynomials
1414
@test collect(basis) == gens
1515
@test generators(basis) == gens
1616
@test length(basis) == 2
17-
@test firstindex(basis) == 1
18-
@test lastindex(basis) == 2
1917
@test mindegree(basis) == 0
2018
@test mindegree(basis, x) == 0
2119
@test maxdegree(basis) == 2

test/monomial.jl

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,6 @@ using DynamicPolynomials
1212
@test basis[2] == x
1313
@test generators(basis) == [y, x]
1414
@test collect(basis) == [y, x]
15-
@test length(basis) == 2
16-
@test firstindex(basis) == 1
17-
@test lastindex(basis) == 2
1815
@test variables(basis) == [x, y]
1916
@test nvariables(basis) == 2
2017
@test sprint(show, basis) == "MonomialBasis([y, x])"

test/orthonormal.jl

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
using Test
2+
using MultivariateBases
3+
using DynamicPolynomials
4+
5+
@polyvar x y
6+
7+
@testset "Polynomials" begin
8+
gens = [1 + x + y + x * y, 1 - x + y - x * y] / 2
9+
basis = OrthonormalCoefficientsBasis(gens)
10+
@test iszero(dot(gens[1], gens[2], OrthonormalCoefficientsBasis))
11+
coefficient_test(basis, [2, -3])
12+
coefficient_test(basis, [-2im, 1 + 5im])
13+
coefficient_test(basis, [1im, 2im])
14+
@test polynomial_type(basis, Int) == polynomial_type(x, Float64)
15+
@test polynomial(one, basis) == 1 + y
16+
@test basis[1] == gens[1]
17+
@test basis[2] == gens[2]
18+
@test collect(basis) == gens
19+
@test generators(basis) == gens
20+
@test length(basis) == 2
21+
@test mindegree(basis) == 0
22+
@test mindegree(basis, x) == 0
23+
@test mindegree(basis, y) == 0
24+
@test maxdegree(basis) == 2
25+
@test maxdegree(basis, x) == 1
26+
@test maxdegree(basis, y) == 1
27+
@test extdegree(basis) == (0, 2)
28+
@test extdegree(basis, x) == (0, 1)
29+
@test extdegree(basis, y) == (0, 1)
30+
@test variables(basis) == [x, y]
31+
@test nvariables(basis) == 2
32+
@test sprint(show, basis) ==
33+
"OrthonormalCoefficientsBasis([0.5 + 0.5y + 0.5x + 0.5xy, 0.5 + 0.5y - 0.5x - 0.5xy])"
34+
@test sprint(print, basis) ==
35+
"OrthonormalCoefficientsBasis([0.5 + 0.5*y + 0.5*x + 0.5*x*y, 0.5 + 0.5*y - 0.5*x - 0.5*x*y])"
36+
b2 = basis[2:2]
37+
@test length(b2) == 1
38+
@test b2[1] == gens[2]
39+
b3 = basis[2:1]
40+
@test isempty(b3)
41+
end
42+
@testset "Linear" begin
43+
basis = OrthonormalCoefficientsBasis([x, y])
44+
@test polynomial_type(basis, Int) == polynomial_type(x, Int)
45+
@test polynomial(identity, basis) == x + 2y
46+
end
47+
@testset "One variable" begin
48+
basis = OrthonormalCoefficientsBasis([x])
49+
@test polynomial_type(basis, Int) == polynomial_type(x, Int)
50+
@test polynomial(i -> 5, basis) == 5x
51+
@test typeof(polynomial(i -> 5, basis)) == polynomial_type(basis, Int)
52+
@test typeof(polynomial(ones(Int, 1, 1), basis, Int)) <:
53+
AbstractPolynomial{Int}
54+
@test typeof(polynomial(ones(Int, 1, 1), basis, Float64)) <:
55+
AbstractPolynomial{Float64}
56+
end
57+
@testset "Complex" begin
58+
for a in [1, -1, im, -im]
59+
basis = OrthonormalCoefficientsBasis([a * x])
60+
@test 5x^2 ==
61+
@inferred polynomial(5ones(Int, 1, 1), basis, Complex{Int})
62+
@test 5x^2 == @inferred polynomial(5ones(Int, 1, 1), basis, Int)
63+
coefficient_test(basis, [2])
64+
coefficient_test(basis, [-2im])
65+
coefficient_test(basis, [1 + 5im])
66+
end
67+
end
68+
@testset "Empty" begin
69+
basis = OrthonormalCoefficientsBasis(typeof(x + 1)[])
70+
@test isempty(basis)
71+
@test isempty(eachindex(basis))
72+
p = @inferred polynomial(zeros(Int, 0, 0), basis, Int)
73+
@test iszero(p)
74+
end
75+
76+
@testset "Enumerate" begin
77+
monos = [1, x, y^2]
78+
basis = OrthonormalCoefficientsBasis(monos)
79+
for (i, e) in enumerate(basis)
80+
@test e == monos[i]
81+
end
82+
end

test/runtests.jl

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ function api_test(B::Type{<:AbstractPolynomialBasis}, degree)
1212
]
1313
n = binomial(2 + degree, 2)
1414
@test length(basis) == n
15+
@test firstindex(basis) == 1
16+
@test lastindex(basis) == n
1517
@test typeof(copy(basis)) == typeof(basis)
1618
@test nvariables(basis) == 2
1719
@test variables(basis) == x
@@ -87,13 +89,31 @@ function orthogonal_test(
8789
end
8890
end
8991

92+
function coefficient_test(basis::AbstractPolynomialBasis, p, coefs; kwargs...)
93+
cc = coefficients(p, basis)
94+
@test isapprox(coefs, cc; kwargs...)
95+
@test isapprox(p, polynomial(cc, basis); kwargs...)
96+
end
97+
98+
function coefficient_test(
99+
basis::AbstractPolynomialBasis,
100+
coefs::AbstractVector;
101+
kwargs...,
102+
)
103+
return coefficient_test(
104+
basis,
105+
sum(generators(basis) .* coefs),
106+
coefs;
107+
kwargs...,
108+
)
109+
end
110+
90111
function coefficient_test(B::Type{<:AbstractPolynomialBasis}, coefs; kwargs...)
91112
@polyvar x y
92113
p = x^4 * y^2 + x^2 * y^4 - 3 * x^2 * y^2 + 1
93114
basis = basis_covering_monomials(B, monomials(p))
94-
cc = coefficients(p, basis)
95-
@test isapprox(coefs, cc; kwargs...)
96-
@test isapprox(p, polynomial(cc, basis); kwargs...)
115+
coefficient_test(basis, p, coefs; kwargs...)
116+
return
97117
end
98118

99119
@testset "Monomial" begin
@@ -105,6 +125,9 @@ end
105125
@testset "Fixed" begin
106126
include("fixed.jl")
107127
end
128+
@testset "Orthonormal" begin
129+
include("orthonormal.jl")
130+
end
108131
@testset "Hermite" begin
109132
include("hermite.jl")
110133
end

0 commit comments

Comments
 (0)