Skip to content

Commit 6e99a30

Browse files
committed
Add options for tolerance
1 parent 0242ee4 commit 6e99a30

File tree

2 files changed

+19
-7
lines changed

2 files changed

+19
-7
lines changed

src/indexing.jl

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,10 @@ using Base: ViewIndex, @propagate_inbounds, tail
44

55
immutable Value{T}
66
val::T
7+
tol::T
78
end
8-
atvalue(x) = Value(x)
9+
Value(v,t) = Value(promote(v,t)...)
10+
atvalue(x; rtol=Base.rtoldefault(typeof(x)), atol=zero(x)) = Value(x, atol+rtol*abs(x))
911

1012
# Defer IndexStyle to the wrapped array
1113
@compat Base.IndexStyle{T,N,D,Ax}(::Type{AxisArray{T,N,D,Ax}}) = IndexStyle(D)
@@ -179,16 +181,23 @@ axisindexes(t, ax, idx) = error("cannot index $(typeof(ax)) with $(typeof(idx));
179181
# Maybe extend error message to all <: Numbers if Base allows it?
180182
axisindexes(::Type{Dimensional}, ax::AbstractVector, idx::Real) =
181183
throw(ArgumentError("invalid index: $idx. Use `atvalue` when indexing by value."))
182-
axisindexes(::Type{Dimensional}, ax::AbstractVector, idx) =
183-
_axisindexes(Dimensional, ax::AbstractVector, idx)
184-
# Dimensional axes may always be indexed by value if in a Value type wrapper.
185-
axisindexes(::Type{Dimensional}, ax::AbstractVector, idx::Value) =
186-
_axisindexes(Dimensional, ax::AbstractVector, idx.val)
187-
function _axisindexes(::Type{Dimensional}, ax::AbstractVector, idx)
184+
function axisindexes(::Type{Dimensional}, ax::AbstractVector, idx)
188185
idxs = searchsorted(ax, ClosedInterval(idx,idx))
189186
length(idxs) > 1 && error("more than one datapoint lies on axis value $idx; use an interval to return all values")
190187
idxs[1]
191188
end
189+
# Dimensional axes may always be indexed by value if in a Value type wrapper.
190+
function axisindexes(::Type{Dimensional}, ax::AbstractVector, idx::Value)
191+
idxs = searchsorted(ax, ClosedInterval(idx.val,idx.val))
192+
length(idxs) > 1 && error("more than one datapoint lies on axis value $idx; use an interval to return all values")
193+
if length(idxs) == 1
194+
idxs[1]
195+
else # it's zero
196+
last(idxs) > 0 && abs(ax[last(idxs)] - idx.val) < idx.tol && return last(idxs)
197+
first(idxs) <= length(ax) && abs(ax[first(idxs)] - idx.val) < idx.tol && return first(idxs)
198+
return 0
199+
end
200+
end
192201

193202
# Dimensional axes may be indexed by intervals to select a range
194203
axisindexes{T}(::Type{Dimensional}, ax::AbstractVector{T}, idx::ClosedInterval) = searchsorted(ax, idx)

test/indexing.jl

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,9 @@ A = AxisArray([1 2; 3 4], Axis{:x}([1.0,4.0]), Axis{:y}([2.0,6.1]))
178178
@test @inferred(A[:, atvalue(2.0)]) == [1,3]
179179
@test @inferred(A[Axis{:x}(atvalue(4.0))]) == [3,4]
180180
@test @inferred(A[Axis{:y}(atvalue(6.1))]) == [2,4]
181+
@test @inferred(A[Axis{:x}(atvalue(4.00000001))]) == [3,4]
182+
@test @inferred(A[Axis{:x}(atvalue(2.0, atol=5))]) == [1,2]
183+
@test_throws BoundsError A[Axis{:x}(atvalue(4.00000001, rtol=0))]
181184

182185
# Indexing by value directly is forbidden for indexes that are Real
183186
@test_throws ArgumentError A[4.0]

0 commit comments

Comments
 (0)