Skip to content

Commit

Permalink
Merge pull request #57 from JuliaArrays/teh/0.6
Browse files Browse the repository at this point in the history
Fix 0.6 breakages and depwarns
  • Loading branch information
mbauman committed Feb 21, 2017
2 parents 65263db + e4238b9 commit 4d2f8cc
Show file tree
Hide file tree
Showing 12 changed files with 77 additions and 47 deletions.
23 changes: 11 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,13 @@ Collaboration is welcome! This is still a work-in-progress. See [the roadmap](ht

```julia
julia> Pkg.clone("https://github.com/JuliaArrays/AxisArrays.jl")
using AxisArrays, SIUnits
import SIUnits.ShortUnits: s, ms, µs
using AxisArrays, Unitful
import Unitful: s, ms, µs

julia> fs = 40000 # Generate a 40kHz noisy signal, with spike-like stuff added for testing
y = randn(60*fs+1)*3
for spk = (sin(0.8:0.2:8.6) .* [0:0.01:.1; .15:.1:.95; 1:-.05:.05] .* 50,
sin(0.8:0.4:8.6) .* [0:0.02:.1; .15:.1:1; 1:-.2:.1] .* 50)
for spk = (sin.(0.8:0.2:8.6) .* [0:0.01:.1; .15:.1:.95; 1:-.05:.05] .* 50,
sin.(0.8:0.4:8.6) .* [0:0.02:.1; .15:.1:1; 1:-.2:.1] .* 50)
i = rand(round(Int,.001fs):1fs)
while i+length(spk)-1 < length(y)
y[i:i+length(spk)-1] += spk
Expand Down Expand Up @@ -54,16 +54,15 @@ indices in *any* order, just so long as we annotate them with the axis name:

```jl
julia> A[Axis{:time}(4)]
2-dimensional AxisArray{Float64,2,...} with axes:
:time, 7.5e-5 s:2.5e-5 s:7.5e-5 s
:chan, [:c1,:c2]
And data, a 1x2 SubArray{Float64,2,Array{Float64,2},Tuple{UnitRange{Int64},Colon},2}:
2-dimensional AxisArray{Float64,1,...} with axes:
:chan, Symbol[:c1,:c2]
And data, a 2-element Array{Float64,1}:
-1.4144 -2.82879

julia> A[Axis{:chan}(:c2), Axis{:time}(1:5)]
1-dimensional AxisArray{Float64,1,...} with axes:
:time, 0.0 s:2.5e-5 s:0.0001 s
And data, a 5-element SubArray{Float64,1,Array{Float64,2},Tuple{UnitRange{Int64},Int64},2}:
A[Axis{:chan}(:c2), Axis{:time}(1:5)]:
-6.12181
0.304668
15.7366
Expand All @@ -80,7 +79,7 @@ still has the correct time information for those datapoints!
julia> A[40µs .. 220µs, :c1]
1-dimensional AxisArray{Float64,1,...} with axes:
:time, 5.0e-5 s:2.5e-5 s:0.0002 s
And data, a 7-element SubArray{Float64,1,Array{Float64,2},Tuple{UnitRange{Int64},Int64},2}:
And data, a 7-element Array{Float64,1}:
7.86831
-1.4144
-2.02881
Expand All @@ -90,7 +89,7 @@ And data, a 7-element SubArray{Float64,1,Array{Float64,2},Tuple{UnitRange{Int64}
-1.97716

julia> axes(ans, 1)
AxisArrays.Axis{:time,SIUnits.SIRange{FloatRange{Float64},Float64,0,0,1,0,0,0,0,0,0}}(5.0e-5 s:2.5e-5 s:0.0002 s)
AxisArrays.Axis{:time,StepRangeLen{Quantity{Float64, Dimensions:{𝐓}, Units:{s}},Base.TwicePrecision{Quantity{Float64, Dimensions:{𝐓}, Units:{s}}},Base.TwicePrecision{Quantity{Float64, Dimensions:{𝐓}, Units:{s}}}}}(5.0e-5 s:2.5e-5 s:0.0002 s)
```

Sometimes, though, what we're really interested in is a window of time about a
Expand Down Expand Up @@ -125,7 +124,7 @@ julia> idxs = find(diff(A[:,:c1] .< -15) .> 0)
julia> spks = A[atindex(-200µs .. 800µs, idxs), :c1]
2-dimensional AxisArray{Float64,2,...} with axes:
:time_sub, -0.000175 s:2.5e-5 s:0.000775 s
:time_rep, SIUnits.SIQuantity{Float64,0,0,1,0,0,0,0,0,0}[0.178725 s,0.806825 s,0.88305 s,1.47485 s,1.50465 s,1.53805 s,1.541025 s,2.16365 s,2.368425 s,2.739 s 57.797925 s,57.924075 s,58.06075 s,58.215125 s,58.6403 s,58.96215 s,58.990225 s,59.001325 s,59.48395 s,59.611525 s]
:time_rep, Quantity{Float64, Dimensions:{𝐓}, Units:{s}}[0.178725 s,0.806825 s,0.88305 s,1.47485 s,1.50465 s,1.53805 s,1.541025 s,2.16365 s,2.368425 s,2.739 s 57.797925 s,57.924075 s,58.06075 s,58.215125 s,58.6403 s,58.96215 s,58.990225 s,59.001325 s,59.48395 s,59.611525 s]
And data, a 39x242 Array{Float64,2}:
-1.53038 4.72882 5.8706 -0.231564 0.624714 3.44076
-2.24961 2.12414 5.69936 7.00179 2.30993 5.20432
Expand Down
1 change: 1 addition & 0 deletions REQUIRE
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@ julia 0.5
IntervalSets
Iterators
RangeArrays
Compat 0.19
1 change: 1 addition & 0 deletions src/AxisArrays.jl
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ module AxisArrays

using Base: tail
using RangeArrays, Iterators, IntervalSets
using Compat

export AxisArray, Axis, axisnames, axisvalues, axisdim, axes, atindex

Expand Down
2 changes: 1 addition & 1 deletion src/combine.jl
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ sizes{T<:AxisArray}(As::T...) = tuple(zip(map(size, As)...)...)
matchingdims{N,T<:AxisArray}(As::NTuple{N,T}) = all(equalvalued, sizes(As...))
matchingdimsexcept{N,T<:AxisArray}(As::NTuple{N,T}, n::Int) = all(equalvalued, sizes(As[[1:n-1; n+1:end]]...))

function Base.cat{T<:AxisArray}(n::Integer, As::T...)
function Base.cat{T}(n::Integer, As::AxisArray{T}...)
if n <= ndims(As[1])
matchingdimsexcept(As, n) || error("All non-concatenated axes must be identically-valued")
newaxis = Axis{axisnames(As[1])[n]}(vcat(map(A -> A.axes[n].val, As)...))
Expand Down
15 changes: 7 additions & 8 deletions src/core.jl
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ else
using Base: @pure
end

typealias Symbols Tuple{Symbol,Vararg{Symbol}}
const Symbols = Tuple{Symbol,Vararg{Symbol}}

@doc """
Type-stable axis-specific indexing and identification with a
Expand Down Expand Up @@ -158,17 +158,17 @@ A[ClosedInterval(0.,.3), [:a, :c]] # select an interval and two columns
immutable AxisArray{T,N,D,Ax} <: AbstractArray{T,N}
data::D # D <:AbstractArray, enforced in constructor to avoid dispatch bugs (https://github.com/JuliaLang/julia/issues/6383)
axes::Ax # Ax<:NTuple{N, Axis}, but with specialized Axis{...} types
AxisArray(data::AbstractArray, axs) = new{T,N,D,Ax}(data, axs)
(::Type{AxisArray{T,N,D,Ax}}){T,N,D,Ax}(data::AbstractArray{T,N}, axs::Tuple{Vararg{Axis,N}}) = new{T,N,D,Ax}(data, axs)
end
#
_defaultdimname(i) = i == 1 ? (:row) : i == 2 ? (:col) : i == 3 ? (:page) : Symbol(:dim_, i)

default_axes(A::AbstractArray) = _default_axes(A, indices(A), ())
_default_axes{T,N}(A::AbstractArray{T,N}, inds, axs::NTuple{N}) = axs
@inline _default_axes{T,N,M}(A::AbstractArray{T,N}, inds, axs::NTuple{M}) =
_default_axes{T,N}(A::AbstractArray{T,N}, inds, axs::NTuple{N,Axis}) = axs
@inline _default_axes{T,N,M}(A::AbstractArray{T,N}, inds, axs::NTuple{M,Axis}) =
_default_axes(A, inds, (axs..., _nextaxistype(A, axs)(inds[M+1])))
# Why doesn't @pure work here?
@generated function _nextaxistype{T,M}(A::AbstractArray{T}, axs::NTuple{M})
@generated function _nextaxistype{T,M}(A::AbstractArray{T}, axs::NTuple{M,Axis})
name = _defaultdimname(M+1)
:(Axis{$(Expr(:quote, name))})
end
Expand Down Expand Up @@ -245,7 +245,6 @@ Base.size{Ax<:Axis}(A::AxisArray, ::Type{Ax}) = size(A.data, axisdim(A, Ax))
Base.indices(A::AxisArray) = indices(A.data)
Base.indices(A::AxisArray, Ax::Axis) = indices(A.data, axisdim(A, Ax))
Base.indices{Ax<:Axis}(A::AxisArray, ::Type{Ax}) = indices(A.data, axisdim(A, Ax))
Base.linearindexing(A::AxisArray) = Base.linearindexing(A.data)
Base.convert{T,N}(::Type{Array{T,N}}, A::AxisArray{T,N}) = convert(Array{T,N}, A.data)
# Similar is tricky. If we're just changing the element type, it can stay as an
# AxisArray. But if we're changing dimensions, there's no way it can know how
Expand Down Expand Up @@ -308,7 +307,7 @@ function permutation(to::Symbols, from::Symbols)
li = linearindices(from)
d = Dict(from[i]=>i for i in li)
covered = similar(dims->falses(length(li)), li)
ind = Array(Int, max(n, nf))
ind = Array{Int}(max(n, nf))
for (i,toi) in enumerate(to)
j = get(d, toi, 0)
ind[i] = j
Expand Down Expand Up @@ -421,7 +420,7 @@ axes(A::AbstractArray) = default_axes(A)
axes(A::AbstractArray, dim::Int) = default_axes(A)[dim]

### Axis traits ###
abstract AxisTrait
@compat abstract type AxisTrait end
immutable Dimensional <: AxisTrait end
immutable Categorical <: AxisTrait end
immutable Unsupported <: AxisTrait end
Expand Down
26 changes: 20 additions & 6 deletions src/indexing.jl
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
typealias Idx Union{Real,Colon,AbstractArray{Int}}
const Idx = Union{Real,Colon,AbstractArray{Int}}

using Base: ViewIndex, linearindexing, unsafe_getindex, unsafe_setindex!
using Base: ViewIndex, unsafe_getindex, unsafe_setindex!

# Defer linearindexing to the wrapped array
Base.linearindexing{T,N,D}(::AxisArray{T,N,D}) = linearindexing(D)
# Defer IndexStyle to the wrapped array
@compat Base.IndexStyle{T,N,D,Ax}(::Type{AxisArray{T,N,D,Ax}}) = IndexStyle(D)

# Simple scalar indexing where we just set or return scalars
@inline Base.getindex(A::AxisArray, idxs::Int...) = A.data[idxs...]
Expand All @@ -26,16 +26,24 @@ Base.setindex!(A::AxisArray, v, idx::Base.IteratorsMD.CartesianIndex) = (A.data[
end
names = axisnames(A)
newaxes = Expr[]
for d=1:lastnonscalar-droplastaxis
drange = 1:lastnonscalar-droplastaxis
for d=drange
if I[d] <: AxisArray
# Indexing with an AxisArray joins the axis names
idxnames = axisnames(I[d])
for i=1:ndims(I[d])
push!(newaxes, :($(Axis{Symbol(names[d], "_", idxnames[i])})(I[$d].axes[$i].val)))
end
elseif I[d] <: Real
elseif I[d] <: Union{AbstractVector,Colon}
elseif I[d] <: AbstractVector
push!(newaxes, :($(Axis{names[d]})(A.axes[$d].val[Base.to_index(I[$d])])))
elseif I[d] <: Colon
if d < length(I) || d <= ndims(A)
push!(newaxes, :($(Axis{names[d]})(A.axes[$d].val)))
else
dimname = _defaultdimname(d)
push!(newaxes, :($(Axis{dimname})(Base.OneTo(Base.trailingsize(A, $d)))))
end
elseif I[d] <: AbstractArray
for i=1:ndims(I[d])
# When we index with non-vector arrays, we *add* dimensions.
Expand Down Expand Up @@ -117,6 +125,12 @@ end
return :($meta; to_index(A, $(idxs...)))
end

function Base.reshape{N}(A::AxisArray, ::Type{Val{N}})
# axN, _ = Base.IteratorsMD.split(axes(A), Val{N})
# AxisArray(reshape(A.data, Val{N}), reaxis(A, Base.fill_to_length(axN, :, Val{N})...))
AxisArray(reshape(A.data, Val{N}), reaxis(A, ntuple(d->Colon(), Val{N})...))
end

### Indexing along values of the axes ###

# Default axes indexing throws an error
Expand Down
6 changes: 3 additions & 3 deletions src/intervals.jl
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
# downside is that Intervals are not as useful as they could be; they really
# could be considered as <: Number themselves. We do this in general for any
# supported Scalar:
typealias Scalar Union{Number, Dates.AbstractTime}
const Scalar = Union{Number, Dates.AbstractTime}
Base.promote_rule{T<:Scalar}(::Type{ClosedInterval{T}}, ::Type{T}) = ClosedInterval{T}
Base.promote_rule{T,S<:Scalar}(::Type{ClosedInterval{T}}, ::Type{S}) = ClosedInterval{promote_type(T,S)}
Base.promote_rule{T,S}(::Type{ClosedInterval{T}}, ::Type{ClosedInterval{S}}) = ClosedInterval{promote_type(T,S)}
Expand Down Expand Up @@ -62,7 +62,7 @@ immutable RepeatedInterval{T,S,A} <: AbstractVector{T}
end
RepeatedInterval{S,A<:AbstractVector}(window::ClosedInterval{S}, offsets::A) = RepeatedInterval{promote_type(ClosedInterval{S}, eltype(A)), S, A}(window, offsets)
Base.size(r::RepeatedInterval) = size(r.offsets)
Base.linearindexing{R<:RepeatedInterval}(::Type{R}) = Base.LinearFast()
@compat Base.IndexStyle(::Type{<:RepeatedInterval}) = IndexLinear()
Base.getindex(r::RepeatedInterval, i::Int) = r.window + r.offsets[i]
+(window::ClosedInterval, offsets::AbstractVector) = RepeatedInterval(window, offsets)
+(offsets::AbstractVector, window::ClosedInterval) = RepeatedInterval(window, offsets)
Expand All @@ -84,5 +84,5 @@ immutable RepeatedIntervalAtIndexes{T,A<:AbstractVector{Int}} <: AbstractVector{
end
atindex(window::ClosedInterval, indexes::AbstractVector) = RepeatedIntervalAtIndexes(window, indexes)
Base.size(r::RepeatedIntervalAtIndexes) = size(r.indexes)
Base.linearindexing{R<:RepeatedIntervalAtIndexes}(::Type{R}) = Base.LinearFast()
@compat Base.IndexStyle(::Type{<:RepeatedIntervalAtIndexes}) = IndexLinear()
Base.getindex(r::RepeatedIntervalAtIndexes, i::Int) = IntervalAtIndex(r.window, r.indexes[i])
27 changes: 18 additions & 9 deletions src/search.jl
Original file line number Diff line number Diff line change
Expand Up @@ -36,21 +36,30 @@ function Base.searchsorted(a::Range, I::ClosedInterval)
searchsortedfirst(a, I.left):searchsortedlast(a, I.right)
end

if VERSION > v"0.5.0-dev+4557"
# When running with "--check-bounds=yes" (like on Travis), the bounds-check isn't elided
@inline function Base.unsafe_getindex{T}(v::Range{T}, i::Integer)
convert(T, first(v) + (i-1)*step(v))
end
# When running with "--check-bounds=yes" (like on Travis), the bounds-check isn't elided
@inline function Base.unsafe_getindex{T}(v::Range{T}, i::Integer)
convert(T, first(v) + (i-1)*step(v))
end
@inline function Base.unsafe_getindex{T<:Integer}(r::StepRange, s::Range{T})
st = oftype(r.start, r.start + (first(s)-1)*step(r))
range(st, step(r)*step(s), length(s))
end
if VERSION < v"0.6.0-dev.2390"
include_string("""
@inline function Base.unsafe_getindex{T}(r::FloatRange{T}, i::Integer)
convert(T, (r.start + (i-1)*r.step)/r.divisor)
end
@inline function Base.unsafe_getindex{T<:Integer}(r::StepRange, s::Range{T})
st = oftype(r.start, r.start + (first(s)-1)*step(r))
range(st, step(r)*step(s), length(s))
end
@inline function Base.unsafe_getindex(r::FloatRange, s::OrdinalRange)
FloatRange(r.start + (first(s)-1)*r.step, step(s)*r.step, length(s), r.divisor)
end
""")
else
include_string("""
@inline function Base.unsafe_getindex(r::StepRangeLen, s::OrdinalRange)
vfirst = unsafe_getindex(r, first(s))
StepRangeLen(vfirst, r.step*step(s), length(s))
end
""")
end

function unsafe_searchsortedlast{T<:Number}(a::Range{T}, x::Number)
Expand Down
2 changes: 1 addition & 1 deletion test/REQUIRE
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
OffsetArrays
SIUnits
Unitful
9 changes: 7 additions & 2 deletions test/indexing.jl
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,13 @@ D[1,1,1,1,1] = 10

# Linear indexing across multiple dimensions drops tracking of those dims
@test A[:].axes[1].val == 1:length(A)
@test A[1:2,:].axes[1].val == A.axes[1].val[1:2]
@test A[1:2,:].axes[2].val == 1:Base.trailingsize(A,2)
B = A[1:2,:]
@test B.axes[1].val == A.axes[1].val[1:2]
@test B.axes[2].val == 1:Base.trailingsize(A,2)
B2 = reshape(A, Val{2})
B = B2[1:2,:]
@test B.axes[1].val == A.axes[1].val[1:2]
@test B.axes[2].val == 1:Base.trailingsize(A,2)

B = AxisArray(reshape(1:15, 5,3), .1:.1:0.5, [:a, :b, :c])

Expand Down
8 changes: 4 additions & 4 deletions test/readme.jl
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
# Intended to ensure the README stays working (this is a copy)

using AxisArrays, SIUnits
import SIUnits.ShortUnits: s, ms, µs
using AxisArrays, Unitful
import Unitful: s, ms, µs

fs = 40000
y = randn(60*fs+1)*3
for spk = (sin(0.8:0.2:8.6) .* [0:0.01:.1; .15:.1:.95; 1:-.05:.05] .* 50,
sin(0.8:0.4:8.6) .* [0:0.02:.1; .15:.1:1; 1:-.2:.1] .* 50)
for spk = (sin.(0.8:0.2:8.6) .* [0:0.01:.1; .15:.1:.95; 1:-.05:.05] .* 50,
sin.(0.8:0.4:8.6) .* [0:0.02:.1; .15:.1:1; 1:-.2:.1] .* 50)
i = rand(round(Int,.001fs):1fs)
while i+length(spk)-1 < length(y)
y[i:i+length(spk)-1] += spk
Expand Down
4 changes: 3 additions & 1 deletion test/runtests.jl
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
using AxisArrays
using Base.Test

@test isempty(detect_ambiguities(AxisArrays, Base, Core))
if VERSION < v"0.6.0-dev"
@test isempty(detect_ambiguities(AxisArrays, Base, Core))
end

include("core.jl")
include("intervals.jl")
Expand Down

0 comments on commit 4d2f8cc

Please sign in to comment.