Skip to content

Commit caee0b1

Browse files
committed
merge constructors
1 parent be04ae0 commit caee0b1

13 files changed

+187
-74
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
name: "Integration Test Request"
2+
3+
on:
4+
issue_comment:
5+
types: [created]
6+
7+
jobs:
8+
integrationrequest:
9+
if: |
10+
github.event.issue.pull_request &&
11+
contains(fromJSON('["OWNER", "COLLABORATOR", "MEMBER"]'), github.event.comment.author_association)
12+
uses: ITensor/ITensorActions/.github/workflows/IntegrationTestRequest.yml@main
13+
with:
14+
localregistry: https://github.com/ITensor/ITensorRegistry.git

.github/workflows/Register.yml

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
name: Register Package
2+
on:
3+
workflow_dispatch:
4+
pull_request:
5+
types:
6+
- closed
7+
paths:
8+
- 'Project.toml'
9+
branches:
10+
- 'master'
11+
- 'main'
12+
jobs:
13+
Register:
14+
if: github.event_name == 'workflow_dispatch' || github.event.pull_request.merged == true
15+
uses: "ITensor/ITensorActions/.github/workflows/Registrator.yml@main"
16+
with:
17+
localregistry: ITensor/ITensorRegistry

LICENSE

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
MIT License
22

3-
Copyright (c) 2024 ITensor developers
3+
Copyright (c) 2025 ITensor developers
44

55
Permission is hereby granted, free of charge, to any person obtaining a copy
66
of this software and associated documentation files (the "Software"), to deal

Project.toml

+2
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ Dictionaries = "85a47980-9c8c-11e8-2b9f-f7ca1fa99fb4"
1111
FillArrays = "1a297f60-69ca-5386-bcde-b61e274b549b"
1212
LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e"
1313
MapBroadcast = "ebd9b9da-f48d-417c-9660-449667d60261"
14+
Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c"
1415

1516
[compat]
1617
Accessors = "0.1.41"
@@ -21,6 +22,7 @@ Dictionaries = "0.4.3"
2122
FillArrays = "1.13.0"
2223
LinearAlgebra = "1.10"
2324
MapBroadcast = "0.1.5"
25+
Random = "1.10.0"
2426
SafeTestsets = "0.1"
2527
Suppressor = "0.2"
2628
Test = "1.10"

README.md

+6-6
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ using SparseArraysBase:
4848
zero!
4949
using Test: @test, @test_throws
5050

51-
a = SparseArrayDOK{Float64}(2, 2)
51+
a = SparseArrayDOK{Float64}(undef, 2, 2)
5252
````
5353

5454
AbstractArray interface:
@@ -122,32 +122,32 @@ b = a[1:2, 2]
122122
@test b == [12, 0]
123123
@test storedlength(b) == 1
124124

125-
a = SparseArrayDOK{Float64}(2, 2)
125+
a = SparseArrayDOK{Float64}(undef, 2, 2)
126126
a .= 2
127127
for I in eachindex(a)
128128
@test a[I] == 2
129129
end
130130
@test storedlength(a) == length(a)
131131

132-
a = SparseArrayDOK{Float64}(2, 2)
132+
a = SparseArrayDOK{Float64}(undef, 2, 2)
133133
fill!(a, 2)
134134
for I in eachindex(a)
135135
@test a[I] == 2
136136
end
137137
@test storedlength(a) == length(a)
138138

139-
a = SparseArrayDOK{Float64}(2, 2)
139+
a = SparseArrayDOK{Float64}(undef, 2, 2)
140140
fill!(a, 0)
141141
@test iszero(a)
142142
@test iszero(storedlength(a))
143143

144-
a = SparseArrayDOK{Float64}(2, 2)
144+
a = SparseArrayDOK{Float64}(undef, 2, 2)
145145
a[1, 2] = 12
146146
zero!(a)
147147
@test iszero(a)
148148
@test iszero(storedlength(a))
149149

