Skip to content

Commit 93fd834

Browse files
authored
Backport isconstant (#637)
1 parent fa060bd commit 93fd834

File tree

6 files changed

+49
-14
lines changed

6 files changed

+49
-14
lines changed

src/Fun.jl

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,8 @@ julia> coefficients(f, Legendre()) ≈ [0, 0, 1]
107107
true
108108
```
109109
"""
110-
function coefficients(f::Fun,msp::Space)
110+
coefficients(f::Fun,msp::Space) = _coefficients(f::Fun,msp::Space)
111+
function _coefficients(f::Fun,msp::Space)
111112
#zero can always be converted
112113
fc = f.coefficients
113114
if ncoefficients(f) == 0 || (ncoefficients(f) == 1 && fc[1] == 0)
@@ -777,9 +778,10 @@ isapprox(g::Number, f::Fun; kw...) = isapprox(g*ones(space(f)), f; kw...)
777778
isreal(f::Fun{<:RealSpace,<:Real}) = true
778779
isreal(f::Fun) = false
779780

780-
iszero(f::Fun) = all(iszero,f.coefficients)
781-
781+
iszero(f::Fun) = all(iszero, coefficients(f)) || all(iszero, values(f))
782782

783+
# Deliberately not named isconst or isconstant to avoid conflicts with Base or DomainSets
784+
isconstantfun(f::Fun) = iszero(f - first(f))
783785

784786
# sum, integrate, and idfferentiate are in CalculusOperator
785787

src/Operators/Operator.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -197,7 +197,7 @@ opissymmetric(::OperatorStyle, A) = false
197197
for f in [:domainspace, :rangespace]
198198
opf = Symbol(:op, f)
199199
@eval begin
200-
$opf(::OperatorStyle, A) = error("Override domainspace for $(typeof(A))")
200+
$opf(::OperatorStyle, A) = error("Override $($f) for $(typeof(A))")
201201
$opf(S::StyleConflict, A) = $opf(dominantstyle(S, $f, A), A)
202202
end
203203
end

src/Spaces/ConstantSpace.jl

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,8 @@ ones(S::Union{AnyDomain,UnsetSpace}) = ones(ConstantSpace())
8181
zeros(S::AnyDomain) = zero(ConstantSpace())
8282
zero(S::UnsetSpace) = zero(ConstantSpace())
8383
_first_or_zero(f::AbstractVector) = get(f, 1, zero(eltype(f)))
84-
function evaluate(f::AbstractVector,::ConstantSpace,x...)
84+
function evaluate(f::AbstractVector, sp::ConstantSpace, x)
85+
x in domain(sp) || return zero(eltype(f))
8586
_first_or_zero(f)
8687
end
8788
evaluate(f::AbstractVector,::ZeroSpace,x...)=zero(eltype(f))
@@ -143,6 +144,10 @@ function getindex(C::ConcreteConversion{CS,S,T},k::Integer,j::Integer) where {CS
143144
k ncoefficients(on) ? strictconvert(T,on.coefficients[k]) : zero(T)
144145
end
145146

147+
function coefficients(f::Fun, msp::ConstantSpace)
148+
isconstantfun(f) || throw(ArgumentError("cannot convert a non-constant Fun to ConstantSpace"))
149+
_coefficients(f, msp)
150+
end
146151

147152
coefficients(f::AbstractVector,sp::ConstantSpace{Segment{SVector{2,TT}}},
148153
ts::TensorSpace{SV,DD}) where {TT,SV,DD<:EuclideanDomain{2}} =
@@ -155,6 +160,9 @@ coefficients(f::AbstractVector, sp::ConstantSpace{<:Domain{<:Number}}, ts::Space
155160
coefficients(f::AbstractVector, sp::ConstantSpace, ts::Space) =
156161
f[1]*ones(ts).coefficients
157162

163+
# a Fun{<:ConstantSpace} corresponds to a constant value within the domain, irrespective of the domain
164+
first(f::Fun{<:ConstantSpace}) = convert(Number, f)
165+
last(f::Fun{<:ConstantSpace}) = convert(Number, f)
158166

159167
########
160168
# Evaluation

src/Spaces/DiracSpace.jl

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -79,19 +79,20 @@ Fun(::typeof(identity), S::DiracSpace) = Fun(PointSpace(S.points),S.points)
7979
transform(S::PointSpace,v::AbstractVector,plan...) = v
8080
values(f::Fun{S}) where S<:PointSpace = coefficient(f,:)
8181

82-
function evaluate(f::AbstractVector,PS::PointSpace,x::Number)
83-
p = findfirst(y->isapprox(x,y),PS.points)
82+
first(f::Fun{<:PointSpace}) = coefficients(f)[1]
83+
last(f::Fun{<:PointSpace}) = coefficients(f)[end]
84+
85+
function evaluate(f::AbstractVector, PS::PointSpace, x)
86+
p = findfirst((convert(Number,x)), PS.points)
8487
if p === nothing
8588
zero(eltype(f))
8689
else
8790
f[p]
8891
end
8992
end
9093

91-
function evaluate(f::AbstractVector, PS::DiracSpace, x::Number)
92-
x domain(PS) && return zero(eltype(f))
93-
94-
p = findfirst(y->isapprox(x,y), PS.points)
94+
function evaluate(f::AbstractVector, PS::DiracSpace, x)
95+
p = findfirst((convert(Number,x)), PS.points)
9596
if p === nothing
9697
zero(eltype(f))
9798
else
@@ -100,7 +101,7 @@ function evaluate(f::AbstractVector, PS::DiracSpace, x::Number)
100101
end
101102

102103
Base.sum(f::Fun{DS}) where DS<:DiracSpace =
103-
sum(f.coefficients[1:dimension(space(f))])
104+
sum(@view f.coefficients[1:dimension(space(f))])
104105

105106
DiracDelta(x::Number)=Fun(DiracSpace(x),[1.])
106107
DiracDelta()=DiracDelta(0.)

test/SpacesTest.jl

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,20 @@
11
using ApproxFunBase
2-
using Test
32
using ApproxFunBase: PointSpace, HeavisideSpace, PiecewiseSegment, dimension, SVector, checkpoints, AnyDomain
4-
using StaticArrays
53
using BandedMatrices: rowrange, colrange, BandedMatrix
4+
using DomainSets: Point
65
using LinearAlgebra
6+
using StaticArrays
7+
using Test
78

89
@testset "Spaces" begin
910
@testset "PointSpace" begin
1011
@test eltype(domain(PointSpace([0,0.1,1])) ) == Float64
1112

1213
f = @inferred Fun(x->(x-0.1),PointSpace([0,0.1,1]))
1314
@test roots(f) == [0.1]
15+
@test first(f) == -0.1
16+
@test last(f) == 0.9
17+
@test f(Point(0)) == -0.1
1418

1519
a = @inferred Fun(exp, space(f))
1620
@test f/a == @inferred Fun(x->(x-0.1)*exp(-x),space(f))
@@ -204,6 +208,11 @@ using LinearAlgebra
204208
F = Fun{typeof(PointSpace(1:3)), Float32}
205209
@test ApproxFunBase.cfstype(F) == Float32
206210
end
211+
212+
@testset "isconstantfun" begin
213+
f = Fun(PointSpace(1:4), ones(4))
214+
@test ApproxFunBase.isconstantfun(f)
215+
end
207216
end
208217

209218
@testset "DiracSpace" begin
@@ -212,6 +221,8 @@ using LinearAlgebra
212221
@test f(0.5) == 0
213222
@test f(5) == 0
214223
@test isinf(f(0))
224+
@test isinf(f(Point(0)))
225+
@test sum(f) == 6
215226
end
216227

217228
@testset "Derivative operator for HeavisideSpace" begin
@@ -317,6 +328,12 @@ using LinearAlgebra
317328
@test g >= f
318329
@test 1 < f < 3
319330
@test differentiate(f) == Fun(0, ConstantSpace(0..1))
331+
@test f(-1) == 0
332+
@test first(f) == last(f) == 2
333+
@test ApproxFunBase.isconstantfun(f)
334+
335+
f = Fun(2, ConstantSpace())
336+
@test first(f) == last(f) == 2
320337

321338
@test maxspace(ConstantSpace(Point(1)), ConstantSpace(Point(2))) == ConstantSpace(Point(1) Point(2))
322339
@test maxspace(ConstantSpace(Point(1)), ConstantSpace(AnyDomain())) == ConstantSpace(Point(1))

test/runtests.jl

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -795,3 +795,10 @@ include("show.jl")
795795

796796
@test @inferred(chebyshev_clenshaw(BigInt[1], 1)) == 1
797797
end
798+
799+
@testset "Unimplemented functionality errors" begin
800+
struct MyOperator{T} <: ApproxFunBase.Operator{T} end
801+
X = MyOperator{Float64}();
802+
@test_throws ErrorException("Override domainspace for $(typeof(X))") domainspace(X)
803+
@test_throws ErrorException("Override rangespace for $(typeof(X))") rangespace(X)
804+
end

0 commit comments

Comments
 (0)