Skip to content

Commit 2a8661e

Browse files
committed
Initial implementation for the inverse of a function
1 parent c1cfd46 commit 2a8661e

File tree

5 files changed

+62
-4
lines changed

5 files changed

+62
-4
lines changed

Project.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
name = "BasisFunctions"
22
uuid = "4343a256-5453-507d-8aad-01a9d7189916"
33
authors = ["Daan Huybrechs <daan.huybrechs@kuleuven.be>"]
4-
version = "0.7"
4+
version = "0.7.1"
55

66
[deps]
77
BlockArrays = "8e7c35d0-a365-5155-bbbb-fb81a777f24e"

src/bases/dictionary/basisfunction.jl

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,8 @@ innerproduct(φ::AbstractBasisFunction, ψ::AbstractBasisFunction, measure; opti
8989
norm::AbstractBasisFunction; options...) = norm(φ, measure(φ); options...)
9090
norm::AbstractBasisFunction, p; options...) = dict_norm(dictionary(φ), index(φ), p; options...)
9191

92+
moment::AbstractBasisFunction; options...) = dict_moment(dictionary(φ), index(φ); options...)
93+
9294
# The inner product of a basis function with another function: this is an analysis integral
9395
# We introduce a separate function name for this for easier dispatch.
9496
innerproduct::AbstractBasisFunction, g, measure; options...) =

src/bases/dictionary/expansions.jl

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,11 @@ const Expansion2d{S <: Number,T,D,C} = Expansion{SVector{2,S},T,D,C}
3535
const Expansion3d{S <: Number,T,D,C} = Expansion{SVector{3,S},T,D,C}
3636
const Expansion4d{S <: Number,T,D,C} = Expansion{SVector{4,S},T,D,C}
3737

38-
@forward Expansion.dictionary domaintype, prectype, dimension,
39-
size, Span, support, interpolation_grid, numtype,
38+
prectype(F::Type{<:Expansion{S,T}}) where {S,T} = prectype(S,T)
39+
numtype(F::Type{<:Expansion{S,T}}) where {S,T} = numtype(S,T)
40+
41+
@forward Expansion.dictionary domaintype, dimension,
42+
size, Span, support, interpolation_grid,
4043
ncomponents,
4144
measure
4245

@@ -127,7 +130,14 @@ adjoint(f::Expansion) = differentiate(f)
127130

128131
(f::Expansion) = antidifferentiate(f)
129132

130-
roots(f::Expansion) = expansion_roots(dictionary(f), coefficients(f))
133+
function roots(f::Expansion; all = true)
134+
r = expansion_roots(dictionary(f), coefficients(f))
135+
if all
136+
r
137+
else
138+
restrict_to_domain(r, support(f))
139+
end
140+
end
131141

132142
show(io::IO, mime::MIME"text/plain", fun::Expansion) = composite_show(io, mime, fun)
133143
Display.displaystencil(fun::Expansion) = ["Expansion(", dictionary(fun), ", ", coefficients(fun), ")"]

src/computations/approximation.jl

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,3 +132,38 @@ end
132132

133133
default_leastsquares::Dictionary, gb::GridBasis, T=operatoreltype(Φ,gb); options...) =
134134
QR_solver(ArrayOperator(leastsquares_matrix(Φ, grid(gb), T), Φ, gb))
135+
136+
137+
########################
138+
# Inverse of a function
139+
########################
140+
141+
"""
142+
inversefunction(F[, domain; n])
143+
144+
Compute an approximation to the inverse of `F`, using an appropriate basis with `n` degrees of freedom.
145+
"""
146+
inversefunction(F::Expansion; args...) = inversefunction(F, support(F); args...)
147+
148+
function inversefunction(F, domain::AbstractInterval; n = 2*length(F))
149+
Fd = differentiate(F)
150+
if length(roots(Fd; all=false)) > 0
151+
throw(ArgumentError("Function is not invertible on its domain."))
152+
end
153+
154+
# compute the value t such that F(t)=z.
155+
function inversevalue(z)
156+
r = roots(F - z; all=false)
157+
if length(r) != 1
158+
throw(ArgumentError("No unique inverse value."))
159+
end
160+
r[1]
161+
end
162+
163+
a = leftendpoint(domain)
164+
b = rightendpoint(domain)
165+
A = F(a)
166+
B = F(b)
167+
G = ChebyshevT(n) (A..B)
168+
Expansion(G, approximation(G) * inversevalue)
169+
end

src/util/common.jl

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,3 +132,14 @@ export Domain1d, Domain2d, Domain3d, Domain4d
132132
iscompatible(map1::AbstractMap, map2::AbstractMap) = map1==map2
133133
iscompatible(map1::AffineMap, map2::AffineMap) = (map1.A map2.A) && (map1.b map2.b)
134134
iscompatible(domain1::Domain, domain2::Domain) = domain1 == domain2
135+
136+
"Filter the given points by leaving out all points that are not an element of the given domain."
137+
function restrict_to_domain(x::AbstractVector, d; tol = DomainSets.domain_tolerance(d))
138+
checkdomain(d)
139+
filter(t->approx_in(t, d, tol), x)
140+
end
141+
142+
function restrict_to_domain(x::AbstractVector{Complex{T}}, d::AbstractInterval{T}; tol = DomainSets.domain_tolerance(d)) where {T}
143+
x1 = real(filter(t->abs(imag(t))<tol, x))
144+
restrict_to_domain(x1, d; tol)
145+
end

0 commit comments

Comments
 (0)