Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -364,8 +364,8 @@ This section lists changes that do not have deprecation warnings.
trait; see its documentation for details. Types which support subtraction (operator
`-`) must now implement `widen` for hashing to work inside heterogeneous arrays.

* `findn(x::AbstractVector)` now returns a 1-tuple with the vector of indices, to be
consistent with higher order arrays ([#25365]).
* `findn(x::AbstractArray)` has been deprecated in favor of `find(!iszero, x)`, which
now returns cartesian indices for multidimensional arrays (see below, [#25532]).

* `find` now returns the same type of indices as `keys`/`pairs` for `AbstractArray`,
`AbstractDict`, `AbstractString`, `Tuple` and `NamedTuple` objects ([#24774]).
Expand Down Expand Up @@ -1191,3 +1191,4 @@ Command-line option changes
[#25231]: https://github.com/JuliaLang/julia/issues/25231
[#25365]: https://github.com/JuliaLang/julia/issues/25365
[#25424]: https://github.com/JuliaLang/julia/issues/25424
[#25532]: https://github.com/JuliaLang/julia/issues/25532
20 changes: 19 additions & 1 deletion base/array.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1778,11 +1778,29 @@ _pairs(iter) = zip(OneTo(typemax(Int)), iter) # safe for objects that don't imp
"""
find(A)

Return a vector of the linear indices of the `true` values in `A`.
Return a vector `I` of the `true` indices or keys of `A`.
If there are no such elements of `A`, return an empty array.
To search for other kinds of values, pass a predicate as the first argument.

Indices or keys are of the same type as those returned by [`keys(A)`](@ref)
and [`pairs(A)`](@ref) for `AbstractArray`, `AbstractDict`, `AbstractString`
`Tuple` and `NamedTuple` objects, and are linear indices starting at `1`
for other iterables.

# Examples
```jldoctest
julia> A = [true, false, false, true]
4-element Array{Bool,1}:
true
false
false
true

julia> find(A)
2-element Array{Int64,1}:
1
4

julia> A = [true false; false true]
2×2 Array{Bool,2}:
true false
Expand Down
22 changes: 9 additions & 13 deletions base/bitarray.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1599,39 +1599,40 @@ end
function find(B::BitArray)
l = length(B)
nnzB = count(B)
I = Vector{Int}(uninitialized, nnzB)
ind = first(keys(B))
I = Vector{typeof(ind)}(uninitialized, nnzB)
nnzB == 0 && return I
Bc = B.chunks
Bcount = 1
Icount = 1
for i = 1:length(Bc)-1
u = UInt64(1)
c = Bc[i]
for j = 1:64
if c & u != 0
I[Icount] = Bcount
I[Icount] = ind
Icount += 1
end
Bcount += 1
ind = nextind(B, ind)
u <<= 1
end
end
u = UInt64(1)
c = Bc[end]
for j = 0:_mod64(l-1)
if c & u != 0
I[Icount] = Bcount
I[Icount] = ind
Icount += 1
end
Bcount += 1
ind = nextind(B, ind)
u <<= 1
end
return I
end

findn(B::BitVector) = find(B)
# For performance
find(::typeof(!iszero), B::BitArray) = find(B)

function findn(B::BitMatrix)
function findnz(B::BitMatrix)
nnzB = count(B)
I = Vector{Int}(uninitialized, nnzB)
J = Vector{Int}(uninitialized, nnzB)
Expand All @@ -1643,11 +1644,6 @@ function findn(B::BitMatrix)
cnt += 1
end
end
return I, J
end

function findnz(B::BitMatrix)
I, J = findn(B)
return I, J, trues(length(I))
end

Expand Down
3 changes: 3 additions & 0 deletions base/deprecated.jl
Original file line number Diff line number Diff line change
Expand Up @@ -2772,6 +2772,9 @@ end

@deprecate findin(a, b) find(occursin(b), a)

@deprecate findn(a::AbstractVector) (find(!iszero, a),)
@deprecate findn(x::AbstractMatrix) (I = find(!iszero, x); (getindex.(I, 1), getindex.(I, 2)))
@deprecate findn(a::AbstractArray{T, N}) where {T, N} (I = find(!iszero, x); ntuple(i -> getindex.(I, i), N))

# END 0.7 deprecations

Expand Down
1 change: 0 additions & 1 deletion base/exports.jl
Original file line number Diff line number Diff line change
Expand Up @@ -495,7 +495,6 @@ export
findmin,
findmin!,
findmax!,
findn,
findnext,
findprev,
findnz,
Expand Down
64 changes: 0 additions & 64 deletions base/multidimensional.jl
Original file line number Diff line number Diff line change
Expand Up @@ -687,51 +687,6 @@ end

##

# small helper function since we cannot use a closure in a generated function
_countnz(x) = x != 0

"""
findn(A)

Return one vector for each dimension containing indices giving the
locations of the non-zeros in `A` (determined by `A[i] != 0`).

# Examples
```jldoctest
julia> A = [1 2 0; 0 0 3; 0 4 0]
3×3 Array{Int64,2}:
1 2 0
0 0 3
0 4 0

julia> findn(A)
([1, 1, 3, 2], [1, 2, 2, 3])

julia> A = [0 0; 0 0]
2×2 Array{Int64,2}:
0 0
0 0

julia> findn(A)
(Int64[], Int64[])
```
"""
@generated function findn(A::AbstractArray{T,N}) where {T,N}
quote
nnzA = count(_countnz, A)
@nexprs $N d->(I_d = Vector{Int}(uninitialized, nnzA))
k = 1
@nloops $N i A begin
@inbounds if (@nref $N A i) != 0
@nexprs $N d->(I_d[k] = i_d)
k += 1
end
end
@ntuple $N I
end
end


# see discussion in #18364 ... we try not to widen type of the resulting array
# from cumsum or cumprod, but in some cases (+, Bool) we may not have a choice.
rcum_promote_type(op, ::Type{T}, ::Type{S}) where {T,S<:Number} = promote_op(op, T, S)
Expand Down Expand Up @@ -1597,25 +1552,6 @@ end
end
end

## findn

@generated function findn(B::BitArray{N}) where N
quote
nnzB = count(B)
I = ntuple(x->Vector{Int}(uninitialized, nnzB), Val($N))
if nnzB > 0
count = 1
@nloops $N i B begin
if (@nref $N B i) # TODO: should avoid bounds checking
@nexprs $N d->(I[d][count] = i_d)
count += 1
end
end
end
return I
end
end

## isassigned

@generated function isassigned(B::BitArray, I_0::Int, I::Int...)
Expand Down
1 change: 0 additions & 1 deletion doc/src/base/arrays.md
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,6 @@ Base.circshift!
Base.circcopy!
Base.find(::Any)
Base.find(::Function, ::Any)
Base.findn
Base.findnz
Base.findfirst(::Any)
Base.findfirst(::Function, ::Any)
Expand Down
11 changes: 8 additions & 3 deletions stdlib/SparseArrays/docs/src/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -115,14 +115,19 @@ julia> R = sparsevec(I,V)

The inverse of the [`sparse`](@ref) and [`sparsevec`](@ref) functions is
[`findnz`](@ref), which retrieves the inputs used to create the sparse array.
There is also a [`findn`](@ref) function which only returns the index vectors.
[`find(!iszero, x)`](@ref) returns the cartesian indices of non-zero entries in `x`
(including stored entries equal to zero).

```jldoctest sparse_function
julia> findnz(S)
([1, 4, 5, 3], [4, 7, 9, 18], [1, 2, 3, -5])

julia> findn(S)
([1, 4, 5, 3], [4, 7, 9, 18])
julia> find(!iszero, S)
4-element Array{CartesianIndex{2},1}:
CartesianIndex(1, 4)
CartesianIndex(4, 7)
CartesianIndex(5, 9)
CartesianIndex(3, 18)

julia> findnz(R)
([1, 3, 4, 5], [1, -5, 2, 3])
Expand Down
2 changes: 1 addition & 1 deletion stdlib/SparseArrays/src/SparseArrays.jl
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import Base.LinAlg: mul!, ldiv!, rdiv!
import Base: @get!, acos, acosd, acot, acotd, acsch, asech, asin, asind, asinh,
atan, atand, atanh, broadcast!, chol, conj!, cos, cosc, cosd, cosh, cospi, cot,
cotd, coth, count, csc, cscd, csch, adjoint!, diag, diff, done, dot, eig,
exp10, exp2, findn, findprev, findnext, floor, hash, indmin, inv,
exp10, exp2, findprev, findnext, floor, hash, indmin, inv,
issymmetric, istril, istriu, log10, log2, lu, next, sec, secd, sech, show,
sin, sinc, sind, sinh, sinpi, squeeze, start, sum, summary, tan,
tand, tanh, trace, transpose!, tril!, triu!, trunc, vecnorm, abs, abs2,
Expand Down
19 changes: 5 additions & 14 deletions stdlib/SparseArrays/src/sparsematrix.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1274,31 +1274,22 @@ function find(p::Function, S::SparseMatrixCSC)
if p(zero(eltype(S)))
return invoke(find, Tuple{Function, Any}, p, S)
end
sz = size(S)
I, J = _findn(p, S)
return CartesianIndex.(I, J)
end
find(p::Base.OccursIn, x::SparseMatrixCSC) =
invoke(find, Tuple{Base.OccursIn, AbstractArray}, p, x)

findn(S::SparseMatrixCSC{Tv,Ti}) where {Tv,Ti} = _findn(x->true, S)

function _findn(p::Function, S::SparseMatrixCSC{Tv,Ti}) where {Tv,Ti}
numnz = nnz(S)
I = Vector{Ti}(uninitialized, numnz)
J = Vector{Ti}(uninitialized, numnz)
inds = Vector{CartesianIndex{2}}(uninitialized, numnz)

count = 1
@inbounds for col = 1 : S.n, k = S.colptr[col] : (S.colptr[col+1]-1)
if p(S.nzval[k])
I[count] = S.rowval[k]
J[count] = col
inds[count] = CartesianIndex(S.rowval[k], col)
count += 1
end
end

return (I, J)
return inds
end
find(p::Base.OccursIn, x::SparseMatrixCSC) =
invoke(find, Tuple{Base.OccursIn, AbstractArray}, p, x)

function findnz(S::SparseMatrixCSC{Tv,Ti}) where {Tv,Ti}
numnz = nnz(S)
Expand Down
6 changes: 0 additions & 6 deletions stdlib/SparseArrays/test/sparse.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1156,12 +1156,6 @@ Base.isless(x::CustomType, y::CustomType) = isless(x.x, y.x)
end
end

@testset "findn" begin
b = findn( sparse(1.0I, 4, 4) )
@test (length(b[1]) == 4)
@test (length(b[2]) == 4)
end

@testset "rotations" begin
a = sparse( [1,1,2,3], [1,3,4,1], [1,2,3,4] )

Expand Down
9 changes: 5 additions & 4 deletions test/abstractarray.jl
Original file line number Diff line number Diff line change
Expand Up @@ -436,12 +436,13 @@ function test_vector_indexing(::Type{T}, shape, ::Type{TestAbstractArray}) where

mask = bitrand(shape)
@testset "test logical indexing" begin
@test B[mask] == A[mask] == B[find(mask)] == A[find(mask)] == find(mask)
@test B[vec(mask)] == A[vec(mask)] == find(mask)
@test B[mask] == A[mask] == B[find(mask)] == A[find(mask)] == LinearIndices(mask)[find(mask)]
@test B[vec(mask)] == A[vec(mask)] == LinearIndices(mask)[find(mask)]
mask1 = bitrand(size(A, 1))
mask2 = bitrand(size(A, 2))
@test B[mask1, mask2, trailing2] == A[mask1, mask2, trailing2] == B[find(mask1), find(mask2), trailing2]
@test B[mask1, 1, trailing2] == A[mask1, 1, trailing2] == find(mask1)
@test B[mask1, mask2, trailing2] == A[mask1, mask2, trailing2] ==
B[LinearIndices(mask1)[find(mask1)], LinearIndices(mask2)[find(mask2)], trailing2]
@test B[mask1, 1, trailing2] == A[mask1, 1, trailing2] == LinearIndices(mask)[find(mask1)]
end
end
end
Expand Down
27 changes: 0 additions & 27 deletions test/arrayops.jl
Original file line number Diff line number Diff line change
Expand Up @@ -471,23 +471,6 @@ end
@test find(isascii, g) == Int[]
@test find(!iszero, (i % 2 for i in 1:10)) == 1:2:9
end
@testset "findn" begin
b = findn(fill(1,2,2,2,2))
@test (length(b[1]) == 16)
@test (length(b[2]) == 16)
@test (length(b[3]) == 16)
@test (length(b[4]) == 16)

#hand made case
a = ([2,1,2],[1,2,2],[2,2,2])
z = zeros(2,2,2)
for i = 1:3
z[a[1][i],a[2][i],a[3][i]] = 10
end
@test isequal(a,findn(z))

@test findn([1, 0, 2]) == ([1, 3], )
end

@testset "findmin findmax indmin indmax" begin
@test indmax([10,12,9,11]) == 2
Expand Down Expand Up @@ -1852,16 +1835,6 @@ end
fill!(B, 2)
@test all(x->x==2, B)

iall = repmat(1:size(A,1), 1, size(A,2))
jall = repmat((1:size(A,2))', size(A,1), 1)
i,j = findn(B)
@test vec(i) == vec(iall)
@test vec(j) == vec(jall)
fill!(S, 2)
i,j = findn(S)
@test vec(i) == vec(iall)
@test vec(j) == vec(jall)

copyto!(B, A)
copyto!(S, A)

Expand Down
2 changes: 2 additions & 0 deletions test/bitarray.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1105,6 +1105,8 @@ timesofar("datamove")
end

b1 = bitrand(n1, n2)
@check_bit_operation find(b1) Vector{CartesianIndex{2}}
@check_bit_operation find(!iszero, b1) Vector{CartesianIndex{2}}
@check_bit_operation findnz(b1) Tuple{Vector{Int}, Vector{Int}, BitArray}
end

Expand Down
5 changes: 2 additions & 3 deletions test/offsetarray.jl
Original file line number Diff line number Diff line change
Expand Up @@ -359,9 +359,8 @@ pmax, ipmax = findmax(parent(A))
@test A[iamax] == amax
@test amax == parent(A)[ipmax]
z = OffsetArray([0 0; 2 0; 0 0; 0 0], (-3,-1))
I,J = findn(z)
@test I == [-1]
@test J == [0]
I = find(!iszero, z)
@test I == [CartesianIndex(-1, 0)]
I,J,N = findnz(z)
@test I == [-1]
@test J == [0]
Expand Down