Skip to content

Commit

Permalink
Throw an error when passing empty input to cov
Browse files Browse the repository at this point in the history
74897fe unintentionnally changed the behavior of `cov`,
which now allows passing two empty vectors instead of throwing an error.
This is inconsistent with `cor`. If we wanted to return a value, `NaN`
would be more appropriate and consistent with `var`,
but for now make this an error again.

Also add tests to cover all empty inputs for similar functions.
Unfortunately it turns out we are quite inconsistent already, as
`cor` and `cov` allow empty matrices already, but `cov` returns `-0.0`
while `cor`, `std` and `var` return `NaN`.
  • Loading branch information
nalimilan committed Oct 26, 2021
1 parent 74897fe commit 2f8cda4
Show file tree
Hide file tree
Showing 2 changed files with 33 additions and 1 deletion.
6 changes: 5 additions & 1 deletion src/Statistics.jl
Original file line number Diff line number Diff line change
Expand Up @@ -519,7 +519,11 @@ unscaled_covzm(x::AbstractVector{<:Number}) = sum(abs2, x)
unscaled_covzm(x::AbstractVector) = sum(t -> t*t', x)
unscaled_covzm(x::AbstractMatrix, vardim::Int) = (vardim == 1 ? _conj(x'x) : x * x')

unscaled_covzm(x::AbstractVector, y::AbstractVector) = dot(y, x)
function unscaled_covzm(x::AbstractVector, y::AbstractVector)
(isempty(x) || isempty(y)) &&
throw(ArgumentError("covariance only defined for non-empty vectors"))
return dot(y, x)
end
unscaled_covzm(x::AbstractVector, y::AbstractMatrix, vardim::Int) =
(vardim == 1 ? *(transpose(x), _conj(y)) : *(transpose(x), transpose(_conj(y))))
unscaled_covzm(x::AbstractMatrix, y::AbstractVector, vardim::Int) =
Expand Down
28 changes: 28 additions & 0 deletions test/runtests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -899,3 +899,31 @@ end
@test isfinite.(cov_sparse) == isfinite.(cov_dense)
end
end

@testset "var, std, cov and cor on empty inputs" begin
@test isnan(var(Int[]))
@test isnan(std(Int[]))
@test isequal(cov(Int[]), -0.0)
@test isequal(cor(Int[]), 1.0)

@test_throws ArgumentError cov(Int[], Int[])
@test_throws ArgumentError cor(Int[], Int[])

mx = Matrix{Int}(undef, 0, 2)
my = Matrix{Int}(undef, 0, 3)

@test isequal(var(mx, dims=1), fill(NaN, 1, 2))
@test isequal(std(mx, dims=1), fill(NaN, 1, 2))
@test isequal(var(mx, dims=2), fill(NaN, 0, 1))
@test isequal(std(mx, dims=2), fill(NaN, 0, 1))

@test isequal(cov(mx, my), fill(-0.0, 2, 3))
@test isequal(cor(mx, my), fill(NaN, 2, 3))
@test isequal(cov(my, mx, dims=1), fill(-0.0, 3, 2))
@test isequal(cor(my, mx, dims=1), fill(NaN, 3, 2))

@test isequal(cov(mx, Int[]), fill(-0.0, 2, 1))
@test isequal(cor(mx, Int[]), fill(NaN, 2, 1))
@test isequal(cov(Int[], my), fill(-0.0, 1, 3))
@test isequal(cor(Int[], my), fill(NaN, 1, 3))
end

0 comments on commit 2f8cda4

Please sign in to comment.