From 1fc0c84195f5113a719727ccaef770a628da38d1 Mon Sep 17 00:00:00 2001 From: Iblis Lin Date: Mon, 25 Dec 2017 12:16:33 +0800 Subject: [PATCH 1/9] timearray: Revoke deprecation of `==` and redefine its meaning ```julia julia> cl == copy(cl) true ``` --- NEWS.md | 10 ++++++++++ src/deprecated.jl | 2 +- src/timearray.jl | 23 +++++++++++++++++++++-- test/timearray.jl | 27 +++++++++++++++++++++++++++ 4 files changed, 59 insertions(+), 3 deletions(-) diff --git a/NEWS.md b/NEWS.md index 543b601f..b6936e61 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,3 +1,13 @@ +### 0.12.0 + +* Revoking deprecation warning of `==` and redefining its meaning as + 'comparing all fields of two TimeArray'. (#356, #TBD) + + ```julia + julia> cl == copy(cl) + true + ``` + ### 0.11.0 * Dropping 0.5 support. (issue [#327]) diff --git a/src/deprecated.jl b/src/deprecated.jl index ae6763f5..7a37287c 100644 --- a/src/deprecated.jl +++ b/src/deprecated.jl @@ -30,7 +30,7 @@ for f ∈ (:^, :/) end for f ∈ (:+, :-, :*, :%, - :|, :&, :<, :>, :(==), :(!=), :>=, :<=) + :|, :&, :<, :>, :>=, :<=) g = Symbol(".", string(f)) @eval import Base: $f @eval @deprecate $f(ta::TimeArray, args...) $g(ta, args...) diff --git a/src/timearray.jl b/src/timearray.jl index 46615e2c..6aeacfd0 100644 --- a/src/timearray.jl +++ b/src/timearray.jl @@ -1,7 +1,7 @@ ###### type definition ########## import Base: convert, copy, length, show, getindex, start, next, done, isempty, - endof, size, eachindex + endof, size, eachindex, == abstract type AbstractTimeSeries end @@ -69,13 +69,32 @@ length(ata::AbstractTimeSeries) = length(ata.timestamp) size(ta::TimeArray, dim...) = size(ta.values, dim...) -###### iterator protocol ######### +###### iterator protocol ######## start(ta::TimeArray) = 1 next(ta::TimeArray, i) = ((ta.timestamp[i], ta.values[i, :]), i + 1) done(ta::TimeArray, i) = (i > length(ta)) isempty(ta::TimeArray) = (length(ta) == 0) +###### equal #################### + +@generated function ==(x::TimeArray{T,N}, y::TimeArray{S,M}) where {T,S,N,M} + if N != M + return :false + # Other type info is not helpful for assertion + # e.g. + # 1.0 == 1 + # Date(2111, 1, 1) == DateTime(2111, 1, 1) + end + + quote + for f ∈ fieldnames(TimeArray) + getfield(x, f) != getfield(y, f) && return :false + end + :true + end +end + ###### show ##################### @inline _showval(v::Any) = repr(v) diff --git a/test/timearray.jl b/test/timearray.jl index cd13f7de..c8ec4522 100644 --- a/test/timearray.jl +++ b/test/timearray.jl @@ -240,6 +240,33 @@ end end +@testset "equal" begin + @test cl == copy(cl) + @test cl != ohlc # rely on fallback definition + @test cl != lag(cl) + + ds = DateTime(2017, 12, 25):DateTime(2017, 12, 31) |> collect + + let # diff colnames + x = TimeArray(ds, 1:7, ["foo"]) + y = TimeArray(ds, 1:7, ["bar"]) + @test x != y + end + + let # Float vs Int + x = TimeArray(ds, 1:7) + y = TimeArray(ds, 1.0:7) + @test x == y + end + + let # Date vs DateTime + ds2 = Date(2017, 12, 25):Date(2017, 12, 31) |> collect + x = TimeArray(ds, 1:7, ["foo"], "bar") + y = TimeArray(ds2, 1:7, ["foo"], "bar") + end +end + + @testset "show methods don't throw errors" begin let str = sprint(show, cl) out = """500x1 TimeSeries.TimeArray{Float64,1,Date,Array{Float64,1}} 2000-01-03 to 2001-12-31 From e4277365a96bdc263857d910099dbb62ebc2078d Mon Sep 17 00:00:00 2001 From: Iblis Lin Date: Mon, 25 Dec 2017 14:57:19 +0800 Subject: [PATCH 2/9] add docstring --- src/timearray.jl | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/timearray.jl b/src/timearray.jl index 6aeacfd0..79817097 100644 --- a/src/timearray.jl +++ b/src/timearray.jl @@ -78,6 +78,20 @@ isempty(ta::TimeArray) = (length(ta) == 0) ###### equal #################### +""" + ==(x::TimeArray, y::TimeArray) + +If true, all fields of x and y should be equal. + +Implies + +```julia +x.timestamp == y.timestamp && +x.values == y.values && +x.colnames == y.colnames && +x.meta == y.meta +``` +""" @generated function ==(x::TimeArray{T,N}, y::TimeArray{S,M}) where {T,S,N,M} if N != M return :false From 4a8bfcaddc182b80553328a17874371b4303e1e6 Mon Sep 17 00:00:00 2001 From: Iblis Lin Date: Mon, 25 Dec 2017 22:27:24 +0800 Subject: [PATCH 3/9] update docstring --- src/timearray.jl | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/timearray.jl b/src/timearray.jl index 79817097..86ea2697 100644 --- a/src/timearray.jl +++ b/src/timearray.jl @@ -81,7 +81,9 @@ isempty(ta::TimeArray) = (length(ta) == 0) """ ==(x::TimeArray, y::TimeArray) -If true, all fields of x and y should be equal. +If `true`, all fields of `x` and `y` should be equal, +meaning that the two `TimeArray`s have the same values at the same points in time, +the same colnames and the same metadata. Implies @@ -95,7 +97,7 @@ x.meta == y.meta @generated function ==(x::TimeArray{T,N}, y::TimeArray{S,M}) where {T,S,N,M} if N != M return :false - # Other type info is not helpful for assertion + # Other type info is not helpful for assertion. # e.g. # 1.0 == 1 # Date(2111, 1, 1) == DateTime(2111, 1, 1) From 483d88c4657e5f1af4400bb69b985d042326c0c6 Mon Sep 17 00:00:00 2001 From: Iblis Lin Date: Mon, 25 Dec 2017 22:45:34 +0800 Subject: [PATCH 4/9] fix indentation --- src/timearray.jl | 26 +++++++++++++------------- test/timearray.jl | 18 +++++++++--------- 2 files changed, 22 insertions(+), 22 deletions(-) diff --git a/src/timearray.jl b/src/timearray.jl index 86ea2697..7968244d 100644 --- a/src/timearray.jl +++ b/src/timearray.jl @@ -95,20 +95,20 @@ x.meta == y.meta ``` """ @generated function ==(x::TimeArray{T,N}, y::TimeArray{S,M}) where {T,S,N,M} - if N != M - return :false - # Other type info is not helpful for assertion. - # e.g. - # 1.0 == 1 - # Date(2111, 1, 1) == DateTime(2111, 1, 1) - end - - quote - for f ∈ fieldnames(TimeArray) - getfield(x, f) != getfield(y, f) && return :false + if N != M + return :false + # Other type info is not helpful for assertion. + # e.g. + # 1.0 == 1 + # Date(2111, 1, 1) == DateTime(2111, 1, 1) + end + + quote + for f ∈ fieldnames(TimeArray) + getfield(x, f) != getfield(y, f) && return :false + end + :true end - :true - end end ###### show ##################### diff --git a/test/timearray.jl b/test/timearray.jl index c8ec4522..bb4ab3fe 100644 --- a/test/timearray.jl +++ b/test/timearray.jl @@ -248,21 +248,21 @@ end ds = DateTime(2017, 12, 25):DateTime(2017, 12, 31) |> collect let # diff colnames - x = TimeArray(ds, 1:7, ["foo"]) - y = TimeArray(ds, 1:7, ["bar"]) - @test x != y + x = TimeArray(ds, 1:7, ["foo"]) + y = TimeArray(ds, 1:7, ["bar"]) + @test x != y end let # Float vs Int - x = TimeArray(ds, 1:7) - y = TimeArray(ds, 1.0:7) - @test x == y + x = TimeArray(ds, 1:7) + y = TimeArray(ds, 1.0:7) + @test x == y end let # Date vs DateTime - ds2 = Date(2017, 12, 25):Date(2017, 12, 31) |> collect - x = TimeArray(ds, 1:7, ["foo"], "bar") - y = TimeArray(ds2, 1:7, ["foo"], "bar") + ds2 = Date(2017, 12, 25):Date(2017, 12, 31) |> collect + x = TimeArray(ds, 1:7, ["foo"], "bar") + y = TimeArray(ds2, 1:7, ["foo"], "bar") end end From db26f89187b7677fdf0906a63aa198b1c686d7f4 Mon Sep 17 00:00:00 2001 From: Iblis Lin Date: Tue, 26 Dec 2017 00:46:09 +0800 Subject: [PATCH 5/9] implement `isequal` and `hash` --- NEWS.md | 14 +++++++++++++- src/timearray.jl | 21 ++++++++++++++++++++- test/timearray.jl | 17 +++++++++++++++-- 3 files changed, 48 insertions(+), 4 deletions(-) diff --git a/NEWS.md b/NEWS.md index b6936e61..b387130f 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,13 +1,25 @@ ### 0.12.0 * Revoking deprecation warning of `==` and redefining its meaning as - 'comparing all fields of two TimeArray'. (#356, #TBD) + 'comparing all fields of two TimeArray'. (#356, #357) ```julia julia> cl == copy(cl) true ``` + * Also, `isequal` and `hash` is supported now. + + ```julia + julia> d = Dict(cl => 42); + + julia> d[cl] + 42 + + julia> d[copy(cl)] + 42 + ``` + ### 0.11.0 * Dropping 0.5 support. (issue [#327]) diff --git a/src/timearray.jl b/src/timearray.jl index 7968244d..5147a73a 100644 --- a/src/timearray.jl +++ b/src/timearray.jl @@ -1,7 +1,7 @@ ###### type definition ########## import Base: convert, copy, length, show, getindex, start, next, done, isempty, - endof, size, eachindex, == + endof, size, eachindex, ==, isequal, hash abstract type AbstractTimeSeries end @@ -111,6 +111,25 @@ x.meta == y.meta end end +@generated function isequal(x::TimeArray{T,N}, y::TimeArray{S,M}) where {T,S,N,M} + if N != M + return :false + end + + quote + for f ∈ fieldnames(TimeArray) + !isequal(getfield(x, f), getfield(y, f)) && return :false + end + :true + end +end + +# support for Dict +hash(x::TimeArray, h::UInt) = + mapreduce(+, fieldnames(TimeArray)) do f + hash(getfield(x, f), h) + end + ###### show ##################### @inline _showval(v::Any) = repr(v) diff --git a/test/timearray.jl b/test/timearray.jl index bb4ab3fe..58586114 100644 --- a/test/timearray.jl +++ b/test/timearray.jl @@ -242,8 +242,12 @@ end @testset "equal" begin @test cl == copy(cl) - @test cl != ohlc # rely on fallback definition - @test cl != lag(cl) + @test cl ≠ ohlc # rely on fallback definition + @test cl ≠ lag(cl) + + @test isequal(cl, copy(cl)) + @test !isequal(cl, ohlc) + @test !isequal(cl, lag(cl)) ds = DateTime(2017, 12, 25):DateTime(2017, 12, 31) |> collect @@ -263,6 +267,15 @@ end ds2 = Date(2017, 12, 25):Date(2017, 12, 31) |> collect x = TimeArray(ds, 1:7, ["foo"], "bar") y = TimeArray(ds2, 1:7, ["foo"], "bar") + @test x == y + end + + @testset "hash" begin + @test hash(cl) == hash(copy(cl)) + + d = Dict(cl => 42) + @test d[cl] == 42 + @test d[copy(cl)] == 42 end end From 9ebe9993eaaa28f56baaf6e115f7ed7fc4ab8bb0 Mon Sep 17 00:00:00 2001 From: Iblis Lin Date: Wed, 27 Dec 2017 08:50:22 +0800 Subject: [PATCH 6/9] sum --- src/timearray.jl | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/timearray.jl b/src/timearray.jl index 5147a73a..b82d1c90 100644 --- a/src/timearray.jl +++ b/src/timearray.jl @@ -125,10 +125,7 @@ end end # support for Dict -hash(x::TimeArray, h::UInt) = - mapreduce(+, fieldnames(TimeArray)) do f - hash(getfield(x, f), h) - end +hash(x::TimeArray, h::UInt) = sum(f -> hash(getfield(x, f), h), fieldnames(TimeArray)) ###### show ##################### From 5964a1759125f03148cb5a06766d4722bdfd30b2 Mon Sep 17 00:00:00 2001 From: Iblis Lin Date: Wed, 27 Dec 2017 09:23:38 +0800 Subject: [PATCH 7/9] elegant --- src/timearray.jl | 43 +++++++++++++------------------------------ 1 file changed, 13 insertions(+), 30 deletions(-) diff --git a/src/timearray.jl b/src/timearray.jl index b82d1c90..98a03216 100644 --- a/src/timearray.jl +++ b/src/timearray.jl @@ -94,38 +94,21 @@ x.colnames == y.colnames && x.meta == y.meta ``` """ -@generated function ==(x::TimeArray{T,N}, y::TimeArray{S,M}) where {T,S,N,M} - if N != M - return :false - # Other type info is not helpful for assertion. - # e.g. - # 1.0 == 1 - # Date(2111, 1, 1) == DateTime(2111, 1, 1) - end - - quote - for f ∈ fieldnames(TimeArray) - getfield(x, f) != getfield(y, f) && return :false - end - :true - end -end - -@generated function isequal(x::TimeArray{T,N}, y::TimeArray{S,M}) where {T,S,N,M} - if N != M - return :false - end - - quote - for f ∈ fieldnames(TimeArray) - !isequal(getfield(x, f), getfield(y, f)) && return :false - end - :true - end -end +# Other type info is not helpful for assertion. +# e.g. +# 1.0 == 1 +# Date(2111, 1, 1) == DateTime(2111, 1, 1) +==(x::TimeArray{T,N}, y::TimeArray{S,M}) where {T,S,N,M} = false +==(x::TimeArray{T,N}, y::TimeArray{S,N}) where {T,S,N} = + all(f -> getfield(x, f) == getfield(y, f), fieldnames(TimeArray)) + +isequal(x::TimeArray{T,N}, y::TimeArray{S,M}) where {T,S,N,M} = false +isequal(x::TimeArray{T,N}, y::TimeArray{S,N}) where {T,S,N} = + all(f -> isequal(getfield(x, f), getfield(y, f)), fieldnames(TimeArray)) # support for Dict -hash(x::TimeArray, h::UInt) = sum(f -> hash(getfield(x, f), h), fieldnames(TimeArray)) +hash(x::TimeArray, h::UInt) = + sum(f -> hash(getfield(x, f), h), fieldnames(TimeArray)) ###### show ##################### From c190e22e7ce09cee97d34d78b3c773e262ec2ef7 Mon Sep 17 00:00:00 2001 From: Iblis Lin Date: Wed, 27 Dec 2017 09:27:02 +0800 Subject: [PATCH 8/9] update NEWS --- NEWS.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/NEWS.md b/NEWS.md index b387130f..c6102d0a 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,7 +1,10 @@ ### 0.12.0 * Revoking deprecation warning of `==` and redefining its meaning as - 'comparing all fields of two TimeArray'. (#356, #357) + 'comparing all fields of two `TimeArray`s'. + Note that if two `TimeArray`s have different dimension, we consider that is + unequal. + (#356, #357) ```julia julia> cl == copy(cl) From dab9ae12e0ee3ec6eb15fe03467b6b6b19438510 Mon Sep 17 00:00:00 2001 From: Iblis Lin Date: Wed, 27 Dec 2017 09:32:50 +0800 Subject: [PATCH 9/9] more test cases --- test/timearray.jl | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/test/timearray.jl b/test/timearray.jl index 58586114..c03fa38c 100644 --- a/test/timearray.jl +++ b/test/timearray.jl @@ -270,12 +270,23 @@ end @test x == y end + let # diff meta + x = TimeArray(ds, 1:7, ["foo"], "bar") + y = TimeArray(ds, 1:7, ["foo"], "baz") + @test x != y + end + @testset "hash" begin - @test hash(cl) == hash(copy(cl)) + @test hash(cl) == hash(copy(cl)) + @test hash(ohlc) == hash(copy(ohlc)) d = Dict(cl => 42) @test d[cl] == 42 @test d[copy(cl)] == 42 + + d = Dict(ohlc => 24) + @test d[ohlc] == 24 + @test d[copy(ohlc)] == 24 end end