Skip to content

Commit 67bed18

Browse files
jishnubclaude
andauthored
Define values for ArraySpace (#688)
`values(f)` errored for an array-valued `Fun`, which broke `iszero` since it started consulting `values` in #635. Three separate causes: * `itransform` was only defined for `VectorSpace`, so a `MatrixSpace` fell through to the generic `Space` method and hit `checkcanonicalspace`, which errors as an `ArraySpace` of canonical spaces is its own canonical space. Widen the method to `ArraySpace` and reshape the values to the shape of the space. * The component coefficients may be views, so `pad!` may not resize them. Use `pad` instead. * `_values` asserted a `Vector{float(T)}` return for any space over a numeric domain, which includes array-valued ones. Restrict the assertion to spaces with a scalar range type. Also fix `points(f::Fun{<:ArraySpace})`, which passed the total number of interlaced coefficients where a per-component count is expected, so that `values(f) == f.(points(f))`. Fixes #647 Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
1 parent e7b41cc commit 67bed18

3 files changed

Lines changed: 36 additions & 3 deletions

File tree

src/Fun.jl

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -426,7 +426,8 @@ true
426426
"""
427427
values(f::Fun,dat...) = _values(f.space, f.coefficients, dat...)
428428
_values(sp, v, dat...) = itransform(sp, v, dat...)
429-
_values(sp::UnivariateSpace, v::Vector{T}, dat...) where {T<:Number} =
429+
# the return type may be asserted only for scalar-valued spaces
430+
_values(sp::Space{<:Domain{<:Number},<:Number}, v::Vector{T}, dat...) where {T<:Number} =
430431
itransform(sp, v, dat...)::Vector{float(T)}
431432

432433
"""

src/Spaces/ArraySpace.jl

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,11 @@ setdomain(A::ArraySpace,d::Domain) = ArraySpace(map(sp->setdomain(sp,d),A.spaces
7474

7575
#TODO: rework for different spaces
7676
points(d::ArraySpace,n) = points(d.spaces[1],n)
77+
# points(::ArraySpace, n) forwards n to a component space, so n must be the number of
78+
# coefficients per component. The generic points(f::Fun) would pass ncoefficients(f),
79+
# which counts the interlaced coefficients of all the components together.
80+
# The count below matches the padding in itransform, so that values(f) == f.(points(f)).
81+
points(f::Fun{<:ArraySpace}) = points(space(f), maximum(ncoefficients, vec(f), init=0))
7782

7883

7984
transform(AS::ArraySpace{SS,1},vals::AbstractVector{Vector{V}}) where {SS,V} =
@@ -98,10 +103,12 @@ transform(AS::VectorSpace{SS},vals::AbstractVector{AV}) where {SS,AV<:AbstractVe
98103
transform(AS::VectorSpace{SS},vals::AbstractVector{SVector{V,n}}) where {SS,n,V} =
99104
transform(AS,map(Vector,vals))
100105

101-
function itransform(AS::VectorSpace,cfs::AbstractVector)
106+
function itransform(AS::ArraySpace,cfs::AbstractVector)
102107
vf = vec(Fun(AS, cfs))
103108
n = maximum(ncoefficients, vf)
104-
vcat.(values.(pad!.(vf, n))...)
109+
vals = vcat.(values.(pad.(vf, n))...)
110+
# the values of an array-valued Fun are arrays of the same shape
111+
[reshape(v, size(AS)) for v in vals]
105112
end
106113

107114

test/SpacesTest.jl

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -395,5 +395,30 @@ using Test
395395
A = ApproxFunBase.ArraySpace(empty!([PointSpace(1:3)]))
396396
@test length(A) == 0
397397
@test ApproxFunBase.dimension(A) == 0
398+
399+
@testset "values" begin
400+
# the two spaces exercise different paths: an ArraySpace of
401+
# HeavisideSpaces lies over a numeric domain and has a trivial
402+
# interlacer, so that the component coefficients are views
403+
@testset for S in (PointSpace(1:3), ApproxFunBase.HeavisideSpace([-1.0, -0.5, 0.0, 1.0]))
404+
@testset for sz in ((2,), (2,2))
405+
A = ApproxFunBase.ArraySpace(S, sz...)
406+
# 3 coefficients per component, so that each component
407+
# may be evaluated on the full grid
408+
n = 3length(A)
409+
f = Fun(A, Float64.(1:n))
410+
v = values(f)
411+
@test all(x -> size(x) == sz, v)
412+
@test v == f.(points(f))
413+
@test !iszero(f)
414+
@test iszero(Fun(A, zeros(n)))
415+
end
416+
end
417+
418+
# static array space
419+
A = ApproxFunBase.ArraySpace(PointSpace(1:3), Val((2,2)))
420+
f = Fun(A, Float64.(1:3length(A)))
421+
@test values(f) == f.(points(f))
422+
end
398423
end
399424
end

0 commit comments

Comments
 (0)