Skip to content

[WIP] DerivableInterfaces refactor #39

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 19 commits into
base: main
Choose a base branch
from
Draft
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
8 changes: 4 additions & 4 deletions .github/workflows/IntegrationTest.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,10 @@ jobs:
name: "IntegrationTest"
strategy:
matrix:
repo:
- 'ITensor/BlockSparseArrays.jl'
- 'ITensor/DiagonalArrays.jl'
pkg:
- 'BlockSparseArrays'
- 'DiagonalArrays'
uses: "ITensor/ITensorActions/.github/workflows/IntegrationTest.yml@main"
with:
localregistry: "https://github.com/ITensor/ITensorRegistry.git"
repo: "${{ matrix.repo }}"
pkg: "${{ matrix.pkg }}"
14 changes: 14 additions & 0 deletions .github/workflows/IntegrationTestRequest.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
name: "Integration Test Request"

on:
issue_comment:
types: [created]

jobs:
integrationrequest:
if: |
github.event.issue.pull_request &&
contains(fromJSON('["OWNER", "COLLABORATOR", "MEMBER"]'), github.event.comment.author_association)
uses: ITensor/ITensorActions/.github/workflows/IntegrationTestRequest.yml@main
with:
localregistry: https://github.com/ITensor/ITensorRegistry.git
25 changes: 13 additions & 12 deletions .github/workflows/Register.yml
Original file line number Diff line number Diff line change
@@ -1,16 +1,17 @@
name: Register Package
on:
workflow_dispatch:
inputs:
version:
description: Version to register or component to bump
required: true
pull_request:
types:
- closed
paths:
- 'Project.toml'
branches:
- 'master'
- 'main'
jobs:
register:
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- uses: julia-actions/RegisterAction@latest
with:
token: ${{ secrets.GITHUB_TOKEN }}
Register:
if: github.event_name == 'workflow_dispatch' || github.event.pull_request.merged == true
uses: "ITensor/ITensorActions/.github/workflows/Registrator.yml@main"
with:
localregistry: ITensor/ITensorRegistry
24 changes: 24 additions & 0 deletions .github/workflows/Registrator.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
name: Register Package
on:
workflow_dispatch:
pull_request:
types:
- closed
paths:
- 'Project.toml'
branches:
- 'master'
- 'main'

permissions:
contents: write
pull-requests: write

jobs:
Register:
if: github.event_name == 'workflow_dispatch' || github.event.pull_request.merged == true
uses: "ITensor/ITensorActions/.github/workflows/Registrator.yml@main"
with:
localregistry: ITensor/ITensorRegistry
secrets:
REGISTRATOR_KEY: ${{ secrets.REGISTRATOR_KEY }}
2 changes: 1 addition & 1 deletion LICENSE
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
MIT License

Copyright (c) 2024 ITensor developers
Copyright (c) 2025 ITensor developers

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
Expand Down
4 changes: 3 additions & 1 deletion Project.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
name = "SparseArraysBase"
uuid = "0d5efcca-f356-4864-8770-e1ed8d78f208"
authors = ["ITensor developers <[email protected]> and contributors"]
version = "0.2.11"
version = "0.3.0"

[deps]
Accessors = "7d9f7c33-5ae7-4f3b-8dc6-eff91059b697"
Expand All @@ -11,6 +11,7 @@ Dictionaries = "85a47980-9c8c-11e8-2b9f-f7ca1fa99fb4"
FillArrays = "1a297f60-69ca-5386-bcde-b61e274b549b"
LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e"
MapBroadcast = "ebd9b9da-f48d-417c-9660-449667d60261"
Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c"

[compat]
Accessors = "0.1.41"
Expand All @@ -21,6 +22,7 @@ Dictionaries = "0.4.3"
FillArrays = "1.13.0"
LinearAlgebra = "1.10"
MapBroadcast = "0.1.5"
Random = "1.10.0"
SafeTestsets = "0.1"
Suppressor = "0.2"
Test = "1.10"
Expand Down
12 changes: 6 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ using SparseArraysBase:
zero!
using Test: @test, @test_throws

a = SparseArrayDOK{Float64}(2, 2)
a = SparseArrayDOK{Float64}(undef, 2, 2)
````

AbstractArray interface:
Expand Down Expand Up @@ -122,32 +122,32 @@ b = a[1:2, 2]
@test b == [12, 0]
@test storedlength(b) == 1

a = SparseArrayDOK{Float64}(2, 2)
a = SparseArrayDOK{Float64}(undef, 2, 2)
a .= 2
for I in eachindex(a)
@test a[I] == 2
end
@test storedlength(a) == length(a)

a = SparseArrayDOK{Float64}(2, 2)
a = SparseArrayDOK{Float64}(undef, 2, 2)
fill!(a, 2)
for I in eachindex(a)
@test a[I] == 2
end
@test storedlength(a) == length(a)

