Skip to content

Commit 53191c8

Browse files
authored
Define a generic dense function (#72)
1 parent e8e89d3 commit 53191c8

File tree

4 files changed

+62
-10
lines changed

4 files changed

+62
-10
lines changed

Project.toml

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
name = "SparseArraysBase"
22
uuid = "0d5efcca-f356-4864-8770-e1ed8d78f208"
33
authors = ["ITensor developers <[email protected]> and contributors"]
4-
version = "0.7.3"
4+
version = "0.7.4"
55

66
[deps]
77
Accessors = "7d9f7c33-5ae7-4f3b-8dc6-eff91059b697"
@@ -10,9 +10,11 @@ ArrayLayouts = "4c555306-a7a7-4459-81d9-ec55ddd5c99a"
1010
DerivableInterfaces = "6c5e35bf-e59e-4898-b73c-732dcc4ba65f"
1111
Dictionaries = "85a47980-9c8c-11e8-2b9f-f7ca1fa99fb4"
1212
FillArrays = "1a297f60-69ca-5386-bcde-b61e274b549b"
13+
GPUArraysCore = "46192b85-c4d5-4398-a991-12ede77f4527"
1314
LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e"
1415
MapBroadcast = "ebd9b9da-f48d-417c-9660-449667d60261"
1516
Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c"
17+
TypeParameterAccessors = "7e5a90cf-f82e-492e-a09b-e3e26432c138"
1618

1719
[compat]
1820
Accessors = "0.1.41"
@@ -22,12 +24,14 @@ ArrayLayouts = "1.11.0"
2224
DerivableInterfaces = "0.5"
2325
Dictionaries = "0.4.3"
2426
FillArrays = "1.13.0"
27+
GPUArraysCore = "0.2.0"
2528
LinearAlgebra = "1.10"
2629
MapBroadcast = "0.1.5"
2730
Random = "1.10.0"
2831
SafeTestsets = "0.1"
2932
Suppressor = "0.2"
3033
Test = "1.10"
34+
TypeParameterAccessors = "0.4.3"
3135
julia = "1.10"
3236

3337
[extras]

src/abstractsparsearrayinterface.jl

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -39,15 +39,17 @@ unstoredsimilar(a::AbstractArray) = a
3939
# Generic functionality for converting to a
4040
# dense array, trying to preserve information
4141
# about the array (such as which device it is on).
42-
# TODO: Maybe call `densecopy`?
43-
# TODO: Make sure this actually preserves the device,
44-
# maybe use `TypeParameterAccessors.unwrap_array_type`.
45-
# TODO: Turn into an `@interface` function.
46-
function densearray(a::AbstractArray)
47-
# TODO: `set_ndims(unwrap_array_type(a), ndims(a))(a)`
48-
# Maybe define `densetype(a) = set_ndims(unwrap_array_type(a), ndims(a))`.
49-
# Or could use `unspecify_parameters(unwrap_array_type(a))(a)`.
50-
return Array(a)
42+
using TypeParameterAccessors: unspecify_type_parameters, unwrap_array, unwrap_array_type
43+
function densetype(arraytype::Type{<:AbstractArray})
44+
return unspecify_type_parameters(unwrap_array_type(arraytype))
45+
end
46+
# TODO: Ideally this would be defined as `densetype(typeof(a))` but that is less general right now since `unwrap_array_type` is defined on fewer arrays, since it is based on `parentype` rather than `parent`.
47+
function densetype(a::AbstractArray)
48+
return unspecify_type_parameters(typeof(unwrap_array(a)))
49+
end
50+
using GPUArraysCore: @allowscalar
51+
function dense(a::AbstractArray)
52+
return @allowscalar convert(densetype(a), a)
5153
end
5254

5355
# Minimal interface for `SparseArrayInterface`.

src/sparsearraydok.jl

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,3 +122,8 @@ end
122122
function ArrayLayouts.zero!(a::SparseArrayDOK)
123123
return zero!(a)
124124
end
125+
126+
# The fallback doesn't work since `SparseArrayDOK`
127+
# isn't a wrapper around `Array`.
128+
densetype(::SparseArrayDOK) = Array
129+
densetype(::Type{<:SparseArrayDOK}) = Array

test/test_dense.jl

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
using Adapt: adapt
2+
using JLArrays: JLArray
3+
using SparseArraysBase: dense, sparsezeros
4+
using Test: @test, @testset
5+
6+
elts = (Float32, ComplexF64)
7+
arrayts = (Array, JLArray)
8+
@testset "dense (arraytype=$arrayt, eltype=$elt)" for arrayt in arrayts, elt in elts
9+
dev(x) = adapt(arrayt, x)
10+
11+
@testset "SparseArrayDOK" begin
12+
s = sparsezeros(elt, 3, 4)
13+
s[1, 2] = 2
14+
d = dense(s)
15+
@test d isa Matrix{elt}
16+
@test d == [0 2 0 0; 0 0 0 0; 0 0 0 0]
17+
end
18+
19+
@testset "Custom sparse array" begin
20+
struct MySparseArrayDOK{T,N,S<:AbstractVector{T}} <: AbstractArray{T,N}
21+
storedvalues::S
22+
storedindices::Dict{CartesianIndex{N},Int}
23+
size::NTuple{N,Int}
24+
end
25+
Base.size(a::MySparseArrayDOK) = a.size
26+
function Base.getindex(a::MySparseArrayDOK{<:Any,N}, I::Vararg{Int,N}) where {N}
27+
storageindex = get(a.storedindices, CartesianIndex(I), nothing)
28+
isnothing(storageindex) && return zero(eltype(a))
29+
return a.storedvalues[storageindex]
30+
end
31+
Base.parent(a::MySparseArrayDOK) = a.storedvalues
32+
33+
s = MySparseArrayDOK(
34+
dev(elt[2, 4]), Dict([CartesianIndex(1, 2) => 1, CartesianIndex(3, 4) => 2]), (3, 4)
35+
)
36+
d = dense(s)
37+
@show typeof(d)
38+
@test d isa arrayt{elt,2}
39+
@test d == dev(elt[0 2 0 0; 0 0 0 0; 0 0 0 4])
40+
end
41+
end

0 commit comments

Comments
 (0)