Skip to content

Commit ca6cfd1

Browse files
Tokazamachriselrod
andauthored
Use missing instead of nothing for dynamic values (#232)
* Use `missing` instead of `nothing` for dynamic values * Tests pass locally, fixes: missing == missing -> missing means we need === for comparisons, and Static.find_first_eq still returns nothing on failure, like Base.findfirst * Add test/Project.toml * Updates for Static v0.5.1 * Remove `reduce_tup` from docs now that it's in Static * Move block/banded stuff to requires Co-authored-by: Chris Elrod <[email protected]>
1 parent 687fdfb commit ca6cfd1

15 files changed

+390
-517
lines changed

Project.toml

Lines changed: 2 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
name = "ArrayInterface"
22
uuid = "4fba245c-0d91-5ea0-9b3e-6abc04ee57a9"
3-
version = "3.2.2"
3+
version = "4"
44

55
[deps]
66
Compat = "34da2185-b29b-5c13-b0c7-acf172513d20"
@@ -14,20 +14,5 @@ Static = "aedffcd0-7271-4cad-89d0-dc628f76c6d3"
1414
Compat = "3.37"
1515
IfElse = "0.1"
1616
Requires = "0.5, 1.0"
17-
Static = "0.4"
17+
Static = "0.5"
1818
julia = "1.2"
19-
20-
[extras]
21-
Aqua = "4c88cf16-eb10-579e-8560-4a9242c79595"
22-
BandedMatrices = "aae01518-5342-5314-be14-df237901396f"
23-
BlockBandedMatrices = "ffab5731-97b5-5995-9138-79e8c1846df0"
24-
IfElse = "615f187c-cbe4-4ef1-ba3b-2fcf58d6d173"
25-
LabelledArrays = "2ee39098-c373-598a-b85f-a56591580800"
26-
OffsetArrays = "6fe1bfb0-de20-5000-8ca7-80f57d26f881"
27-
Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c"
28-
StaticArrays = "90137ffa-7385-5640-81b9-e52037218182"
29-
SuiteSparse = "4607b0f0-06f3-5cda-b6b1-a6196a1729e9"
30-
Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"
31-
32-
[targets]
33-
test = ["Test", "LabelledArrays", "StaticArrays", "BandedMatrices", "BlockBandedMatrices", "SuiteSparse", "Random", "OffsetArrays", "Aqua", "IfElse"]

docs/src/api.md

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,6 @@ ArrayInterface.matrix_colors
5757
ArrayInterface.offset1
5858
ArrayInterface.offsets
5959
ArrayInterface.parent_type
60-
ArrayInterface.reduce_tup
6160
ArrayInterface.restructure
6261
ArrayInterface.safevec
6362
ArrayInterface.setindex!

docs/src/index.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ julia> ArrayInterface.size(a)
4444
(static(1), 3)
4545

4646
julia> ArrayInterface.known_size(typeof(a))
47-
(1, nothing)
47+
(1, missing)
4848

4949
```
5050

@@ -62,8 +62,8 @@ Methods should avoid forcing conversion to static sizes when dynamic sizes could
6262
Fore example, `fxn(x) = _fxn(Static.static(ArrayInterface.size(x)), x)` would result in dynamic dispatch if `x` is an instance of `Matrix`.
6363
Additionally, `ArrayInterface.size` should only be used outside of generated functions to avoid possible world age issues.
6464

65-
Generally, `ArrayInterface.size` uses the return of `known_size` to form a static value for those dimensions with known length and only queries dimensions corresponding to `nothing`.
66-
For example, the previous example had a known size of `(1, nothing)`.
65+
Generally, `ArrayInterface.size` uses the return of `known_size` to form a static value for those dimensions with known length and only queries dimensions corresponding to `missing`.
66+
For example, the previous example had a known size of `(1, missing)`.
6767
Therefore, `ArrayInterface.size` would have compile time information about the first dimension returned as `static(1)` and would only look up the size of the second dimension at run time.
6868
This means the above example `ArrayInterface.size(a)` would lower to code similar to this at compile time: `Static.StaticInt(1), Base.arraysize(x, 1)`.
6969
Generic support for `ArrayInterface.known_size` relies on calling `known_length` for each type returned from `axes_types`.
@@ -155,7 +155,7 @@ using ArrayInterface: axes_types, parent_type, to_dims
155155
for dim in 1:ndims(A)
156156
# offset relative to parent array
157157
O = relative_known_offsets(A, dim)
158-
if O === nothing # offset is not known at compile time and is an `Int`
158+
if O === missing # offset is not known at compile time and is an `Int`
159159
push!(out.args, :(IdOffsetRange{Int, axes_types($P, $(static(dim)))}))
160160
else # offset is known, therefore it is a `StaticInt`
161161
push!(out.args, :(IdOffsetRange{StaticInt{$O}, axes_types($P, $(static(dim))}))

src/ArrayInterface.jl

Lines changed: 214 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@ using Requires
55
using LinearAlgebra
66
using SparseArrays
77
using Static
8-
using Static: Zero, One, nstatic, _get_tuple, eq, ne, gt, ge, lt, le, eachop, eachop_tuple,
9-
find_first_eq, permute, invariant_permutation
8+
using Static: Zero, One, nstatic, eq, ne, gt, ge, lt, le, eachop, eachop_tuple,
9+
find_first_eq, permute, invariant_permutation, field_type, reduce_tup
1010
using Base.Cartesian
1111
import Compat
1212

@@ -81,10 +81,10 @@ buffer(x::SparseMatrixCSC) = getfield(x, :nzval)
8181
buffer(x::SparseVector) = getfield(x, :nzval)
8282

8383
"""
84-
known_length(::Type{T}) -> Union{Int,Nothing}
84+
known_length(::Type{T}) -> Union{Int,Missing}
8585
8686
If `length` of an instance of type `T` is known at compile time, return it.
87-
Otherwise, return `nothing`.
87+
Otherwise, return `missing`.
8888
"""
8989
known_length(x) = known_length(typeof(x))
9090
known_length(::Type{<:NamedTuple{L}}) where {L} = length(L)
@@ -95,13 +95,11 @@ known_length(::Type{<:Number}) = 1
9595
known_length(::Type{<:AbstractCartesianIndex{N}}) where {N} = N
9696
function known_length(::Type{T}) where {T}
9797
if parent_type(T) <: T
98-
return nothing
98+
return missing
9999
else
100-
return _known_length(known_size(T))
100+
return prod(known_size(T))
101101
end
102102
end
103-
_known_length(x::Tuple{Vararg{Union{Nothing,Int}}}) = nothing
104-
_known_length(x::Tuple{Vararg{Int}}) = prod(x)
105103

106104
"""
107105
can_change_size(::Type{T}) -> Bool
@@ -419,10 +417,10 @@ Indicates the most efficient way to access elements from the collection in low-l
419417
For `GPUArrays`, will return `ArrayInterface.GPU()`.
420418
For `AbstractArray` supporting a `pointer` method, returns `ArrayInterface.CPUPointer()`.
421419
For other `AbstractArray`s and `Tuple`s, returns `ArrayInterface.CPUIndex()`.
422-
Otherwise, returns `nothing`.
420+
Otherwise, returns `missing`.
423421
"""
424422
device(A) = device(typeof(A))
425-
device(::Type) = nothing
423+
device(::Type) = missing
426424
device(::Type{<:Tuple}) = CPUTuple()
427425
device(::Type{T}) where {T<:Array} = CPUPointer()
428426
device(::Type{T}) where {T<:AbstractArray} = _device(has_parent(T), T)
@@ -601,7 +599,7 @@ end
601599

602600
function Base.length(A::AbstractArray2)
603601
len = known_length(A)
604-
if len === nothing
602+
if len === missing
605603
return Int(prod(size(A)))
606604
else
607605
return Int(len)
@@ -807,6 +805,53 @@ function __init__()
807805
end
808806

809807
@require BandedMatrices = "aae01518-5342-5314-be14-df237901396f" begin
808+
struct BandedMatrixIndex <: MatrixIndex
809+
count::Int
810+
rowsize::Int
811+
colsize::Int
812+
bandinds::Array{Int,1}
813+
bandsizes::Array{Int,1}
814+
isrow::Bool
815+
end
816+
817+
Base.firstindex(i::BandedMatrixIndex) = 1
818+
Base.lastindex(i::BandedMatrixIndex) = i.count
819+
Base.length(i::BandedMatrixIndex) = lastindex(i)
820+
@propagate_inbounds function Base.getindex(ind::BandedMatrixIndex, i::Int)
821+
@boundscheck 1 <= i <= ind.count || throw(BoundsError(ind, i))
822+
_i = i
823+
p = 1
824+
while _i - ind.bandsizes[p] > 0
825+
_i -= ind.bandsizes[p]
826+
p += 1
827+
end
828+
bandind = ind.bandinds[p]
829+
startfromone = !xor(ind.isrow, (bandind > 0))
830+
if startfromone
831+
return _i
832+
else
833+
return _i + abs(bandind)
834+
end
835+
end
836+
837+
function _bandsize(bandind, rowsize, colsize)
838+
-(rowsize - 1) <= bandind <= colsize - 1 || throw(ErrorException("Invalid Bandind"))
839+
if (bandind * (colsize - rowsize) > 0) & (abs(bandind) <= abs(colsize - rowsize))
840+
return min(rowsize, colsize)
841+
elseif bandind * (colsize - rowsize) <= 0
842+
return min(rowsize, colsize) - abs(bandind)
843+
else
844+
return min(rowsize, colsize) - abs(bandind) + abs(colsize - rowsize)
845+
end
846+
end
847+
848+
function BandedMatrixIndex(rowsize, colsize, lowerbandwidth, upperbandwidth, isrow)
849+
upperbandwidth > -lowerbandwidth || throw(ErrorException("Invalid Bandwidths"))
850+
bandinds = upperbandwidth:-1:-lowerbandwidth
851+
bandsizes = [_bandsize(band, rowsize, colsize) for band in bandinds]
852+
BandedMatrixIndex(sum(bandsizes), rowsize, colsize, bandinds, bandsizes, isrow)
853+
end
854+
810855
function findstructralnz(x::BandedMatrices.BandedMatrix)
811856
l, u = BandedMatrices.bandwidths(x)
812857
rowsize, colsize = Base.size(x)
@@ -829,6 +874,82 @@ function __init__()
829874

830875
@require BlockBandedMatrices = "ffab5731-97b5-5995-9138-79e8c1846df0" begin
831876
@require BlockArrays = "8e7c35d0-a365-5155-bbbb-fb81a777f24e" begin
877+
struct BlockBandedMatrixIndex <: MatrixIndex
878+
count::Int
879+
refinds::Array{Int,1}
880+
refcoords::Array{Int,1}# storing col or row inds at ref points
881+
isrow::Bool
882+
end
883+
Base.firstindex(i::BlockBandedMatrixIndex) = 1
884+
Base.lastindex(i::BlockBandedMatrixIndex) = i.count
885+
Base.length(i::BlockBandedMatrixIndex) = lastindex(i)
886+
function BlockBandedMatrixIndex(nrowblock, ncolblock, rowsizes, colsizes, l, u)
887+
blockrowind = BandedMatrixIndex(nrowblock, ncolblock, l, u, true)
888+
blockcolind = BandedMatrixIndex(nrowblock, ncolblock, l, u, false)
889+
sortedinds = sort(
890+
[(blockrowind[i], blockcolind[i]) for i = 1:length(blockrowind)],
891+
by = x -> x[1],
892+
)
893+
sort!(sortedinds, by = x -> x[2], alg = InsertionSort)# stable sort keeps the second index in order
894+
refinds = Array{Int,1}()
895+
refrowcoords = Array{Int,1}()
896+
refcolcoords = Array{Int,1}()
897+
rowheights = pushfirst!(copy(rowsizes), 1)
898+
cumsum!(rowheights, rowheights)
899+
blockheight = 0
900+
blockrow = 1
901+
blockcol = 1
902+
currenti = 1
903+
lastrowind = sortedinds[1][1] - 1
904+
lastcolind = sortedinds[1][2]
905+
for ind in sortedinds
906+
rowind, colind = ind
907+
if colind == lastcolind
908+
if rowind > lastrowind
909+
blockheight += rowsizes[rowind]
910+
end
911+
else
912+
for j = blockcol:blockcol+colsizes[lastcolind]-1
913+
push!(refinds, currenti)
914+
push!(refrowcoords, blockrow)
915+
push!(refcolcoords, j)
916+
currenti += blockheight
917+
end
918+
blockcol += colsizes[lastcolind]
919+
blockrow = rowheights[rowind]
920+
blockheight = rowsizes[rowind]
921+
end
922+
lastcolind = colind
923+
lastrowind = rowind
924+
end
925+
for j = blockcol:blockcol+colsizes[lastcolind]-1
926+
push!(refinds, currenti)
927+
push!(refrowcoords, blockrow)
928+
push!(refcolcoords, j)
929+
currenti += blockheight
930+
end
931+
push!(refinds, currenti)# guard
932+
push!(refrowcoords, -1)
933+
push!(refcolcoords, -1)
934+
rowindobj = BlockBandedMatrixIndex(currenti - 1, refinds, refrowcoords, true)
935+
colindobj = BlockBandedMatrixIndex(currenti - 1, refinds, refcolcoords, false)
936+
rowindobj, colindobj
937+
end
938+
@propagate_inbounds function Base.getindex(ind::BlockBandedMatrixIndex, i::Int)
939+
@boundscheck 1 <= i <= ind.count || throw(BoundsError(ind, i))
940+
p = 1
941+
while i - ind.refinds[p] >= 0
942+
p += 1
943+
end
944+
p -= 1
945+
_i = i - ind.refinds[p]
946+
if ind.isrow
947+
return ind.refcoords[p] + _i
948+
else
949+
return ind.refcoords[p]
950+
end
951+
end
952+
832953
function findstructralnz(x::BlockBandedMatrices.BlockBandedMatrix)
833954
l, u = BlockBandedMatrices.blockbandwidths(x)
834955
nrowblock = BlockBandedMatrices.blocksize(x, 1)
@@ -844,6 +965,87 @@ function __init__()
844965
u,
845966
)
846967
end
968+
struct BandedBlockBandedMatrixIndex <: MatrixIndex
969+
count::Int
970+
refinds::Array{Int,1}
971+
refcoords::Array{Int,1}# storing col or row inds at ref points
972+
reflocalinds::Array{BandedMatrixIndex,1}
973+
isrow::Bool
974+
end
975+
Base.firstindex(i::BandedBlockBandedMatrixIndex) = 1
976+
Base.lastindex(i::BandedBlockBandedMatrixIndex) = i.count
977+
Base.length(i::BandedBlockBandedMatrixIndex) = lastindex(i)
978+
@propagate_inbounds function Base.getindex(ind::BandedBlockBandedMatrixIndex, i::Int)
979+
@boundscheck 1 <= i <= ind.count || throw(BoundsError(ind, i))
980+
p = 1
981+
while i - ind.refinds[p] >= 0
982+
p += 1
983+
end
984+
p -= 1
985+
_i = i - ind.refinds[p] + 1
986+
ind.reflocalinds[p][_i] + ind.refcoords[p] - 1
987+
end
988+
989+
990+
function BandedBlockBandedMatrixIndex(
991+
nrowblock,
992+
ncolblock,
993+
rowsizes,
994+
colsizes,
995+
l,
996+
u,
997+
lambda,
998+
mu,
999+
)
1000+
blockrowind = BandedMatrixIndex(nrowblock, ncolblock, l, u, true)
1001+
blockcolind = BandedMatrixIndex(nrowblock, ncolblock, l, u, false)
1002+
sortedinds = sort(
1003+
[(blockrowind[i], blockcolind[i]) for i = 1:length(blockrowind)],
1004+
by = x -> x[1],
1005+
)
1006+
sort!(sortedinds, by = x -> x[2], alg = InsertionSort)# stable sort keeps the second index in order
1007+
rowheights = pushfirst!(copy(rowsizes), 1)
1008+
cumsum!(rowheights, rowheights)
1009+
colwidths = pushfirst!(copy(colsizes), 1)
1010+
cumsum!(colwidths, colwidths)
1011+
currenti = 1
1012+
refinds = Array{Int,1}()
1013+
refrowcoords = Array{Int,1}()
1014+
refcolcoords = Array{Int,1}()
1015+
reflocalrowinds = Array{BandedMatrixIndex,1}()
1016+
reflocalcolinds = Array{BandedMatrixIndex,1}()
1017+
for ind in sortedinds
1018+
rowind, colind = ind
1019+
localrowind =
1020+
BandedMatrixIndex(rowsizes[rowind], colsizes[colind], lambda, mu, true)
1021+
localcolind =
1022+
BandedMatrixIndex(rowsizes[rowind], colsizes[colind], lambda, mu, false)
1023+
push!(refinds, currenti)
1024+
push!(refrowcoords, rowheights[rowind])
1025+
push!(refcolcoords, colwidths[colind])
1026+
push!(reflocalrowinds, localrowind)
1027+
push!(reflocalcolinds, localcolind)
1028+
currenti += localrowind.count
1029+
end
1030+
push!(refinds, currenti)
1031+
push!(refrowcoords, -1)
1032+
push!(refcolcoords, -1)
1033+
rowindobj = BandedBlockBandedMatrixIndex(
1034+
currenti - 1,
1035+
refinds,
1036+
refrowcoords,
1037+
reflocalrowinds,
1038+
true,
1039+
)
1040+
colindobj = BandedBlockBandedMatrixIndex(
1041+
currenti - 1,
1042+
refinds,
1043+
refcolcoords,
1044+
reflocalcolinds,
1045+
false,
1046+
)
1047+
rowindobj, colindobj
1048+
end
8471049

8481050
function findstructralnz(x::BlockBandedMatrices.BandedBlockBandedMatrix)
8491051
l, u = BlockBandedMatrices.blockbandwidths(x)
@@ -936,7 +1138,7 @@ function __init__()
9361138
Static.eachop_tuple(_offset_axis_type, Static.nstatic(Val(ndims(T))), ArrayInterface.parent_type(T))
9371139
end
9381140
function ArrayInterface.known_offsets(::Type{A}) where {A<:OffsetArrays.OffsetArray}
939-
ntuple(identity -> nothing, Val(ndims(A)))
1141+
ntuple(identity -> missing, Val(ndims(A)))
9401142
end
9411143
function ArrayInterface.offsets(A::OffsetArrays.OffsetArray)
9421144
map(+, ArrayInterface.offsets(parent(A)), relative_offsets(A))

0 commit comments

Comments
 (0)