Skip to content

Commit

Permalink
Initial package draft (#1)
Browse files Browse the repository at this point in the history
  • Loading branch information
mtfishman authored Dec 6, 2024
1 parent 10e8b9b commit f97d55a
Show file tree
Hide file tree
Showing 17 changed files with 663 additions and 33 deletions.
11 changes: 10 additions & 1 deletion Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,27 @@ uuid = "a07dfc7f-7d04-4eb5-84cc-a97f051f655a"
authors = ["ITensor developers <[email protected]> and contributors"]
version = "0.1.0"

[deps]
Adapt = "79e6a3ab-5dfb-504d-930d-738a2a938a0e"
ExproniconLite = "55351af7-c7e9-48d6-89ff-24e801d99491"
MLStyle = "d8e11817-5142-5d16-987a-aa16d5891078"
TypeParameterAccessors = "7e5a90cf-f82e-492e-a09b-e3e26432c138"

[compat]
Adapt = "4.1.1"
Aqua = "0.8.9"
ExproniconLite = "0.10.13"
MLStyle = "0.4.17"
SafeTestsets = "0.1"
Suppressor = "0.2"
Test = "1.10"
julia = "1.10"

[extras]
Aqua = "4c88cf16-eb10-579e-8560-4a9242c79595"
Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"
SafeTestsets = "1bc83da4-3b8d-516f-aca4-4fe02f6d838f"
Suppressor = "fd094767-a336-5f1f-9728-57cf17d0bbfb"
Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"

[targets]
test = ["Aqua", "Test", "Suppressor", "SafeTestsets"]
98 changes: 96 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,104 @@ julia> Pkg.add("Derive")
## Examples

````julia
using Derive: Derive
using Derive: Derive, @derive, @interface, interface
using Test: @test
````

Examples go here.
Define an interface.

````julia
struct SparseArrayInterface end
````

Define interface functions.

````julia
@interface SparseArrayInterface() function Base.getindex(a, I::Int...)
checkbounds(a, I...)
!isstored(a, I...) && return getunstoredindex(a, I...)
return getstoredindex(a, I...)
end
@interface SparseArrayInterface() function Base.setindex!(a, value, I::Int...)
checkbounds(a, I...)
iszero(value) && return a
if !isstored(a, I...)
setunstoredindex!(a, value, I...)
return a
end
setstoredindex!(a, value, I...)
return a
end
````

Define a type that will derive the interface.

````julia
struct SparseArrayDOK{T,N} <: AbstractArray{T,N}
storage::Dict{CartesianIndex{N},T}
size::NTuple{N,Int}
end
storage(a::SparseArrayDOK) = a.storage
Base.size(a::SparseArrayDOK) = a.size
function SparseArrayDOK{T}(size::Int...) where {T}
N = length(size)
return SparseArrayDOK{T,N}(Dict{CartesianIndex{N},T}(), size)
end
function isstored(a::SparseArrayDOK, I::Int...)
return CartesianIndex(I) in keys(storage(a))
end
function getstoredindex(a::SparseArrayDOK, I::Int...)
return storage(a)[CartesianIndex(I)]
end
function getunstoredindex(a::SparseArrayDOK, I::Int...)
return zero(eltype(a))
end
function setstoredindex!(a::SparseArrayDOK, value, I::Int...)
storage(a)[CartesianIndex(I)] = value
return a
end
function setunstoredindex!(a::SparseArrayDOK, value, I::Int...)
storage(a)[CartesianIndex(I)] = value
return a
end
````

Speficy the interface the type adheres to.

````julia
Derive.interface(::Type{<:SparseArrayDOK}) = SparseArrayInterface()
````

Derive the interface for the type.

````julia
@derive (T=SparseArrayDOK,) begin
Base.getindex(::T, ::Int...)
Base.setindex!(::T, ::Any, ::Int...)
end

a = SparseArrayDOK{Float64}(2, 2)
a[1, 1] = 2
@test a[1, 1] == 2
@test a[2, 1] == 0
@test a[1, 2] == 0
@test a[2, 2] == 0
````

Call the sparse array interface on a dense array.

````julia
isstored(a::AbstractArray, I::Int...) = true
getstoredindex(a::AbstractArray, I::Int...) = getindex(a, I...)
setstoredindex!(a::AbstractArray, value, I::Int...) = setindex!(a, value, I...)

a = zeros(2, 2)
@interface SparseArrayInterface() a[1, 1] = 2
@test @interface(SparseArrayInterface(), a[1, 1]) == 2
@test @interface(SparseArrayInterface(), a[2, 1]) == 0
@test @interface(SparseArrayInterface(), a[1, 2]) == 0
@test @interface(SparseArrayInterface(), a[2, 2]) == 0
````

---

Expand Down
9 changes: 9 additions & 0 deletions TODO.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# Fix this, there is a namespace issue:
# Use `GlobalRef`, use a generalization of `globalref_derive`.
function derive(::Val{:AbstractArrayOps}, type)
return quote
ArrayLayouts.MemoryLayout(::Type{<:$type})
LinearAlgebra.mul!(::Any, ::$type, ::$type, ::Number, ::Number)
end
end

12 changes: 3 additions & 9 deletions docs/make.jl
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
using Derive: Derive
using Documenter: Documenter, DocMeta, deploydocs, makedocs

DocMeta.setdocmeta!(
Derive, :DocTestSetup, :(using Derive); recursive=true
)
DocMeta.setdocmeta!(Derive, :DocTestSetup, :(using Derive); recursive=true)

include("make_index.jl")

Expand All @@ -12,13 +10,9 @@ makedocs(;
authors="ITensor developers <[email protected]> and contributors",
sitename="Derive.jl",
format=Documenter.HTML(;
canonical="https://ITensor.github.io/Derive.jl",
edit_link="main",
assets=String[],
canonical="https://ITensor.github.io/Derive.jl", edit_link="main", assets=String[]
),
pages=["Home" => "index.md"],
)

deploydocs(;
repo="github.com/ITensor/Derive.jl", devbranch="main", push_preview=true
)
deploydocs(; repo="github.com/ITensor/Derive.jl", devbranch="main", push_preview=true)
81 changes: 79 additions & 2 deletions examples/README.jl
Original file line number Diff line number Diff line change
Expand Up @@ -37,5 +37,82 @@ julia> Pkg.add("Derive")

# ## Examples

using Derive: Derive
# Examples go here.
using Derive: Derive, @derive, @interface, interface
using Test: @test

# Define an interface.
struct SparseArrayInterface end

# Define interface functions.
@interface SparseArrayInterface() function Base.getindex(a, I::Int...)
checkbounds(a, I...)
!isstored(a, I...) && return getunstoredindex(a, I...)
return getstoredindex(a, I...)
end
@interface SparseArrayInterface() function Base.setindex!(a, value, I::Int...)
checkbounds(a, I...)
iszero(value) && return a
if !isstored(a, I...)
setunstoredindex!(a, value, I...)
return a
end
setstoredindex!(a, value, I...)
return a
end

# Define a type that will derive the interface.
struct SparseArrayDOK{T,N} <: AbstractArray{T,N}
storage::Dict{CartesianIndex{N},T}
size::NTuple{N,Int}
end
storage(a::SparseArrayDOK) = a.storage
Base.size(a::SparseArrayDOK) = a.size
function SparseArrayDOK{T}(size::Int...) where {T}
N = length(size)
return SparseArrayDOK{T,N}(Dict{CartesianIndex{N},T}(), size)
end
function isstored(a::SparseArrayDOK, I::Int...)
return CartesianIndex(I) in keys(storage(a))
end
function getstoredindex(a::SparseArrayDOK, I::Int...)
return storage(a)[CartesianIndex(I)]
end
function getunstoredindex(a::SparseArrayDOK, I::Int...)
return zero(eltype(a))
end
function setstoredindex!(a::SparseArrayDOK, value, I::Int...)
storage(a)[CartesianIndex(I)] = value
return a
end
function setunstoredindex!(a::SparseArrayDOK, value, I::Int...)
storage(a)[CartesianIndex(I)] = value
return a
end

# Speficy the interface the type adheres to.
Derive.interface(::Type{<:SparseArrayDOK}) = SparseArrayInterface()

# Derive the interface for the type.
@derive (T=SparseArrayDOK,) begin
Base.getindex(::T, ::Int...)
Base.setindex!(::T, ::Any, ::Int...)
end

a = SparseArrayDOK{Float64}(2, 2)
a[1, 1] = 2
@test a[1, 1] == 2
@test a[2, 1] == 0
@test a[1, 2] == 0
@test a[2, 2] == 0

# Call the sparse array interface on a dense array.
isstored(a::AbstractArray, I::Int...) = true
getstoredindex(a::AbstractArray, I::Int...) = getindex(a, I...)
setstoredindex!(a::AbstractArray, value, I::Int...) = setindex!(a, value, I...)

a = zeros(2, 2)
@interface SparseArrayInterface() a[1, 1] = 2
@test @interface(SparseArrayInterface(), a[1, 1]) == 2
@test @interface(SparseArrayInterface(), a[2, 1]) == 0
@test @interface(SparseArrayInterface(), a[1, 2]) == 0
@test @interface(SparseArrayInterface(), a[2, 2]) == 0
9 changes: 8 additions & 1 deletion src/Derive.jl
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
module Derive

# Write your package code here.
include("interface_function.jl")
include("abstractinterface.jl")
include("derive_macro.jl")
include("interface_macro.jl")
include("wrappedarrays.jl")
include("abstractarrayinterface.jl")
include("defaultarrayinterface.jl")
include("traits.jl")

end
2 changes: 2 additions & 0 deletions src/abstractarrayinterface.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# TODO: Add `ndims` type parameter.
abstract type AbstractArrayInterface <: AbstractInterface end
25 changes: 25 additions & 0 deletions src/abstractinterface.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# Get the interface of an object.
interface(x) = interface(typeof(x))
# TODO: Define as `DefaultInterface()`.
interface(::Type) = error("Interface unknown.")

# Adapted from `Base.Broadcast.combine_styles`.
# Get the combined interfaces of the input objects.
function combine_interfaces(x1, x2, x_rest...)
return combine_interfaces(combine_interfaces(x1, x2), x_rest...)
end
combine_interfaces(x1, x2) = comine_interface_rule(interface(x1), interface(x2))
combine_interfaces(x) = interface(x)

# Rules for combining interfaces.
function combine_interface_rule(
interface1::Interface, interface2::Interface
) where {Interface}
return interface1
end
# TODO: Define as `UnknownInterface()`.
combine_interface_rule(interface1, interface2) = error("No rule for combining interfaces.")

abstract type AbstractInterface end

(interface::AbstractInterface)(f) = InterfaceFunction(interface, f)
8 changes: 8 additions & 0 deletions src/defaultarrayinterface.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# TODO: Add `ndims` type parameter.
struct DefaultArrayInterface <: AbstractArrayInterface end

using TypeParameterAccessors: parenttype
function interface(a::Type{<:AbstractArray})
parenttype(a) === a && return DefaultArrayInterface()
return interface(parenttype(a))
end
Loading

0 comments on commit f97d55a

Please sign in to comment.