a = SparseArrayDOK{Float64}(2, 2)
a = SparseArrayDOK{Float64}(undef, 2, 2)
fill!(a, 0)
@test iszero(a)
@test iszero(storedlength(a))

a = SparseArrayDOK{Float64}(2, 2)
a = SparseArrayDOK{Float64}(undef, 2, 2)
a[1, 2] = 12
zero!(a)
@test iszero(a)
@test iszero(storedlength(a))

a = SparseArrayDOK{Float64}(2, 2)
a = SparseArrayDOK{Float64}(undef, 2, 2)
a[1, 2] = 12
b = zero(a)
@test iszero(b)
Expand Down
2 changes: 1 addition & 1 deletion docs/make.jl
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ makedocs(;
edit_link="main",
assets=String[],
),
pages=["Home" => "index.md"],
pages=["Home" => "index.md", "Reference" => "reference.md"],
)

deploydocs(;
Expand Down
5 changes: 5 additions & 0 deletions docs/src/reference.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# Reference

```@autodocs
Modules = [SparseArraysBase]
```
12 changes: 6 additions & 6 deletions examples/README.jl
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ using SparseArraysBase:
zero!
using Test: @test, @test_throws

a = SparseArrayDOK{Float64}(2, 2)
a = SparseArrayDOK{Float64}(undef, 2, 2)

# AbstractArray interface:

Expand Down Expand Up @@ -118,32 +118,32 @@ b = a[1:2, 2]
@test b == [12, 0]
@test storedlength(b) == 1

a = SparseArrayDOK{Float64}(2, 2)
a = SparseArrayDOK{Float64}(undef, 2, 2)
a .= 2
for I in eachindex(a)
@test a[I] == 2
end
@test storedlength(a) == length(a)

a = SparseArrayDOK{Float64}(2, 2)
a = SparseArrayDOK{Float64}(undef, 2, 2)
fill!(a, 2)
for I in eachindex(a)
@test a[I] == 2
end
@test storedlength(a) == length(a)

a = SparseArrayDOK{Float64}(2, 2)
a = SparseArrayDOK{Float64}(undef, 2, 2)
fill!(a, 0)
@test iszero(a)
@test iszero(storedlength(a))

a = SparseArrayDOK{Float64}(2, 2)
a = SparseArrayDOK{Float64}(undef, 2, 2)
a[1, 2] = 12
zero!(a)
@test iszero(a)
@test iszero(storedlength(a))

a = SparseArrayDOK{Float64}(2, 2)
a = SparseArrayDOK{Float64}(undef, 2, 2)
a[1, 2] = 12
b = zero(a)
@test iszero(b)
Expand Down
9 changes: 8 additions & 1 deletion src/SparseArraysBase.jl
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,15 @@ export SparseArrayDOK,
storedpairs,
storedvalues

using DerivableInterfaces

# sparsearrayinterface
include("abstractsparsearrayinterface.jl")
include("sparsearrayinterface.jl")
include("indexing.jl")
include("map.jl")
include("broadcast.jl")

# types
include("wrappers.jl")
include("abstractsparsearray.jl")
include("sparsearraydok.jl")
Expand Down
118 changes: 87 additions & 31 deletions src/abstractsparsearray.jl
Original file line number Diff line number Diff line change
Expand Up @@ -5,51 +5,107 @@ using DerivableInterfaces: @array_aliases
@array_aliases AbstractSparseArray

using DerivableInterfaces: DerivableInterfaces
function DerivableInterfaces.interface(::Type{<:AbstractSparseArray})
function DerivableInterfaces.interface(::Type{A}) where {A<:AnyAbstractSparseArray}
return SparseArrayInterface()
end

using DerivableInterfaces: @derive

# TODO: These need to be loaded since `AbstractArrayOps`
# includes overloads of functions from these modules.
# Ideally that wouldn't be needed and can be circumvented
# with `GlobalRef`.
using ArrayLayouts: ArrayLayouts
using LinearAlgebra: LinearAlgebra

# DerivableInterfaces `Base.getindex`, `Base.setindex!`, etc.
# TODO: Define `AbstractMatrixOps` and overload for
# `AnyAbstractSparseMatrix` and `AnyAbstractSparseVector`,
# which is where matrix multiplication and factorizations
# should go.
@derive AnyAbstractSparseArray AbstractArrayOps

# This type alias is a temporary workaround since `@derive`
# doesn't parse the `@MIME_str` macro properly at the moment.
const MIMEtextplain = MIME"text/plain"

@derive (T=AnyAbstractSparseArray,) begin
Base.show(::IO, ::MIMEtextplain, ::T)
Base.getindex(::T, ::Int...)
Base.setindex!(::T, ::Any, ::Int...)
Base.similar(::T, ::Type, ::Tuple{Vararg{Int}})
Base.similar(::T, ::Type, ::Tuple{Base.OneTo,Vararg{Base.OneTo}})
# Base.copy(::T)
# Base.copy!(::AbstractArray, ::T)
# Base.copyto!(::AbstractArray, ::T)
Base.map(::Any, ::T...)
Base.map!(::Any, ::AbstractArray, ::T...)
# Base.mapreduce(::Any, ::Any, ::T...; kwargs...)
# Base.reduce(::Any, ::T...; kwargs...)
# Base.all(::Function, ::T)
# Base.all(::T)
Base.iszero(::T)
Base.real(::T)
Base.fill!(::T, ::Any)
ArrayLayouts.zero!(::T)
Base.zero(::T)
Base.permutedims!(::Any, ::T, ::Any)
Broadcast.BroadcastStyle(::Type{<:T})
Base.copyto!(::T, ::Broadcast.Broadcasted{Broadcast.DefaultArrayStyle{0}})
Base.cat(::T...; kwargs...)
ArrayLayouts.MemoryLayout(::Type{<:T})
LinearAlgebra.mul!(::AbstractMatrix, ::T, ::T, ::Number, ::Number)
# Base.show(::IO, ::MIMEtextplain, ::T)
end

# Wraps a sparse array but replaces the unstored values.
# This is used in printing in order to customize printing
# of zero/unstored values.
struct ReplacedUnstoredSparseArray{T,N,F,Parent<:AbstractArray{T,N}} <:
AbstractSparseArray{T,N}
parent::Parent
getunstoredindex::F
function Base.replace_in_print_matrix(
A::AnyAbstractSparseArray{<:Any,2}, i::Integer, j::Integer, s::AbstractString
)
return isstored(A, CartesianIndex(i, j)) ? s : Base.replace_with_centered_mark(s)
end
Base.parent(a::ReplacedUnstoredSparseArray) = a.parent
Base.size(a::ReplacedUnstoredSparseArray) = size(parent(a))
function isstored(a::ReplacedUnstoredSparseArray, I::Int...)
return isstored(parent(a), I...)

# Special-purpose constructors
# ----------------------------
using Random: Random, AbstractRNG, default_rng
@doc """
spzeros([T::Type], dims) -> A::SparseArrayDOK{T}

Create an empty size `dims` sparse array.
The optional `T` argument specifies the element type, which defaults to `Float64`.
""" spzeros

spzeros(dims::Dims) = spzeros(Float64, dims)
spzeros(::Type{T}, dims::Dims) where {T} = SparseArrayDOK{T}(undef, dims)

@doc """
sprand([rng], [T::Type], dims; density::Real=0.5, rfn::Function=rand) -> A::SparseArrayDOK{T}

Create a random size `dims` sparse array in which the probability of any element being stored is independently given by `density`.
The optional `rng` argument specifies a random number generator, see also `Random`.
The optional `T` argument specifies the element type, which defaults to `Float64`.
The optional `rfn` argument can be used to control the type of random elements.

See also [`sprand!`](@ref).
""" sprand

function sprand(::Type{T}, dims::Dims; kwargs...) where {T}
return sprand(default_rng(), T, dims; kwargs...)
end
function getstoredindex(a::ReplacedUnstoredSparseArray, I::Int...)
return getstoredindex(parent(a), I...)
sprand(dims::Dims; kwargs...) = sprand(default_rng(), Float64, dims; kwargs...)
function sprand(rng::AbstractRNG, dims::Dims; kwargs...)
return sprand(rng, Float64, dims; kwargs...)
end
function getunstoredindex(a::ReplacedUnstoredSparseArray, I::Int...)
return a.getunstoredindex(a, I...)
function sprand(rng::AbstractRNG, ::Type{T}, dims::Dims; kwargs...) where {T}
A = SparseArrayDOK{T}(undef, dims)
sprand!(rng, A; kwargs...)
return A
end

@doc """
sprand!([rng], A::AbstractArray; density::Real=0.5, rfn::Function=rand) -> A

Overwrite part of an array with random entries, where the probability of overwriting is independently given by `density`.
The optional `rng` argument specifies a random number generator, see also `Random`.
The optional `rfn` argument can be used to control the type of random elements.

See also [`sprand`](@ref).
""" sprand!

sprand!(A::AbstractArray; kwargs...) = sprand!(default_rng(), A; kwargs...)
function sprand!(
rng::AbstractRNG, A::AbstractArray; density::Real=0.5, rfn::Function=Random.rand
)
ArrayLayouts.zero!(A)
rand_inds = Random.randsubseq(rng, eachindex(A), density)
rand_entries = rfn(rng, eltype(A), length(rand_inds))
for (I, v) in zip(rand_inds, rand_entries)
A[I] = v
end
end
eachstoredindex(a::ReplacedUnstoredSparseArray) = eachstoredindex(parent(a))
@derive ReplacedUnstoredSparseArray AbstractArrayOps
Loading