150-
a = SparseArrayDOK{Float64}(2, 2)
150+
a = SparseArrayDOK{Float64}(undef, 2, 2)
151151
a[1, 2] = 12
152152
b = zero(a)
153153
@test iszero(b)

docs/make.jl

+1-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ makedocs(;
1616
edit_link="main",
1717
assets=String[],
1818
),
19-
pages=["Home" => "index.md"],
19+
pages=["Home" => "index.md", "Reference" => "reference.md"],
2020
)
2121

2222
deploydocs(;

docs/src/reference.md

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
# Reference
2+
3+
```@autodocs
4+
Modules = [SparseArraysBase]
5+
```

examples/README.jl

+6-6
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ using SparseArraysBase:
5353
zero!
5454
using Test: @test, @test_throws
5555

56-
a = SparseArrayDOK{Float64}(2, 2)
56+
a = SparseArrayDOK{Float64}(undef, 2, 2)
5757

5858
# AbstractArray interface:
5959

@@ -118,32 +118,32 @@ b = a[1:2, 2]
118118
@test b == [12, 0]
119119
@test storedlength(b) == 1
120120

121-
a = SparseArrayDOK{Float64}(2, 2)
121+
a = SparseArrayDOK{Float64}(undef, 2, 2)
122122
a .= 2
123123
for I in eachindex(a)
124124
@test a[I] == 2
125125
end
126126
@test storedlength(a) == length(a)
127127

128-
a = SparseArrayDOK{Float64}(2, 2)
128+
a = SparseArrayDOK{Float64}(undef, 2, 2)
129129
fill!(a, 2)
130130
for I in eachindex(a)
131131
@test a[I] == 2
132132
end
133133
@test storedlength(a) == length(a)
134134

135-
a = SparseArrayDOK{Float64}(2, 2)
135+
a = SparseArrayDOK{Float64}(undef, 2, 2)
136136
fill!(a, 0)
137137
@test iszero(a)
138138
@test iszero(storedlength(a))
139139

140-
a = SparseArrayDOK{Float64}(2, 2)
140+
a = SparseArrayDOK{Float64}(undef, 2, 2)
141141
a[1, 2] = 12
142142
zero!(a)
143143
@test iszero(a)
144144
@test iszero(storedlength(a))
145145

146-
a = SparseArrayDOK{Float64}(2, 2)
146+
a = SparseArrayDOK{Float64}(undef, 2, 2)
147147
a[1, 2] = 12
148148
b = zero(a)
149149
@test iszero(b)

src/abstractsparsearray.jl

+59
Original file line numberDiff line numberDiff line change
@@ -50,3 +50,62 @@ function Base.replace_in_print_matrix(
5050
)
5151
return isstored(A, CartesianIndex(i, j)) ? s : Base.replace_with_centered_mark(s)
5252
end
53+
54+
# Special-purpose constructors
55+
# ----------------------------
56+
using Random: Random, AbstractRNG, default_rng
57+
@doc """
58+
spzeros([T::Type], dims) -> A::SparseArrayDOK{T}
59+
60+
Create an empty size `dims` sparse array.
61+
The optional `T` argument specifies the element type, which defaults to `Float64`.
62+
""" spzeros
63+
64+
spzeros(dims::Dims) = spzeros(Float64, dims)
65+
spzeros(::Type{T}, dims::Dims) where {T} = SparseArrayDOK{T}(undef, dims)
66+
67+
@doc """
68+
sprand([rng], [T::Type], dims; density::Real=0.5, rfn::Function=rand) -> A::SparseArrayDOK{T}
69+
70+
Create a random size `dims` sparse array in which the probability of any element being stored is independently given by `density`.
71+
The optional `rng` argument specifies a random number generator, see also `Random`.
72+
The optional `T` argument specifies the element type, which defaults to `Float64`.
73+
The optional `rfn` argument can be used to control the type of random elements.
74+
75+
See also [`sprand!`](@ref).
76+
""" sprand
77+
78+
function sprand(::Type{T}, dims::Dims; kwargs...) where {T}
79+
return sprand(default_rng(), T, dims; kwargs...)
80+
end
81+
sprand(dims::Dims; kwargs...) = sprand(default_rng(), Float64, dims; kwargs...)
82+
function sprand(rng::AbstractRNG, dims::Dims; kwargs...)
83+
return sprand(rng, Float64, dims; kwargs...)
84+
end
85+
function sprand(rng::AbstractRNG, ::Type{T}, dims::Dims; kwargs...) where {T}
86+
A = SparseArrayDOK{T}(undef, dims)
87+
sprand!(rng, A; kwargs...)
88+
return A
89+
end
90+
91+
@doc """
92+
sprand!([rng], A::AbstractArray; density::Real=0.5, rfn::Function=rand) -> A
93+
94+
Overwrite part of an array with random entries, where the probability of overwriting is independently given by `density`.
95+
The optional `rng` argument specifies a random number generator, see also `Random`.
96+
The optional `rfn` argument can be used to control the type of random elements.
97+
98+
See also [`sprand`](@ref).
99+
""" sprand!
100+
101+
sprand!(A::AbstractArray; kwargs...) = sprand!(default_rng(), A; kwargs...)
102+
function sprand!(
103+
rng::AbstractRNG, A::AbstractArray; density::Real=0.5, rfn::Function=Random.rand
104+
)
105+
ArrayLayouts.zero!(A)
106+
rand_inds = Random.randsubseq(rng, eachindex(A), density)
107+
rand_entries = rfn(rng, eltype(A), length(rand_inds))
108+
for (I, v) in zip(rand_inds, rand_entries)
109+
A[I] = v
110+
end
111+
end

src/sparsearraydok.jl

+44-19
Original file line numberDiff line numberDiff line change
@@ -1,44 +1,69 @@
11
using Accessors: @set
2-
using Dictionaries: Dictionary, IndexError, set!
2+
using Dictionaries: AbstractDictionary, Dictionary, IndexError, set!
33

44
function default_getunstoredindex(a::AbstractArray, I::Int...)
55
return zero(eltype(a))
66
end
77

8+
const DOKStorage{T,N} = Dictionary{CartesianIndex{N},T}
9+
810
struct SparseArrayDOK{T,N,F} <: AbstractSparseArray{T,N}
9-
storage::Dictionary{CartesianIndex{N},T}
11+
storage::DOKStorage{T,N}
1012
size::NTuple{N,Int}
1113
getunstoredindex::F
12-
end
1314

14-
function set_getunstoredindex(a::SparseArrayDOK, f)
15-
@set a.getunstoredindex = f
16-
return a
17-
end
18-
19-
using DerivableInterfaces: DerivableInterfaces
20-
# This defines the destination type of various operations in DerivableInterfaces.jl.
15+
# bare constructor
16+
function SparseArrayDOK{T,N,F}(
17+
::UndefInitializer, size::Dims{N}, getunstoredindex::F
18+
) where {T,N,F}
19+
storage = DOKStorage{T,N}()
20+
return new{T,N,F}(storage, size, getunstoredindex)
21+
end
2122

22-
Base.similar(::AbstractSparseArrayInterface, T::Type, ax) = SparseArrayDOK{T}(undef, ax)
23+
# unchecked constructor from data
24+
function SparseArrayDOK{T,N,F}(
25+
storage::DOKStorage{T,N}, size::Dims{N}, getunstoredindex::F
26+
) where {T,N,F}
27+
return new{T,N,F}(storage, size, getunstoredindex)
28+
end
29+
end
2330

24-
function SparseArrayDOK{T,N}(size::Vararg{Int,N}) where {T,N}
25-
getunstoredindex = default_getunstoredindex
31+
# undef constructors
32+
function SparseArrayDOK{T}(
33+
::UndefInitializer, dims::Dims, getunstoredindex=default_getunstoredindex
34+
) where {T}
35+
all((0), dims) || throw(ArgumentError("Invalid dimensions: $dims"))
36+
N = length(dims)
2637
F = typeof(getunstoredindex)
27-
return SparseArrayDOK{T,N,F}(Dictionary{CartesianIndex{N},T}(), size, getunstoredindex)
38+
return SparseArrayDOK{T,N,F}(undef, dims, getunstoredindex)
2839
end
29-
30-
function SparseArrayDOK{T}(::UndefInitializer, size::Tuple{Vararg{Int}}) where {T}
31-
return SparseArrayDOK{T,length(size)}(size...)
40+
function SparseArrayDOK{T}(::UndefInitializer, dims::Int...) where {T}
41+
return SparseArrayDOK{T}(undef, dims)
3242
end
3343

34-
function SparseArrayDOK{T}(size::Int...) where {T}
35-
return SparseArrayDOK{T,length(size)}(size...)
44+
# checked constructor from data: use `setindex!` to validate input
45+
# does not take ownership of `storage`!
46+
function SparseArrayDOK(
47+
storage::Union{AbstractDictionary{I,T},AbstractDict{I,T}}, dims::Dims{N}, unstored...
48+
) where {N,I<:Union{Int,CartesianIndex{N}},T}
49+
A = SparseArrayDOK{T}(undef, dims, unstored...)
50+
for (i, v) in pairs(storage)
51+
A[i] = v
52+
end
53+
return A
3654
end
3755

3856
function SparseArrayDOK{T}(::UndefInitializer, axes::Tuple) where {T}
3957
return SparseArrayDOK{T}(undef, Base.to_shape(axes))
4058
end
4159

60+
function set_getunstoredindex(a::SparseArrayDOK, f)
61+
@set a.getunstoredindex = f
62+
return a
63+
end
64+
65+
Base.similar(::AbstractSparseArrayInterface, T::Type, ax) = SparseArrayDOK{T}(undef, ax)
66+
4267
using DerivableInterfaces: @array_aliases
4368
# Define `SparseMatrixDOK`, `AnySparseArrayDOK`, etc.
4469
@array_aliases SparseArrayDOK

test/runtests.jl

+4-2
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,11 @@ isexamplefile(fn) =
2424
# tests in groups based on folder structure
2525
for testgroup in filter(isdir, readdir(@__DIR__))
2626
if GROUP == "ALL" || GROUP == uppercase(testgroup)
27-
for file in filter(istestfile, readdir(joinpath(@__DIR__, testgroup); join=true))
27+
groupdir = joinpath(@__DIR__, testgroup)
28+
for file in filter(istestfile, readdir(groupdir))
29+
filename = joinpath(groupdir, file)
2830
@eval @safetestset $file begin
29-
include($file)
31+
include($filename)
3032
end
3133
end
3234
end

test/test_linalg.jl

+1-12
Original file line numberDiff line numberDiff line change
@@ -5,17 +5,6 @@ using StableRNGs: StableRNG
55

66
const rng = StableRNG(123)
77

8-
# TODO: add this to main package
9-
function sprand(rng::Random.AbstractRNG, ::Type{T}, sz::Base.Dims; p::Real=0.5) where {T}
10-
A = SparseArrayDOK{T}(undef, sz)
11-
for I in eachindex(A)
12-
if rand(rng) < p
13-
A[I] = rand(rng, T)
14-
end
15-
end
16-
return A
17-
end
18-
198
@testset "mul!" begin
209
T = Float64
2110
szA = (2, 2)
@@ -31,7 +20,7 @@ end
3120
@test mul!(copy(C), A, B) check1
3221

3322
α = rand(rng, T)
34-
β = rand(rng, T)
23+
β = rand(rng, T) * false
3524
check2 = mul!(Array(C), Array(A), Array(B), α, β)
3625
@test mul!(copy(C), A, B, α, β) check2
3726
end

0 commit comments

Comments
 (0)