diff --git a/benchmark/benchmark.jl b/benchmark/benchmark.jl index 3eb14cf8..b7bee69e 100644 --- a/benchmark/benchmark.jl +++ b/benchmark/benchmark.jl @@ -1,8 +1,7 @@ -using ADTypes -using ADTypes: AbstractSparsityDetector +using ADTypes: AbstractSparsityDetector, jacobian_sparsity using BenchmarkTools using SparseConnectivityTracer -using SparseConnectivityTracer: SortedVector +using SparseConnectivityTracer: DuplicateVector, RecursiveSet, SortedVector using NNlib: conv include("../test/brusselator_definition.jl") @@ -10,23 +9,17 @@ include("../test/brusselator_definition.jl") const METHODS = ( TracerSparsityDetector(BitSet), TracerSparsityDetector(Set{UInt64}), + TracerSparsityDetector(DuplicateVector{UInt64}), + TracerSparsityDetector(RecursiveSet{UInt64}), TracerSparsityDetector(SortedVector{UInt64}), ) function benchmark_brusselator(N::Integer, method::AbstractSparsityDetector) - dims = (N, N, 2) - A = 1.0 - B = 1.0 - alpha = 1.0 - xyd = fill(1.0, N) - dx = 1.0 - p = (A, B, alpha, xyd, dx, N) - - u = rand(dims...) - du = similar(u) - f!(du, u) = brusselator_2d_loop(du, u, p, nothing) - - return @benchmark ADTypes.jacobian_sparsity($f!, $du, $u, $method) + f! = Brusselator!(N) + x = rand(N, N, 2) + y = similar(x) + + return @benchmark jacobian_sparsity($f!, $y, $x, $method) end function benchmark_conv(N, method::AbstractSparsityDetector) @@ -34,7 +27,7 @@ function benchmark_conv(N, method::AbstractSparsityDetector) w = rand(5, 5, 3, 2) # corresponds to Conv((5, 5), 3 => 2) f(x) = conv(x, w) - return @benchmark ADTypes.jacobian_sparsity($f, $x, $method) + return @benchmark jacobian_sparsity($f, $x, $method) end ## Run Brusselator benchmarks diff --git a/docs/src/api.md b/docs/src/api.md index aa87a1b5..7fb70955 100644 --- a/docs/src/api.md +++ b/docs/src/api.md @@ -28,8 +28,10 @@ JacobianTracer HessianTracer ``` -We also define a custom alternative to sets that can deliver faster `union`: +We also define alternative pseudo-set types that can deliver faster `union`: ```@docs +SparseConnectivityTracer.DuplicateVector +SparseConnectivityTracer.RecursiveSet SparseConnectivityTracer.SortedVector ``` diff --git a/references/show/HessianTracer_BitSet.txt b/references/show/HessianTracer_BitSet.txt new file mode 100644 index 00000000..0aeee5ed --- /dev/null +++ b/references/show/HessianTracer_BitSet.txt @@ -0,0 +1,3 @@ +HessianTracer{BitSet}( + 2 => (), +) \ No newline at end of file diff --git a/references/show/HessianTracer_DuplicateVector{UInt64}.txt b/references/show/HessianTracer_DuplicateVector{UInt64}.txt new file mode 100644 index 00000000..baf1bcea --- /dev/null +++ b/references/show/HessianTracer_DuplicateVector{UInt64}.txt @@ -0,0 +1,3 @@ +HessianTracer{DuplicateVector{UInt64}}( + 2 => (), +) \ No newline at end of file diff --git a/references/show/HessianTracer_RecursiveSet{UInt64}.txt b/references/show/HessianTracer_RecursiveSet{UInt64}.txt new file mode 100644 index 00000000..fa015a48 --- /dev/null +++ b/references/show/HessianTracer_RecursiveSet{UInt64}.txt @@ -0,0 +1,3 @@ +HessianTracer{RecursiveSet{UInt64}}( + 2 => (), +) \ No newline at end of file diff --git a/references/show/HessianTracer_Set{UInt64}.txt b/references/show/HessianTracer_Set{UInt64}.txt new file mode 100644 index 00000000..54572703 --- /dev/null +++ b/references/show/HessianTracer_Set{UInt64}.txt @@ -0,0 +1,3 @@ +HessianTracer{Set{UInt64}}( + 2 => (), +) \ No newline at end of file diff --git a/references/show/HessianTracer_SortedVector{UInt64}.txt b/references/show/HessianTracer_SortedVector{UInt64}.txt new file mode 100644 index 00000000..fb4fbb7a --- /dev/null +++ b/references/show/HessianTracer_SortedVector{UInt64}.txt @@ -0,0 +1,3 @@ +HessianTracer{SortedVector{UInt64}}( + 2 => (), +) \ No newline at end of file diff --git a/src/SparseConnectivityTracer.jl b/src/SparseConnectivityTracer.jl index 98be5bde..9673c0c0 100644 --- a/src/SparseConnectivityTracer.jl +++ b/src/SparseConnectivityTracer.jl @@ -4,7 +4,6 @@ using ADTypes: ADTypes import SparseArrays: sparse import Random: rand, AbstractRNG, SamplerType -include("sortedvector.jl") include("tracers.jl") include("conversion.jl") include("operators.jl") @@ -14,6 +13,10 @@ include("overload_hessian.jl") include("pattern.jl") include("adtypes.jl") +include("settypes/duplicatevector.jl") +include("settypes/recursiveset.jl") +include("settypes/sortedvector.jl") + export ConnectivityTracer, connectivity_pattern export JacobianTracer, jacobian_pattern export HessianTracer, hessian_pattern diff --git a/src/pattern.jl b/src/pattern.jl index 6c19a740..863e401d 100644 --- a/src/pattern.jl +++ b/src/pattern.jl @@ -203,7 +203,7 @@ function hessian_pattern_to_mat( V = Bool[] # values for i in keys(yt.inputs) - for j in yt.inputs[i] + for j in inputs(yt, i) push!(I, i) push!(J, j) push!(V, true) diff --git a/src/settypes/duplicatevector.jl b/src/settypes/duplicatevector.jl new file mode 100644 index 00000000..7203d318 --- /dev/null +++ b/src/settypes/duplicatevector.jl @@ -0,0 +1,56 @@ +""" + DuplicateVector + +Vector that can have duplicate values, for which union is just concatenation. +""" +struct DuplicateVector{T<:Number} + data::Vector{T} + + DuplicateVector{T}(data::AbstractVector{T}) where {T} = new{T}(convert(Vector{T}, data)) + DuplicateVector{T}(x::Number) where {T} = new{T}([convert(T, x)]) + DuplicateVector{T}() where {T} = new{T}(T[]) +end + +Base.eltype(::Type{DuplicateVector{T}}) where {T} = T + +function Base.union(dv1::DuplicateVector{T}, dv2::DuplicateVector{T}) where {T} + return DuplicateVector{T}(vcat(dv1.data, dv2.data)) +end + +Base.collect(dv::DuplicateVector) = collect(Set(dv.data)) + +## SCT tricks + +function keys2set(::Type{S}, d::Dict{I}) where {I<:Integer,S<:DuplicateVector{I}} + return S(collect(keys(d))) +end + +const EMPTY_CONNECTIVITY_TRACER_DV_U16 = ConnectivityTracer(DuplicateVector{UInt16}()) +const EMPTY_CONNECTIVITY_TRACER_DV_U32 = ConnectivityTracer(DuplicateVector{UInt32}()) +const EMPTY_CONNECTIVITY_TRACER_DV_U64 = ConnectivityTracer(DuplicateVector{UInt64}()) + +const EMPTY_JACOBIAN_TRACER_DV_U16 = JacobianTracer(DuplicateVector{UInt16}()) +const EMPTY_JACOBIAN_TRACER_DV_U32 = JacobianTracer(DuplicateVector{UInt32}()) +const EMPTY_JACOBIAN_TRACER_DV_U64 = JacobianTracer(DuplicateVector{UInt64}()) + +const EMPTY_HESSIAN_TRACER_DV_U16 = HessianTracer(Dict{UInt16,DuplicateVector{UInt16}}()) +const EMPTY_HESSIAN_TRACER_DV_U32 = HessianTracer(Dict{UInt32,DuplicateVector{UInt32}}()) +const EMPTY_HESSIAN_TRACER_DV_U64 = HessianTracer(Dict{UInt64,DuplicateVector{UInt64}}()) + +function empty(::Type{ConnectivityTracer{DuplicateVector{UInt16}}}) + return EMPTY_CONNECTIVITY_TRACER_DV_U16 +end +function empty(::Type{ConnectivityTracer{DuplicateVector{UInt32}}}) + return EMPTY_CONNECTIVITY_TRACER_DV_U32 +end +function empty(::Type{ConnectivityTracer{DuplicateVector{UInt64}}}) + return EMPTY_CONNECTIVITY_TRACER_DV_U64 +end + +empty(::Type{JacobianTracer{DuplicateVector{UInt16}}}) = EMPTY_JACOBIAN_TRACER_DV_U16 +empty(::Type{JacobianTracer{DuplicateVector{UInt32}}}) = EMPTY_JACOBIAN_TRACER_DV_U32 +empty(::Type{JacobianTracer{DuplicateVector{UInt64}}}) = EMPTY_JACOBIAN_TRACER_DV_U64 + +empty(::Type{HessianTracer{DuplicateVector{UInt16},UInt16}}) = EMPTY_HESSIAN_TRACER_DV_U16 +empty(::Type{HessianTracer{DuplicateVector{UInt32},UInt32}}) = EMPTY_HESSIAN_TRACER_DV_U32 +empty(::Type{HessianTracer{DuplicateVector{UInt64},UInt64}}) = EMPTY_HESSIAN_TRACER_DV_U64 diff --git a/src/settypes/recursiveset.jl b/src/settypes/recursiveset.jl new file mode 100644 index 00000000..4e7a0bd6 --- /dev/null +++ b/src/settypes/recursiveset.jl @@ -0,0 +1,94 @@ +""" + RecursiveSet + +Lazy union of sets. +""" +struct RecursiveSet{T<:Number} + s::Union{Nothing,Set{T}} + child1::Union{Nothing,RecursiveSet{T}} + child2::Union{Nothing,RecursiveSet{T}} + + function RecursiveSet{T}(s) where {T} + return new{T}(Set{T}(s), nothing, nothing) + end + + function RecursiveSet{T}(x::Number) where {T} + return new{T}(Set{T}(convert(T, x)), nothing, nothing) + end + + function RecursiveSet{T}() where {T} + return new{T}(Set{T}(), nothing, nothing) + end + + function RecursiveSet{T}(rs1::RecursiveSet{T}, rs2::RecursiveSet{T}) where {T} + return new{T}(nothing, rs1, rs2) + end +end + +function print_recursiveset(io::IO, rs::RecursiveSet{T}; offset) where {T} + if !isnothing(rs.s) + print(io, "RecursiveSet{$T} containing $(rs.s)") + else + print(io, "RecursiveSet{$T} with two children:") + print(io, "\n ", " "^offset, "1: ") + print_recursiveset(io, rs.child1; offset=offset + 2) + print(io, "\n ", " "^offset, "2: ") + print_recursiveset(io, rs.child2; offset=offset + 2) + end +end + +function Base.show(io::IO, rs::RecursiveSet{T}) where {T} + return print_recursiveset(io, rs; offset=0) +end + +Base.eltype(::Type{RecursiveSet{T}}) where {T} = T + +function Base.union(rs1::RecursiveSet{T}, rs2::RecursiveSet{T}) where {T} + return RecursiveSet{T}(rs1, rs2) +end + +function Base.collect(rs::RecursiveSet{T}) where {T} + accumulator = Set{T}() + collect_aux!(accumulator, rs) + return collect(accumulator) +end + +function collect_aux!(accumulator::Set{T}, rs::RecursiveSet{T})::Nothing where {T} + if !isnothing(rs.s) + union!(accumulator, rs.s::Set{T}) + else + collect_aux!(accumulator, rs.child1::RecursiveSet{T}) + collect_aux!(accumulator, rs.child2::RecursiveSet{T}) + end + return nothing +end + +## SCT tricks + +function keys2set(::Type{S}, d::Dict{I}) where {I<:Integer,S<:RecursiveSet{I}} + return S(keys(d)) +end + +const EMPTY_CONNECTIVITY_TRACER_RS_U16 = ConnectivityTracer(RecursiveSet{UInt16}()) +const EMPTY_CONNECTIVITY_TRACER_RS_U32 = ConnectivityTracer(RecursiveSet{UInt32}()) +const EMPTY_CONNECTIVITY_TRACER_RS_U64 = ConnectivityTracer(RecursiveSet{UInt64}()) + +const EMPTY_JACOBIAN_TRACER_RS_U16 = JacobianTracer(RecursiveSet{UInt16}()) +const EMPTY_JACOBIAN_TRACER_RS_U32 = JacobianTracer(RecursiveSet{UInt32}()) +const EMPTY_JACOBIAN_TRACER_RS_U64 = JacobianTracer(RecursiveSet{UInt64}()) + +const EMPTY_HESSIAN_TRACER_RS_U16 = HessianTracer(Dict{UInt16,RecursiveSet{UInt16}}()) +const EMPTY_HESSIAN_TRACER_RS_U32 = HessianTracer(Dict{UInt32,RecursiveSet{UInt32}}()) +const EMPTY_HESSIAN_TRACER_RS_U64 = HessianTracer(Dict{UInt64,RecursiveSet{UInt64}}()) + +empty(::Type{ConnectivityTracer{RecursiveSet{UInt16}}}) = EMPTY_CONNECTIVITY_TRACER_RS_U16 +empty(::Type{ConnectivityTracer{RecursiveSet{UInt32}}}) = EMPTY_CONNECTIVITY_TRACER_RS_U32 +empty(::Type{ConnectivityTracer{RecursiveSet{UInt64}}}) = EMPTY_CONNECTIVITY_TRACER_RS_U64 + +empty(::Type{JacobianTracer{RecursiveSet{UInt16}}}) = EMPTY_JACOBIAN_TRACER_RS_U16 +empty(::Type{JacobianTracer{RecursiveSet{UInt32}}}) = EMPTY_JACOBIAN_TRACER_RS_U32 +empty(::Type{JacobianTracer{RecursiveSet{UInt64}}}) = EMPTY_JACOBIAN_TRACER_RS_U64 + +empty(::Type{HessianTracer{RecursiveSet{UInt16},UInt16}}) = EMPTY_HESSIAN_TRACER_RS_U16 +empty(::Type{HessianTracer{RecursiveSet{UInt32},UInt32}}) = EMPTY_HESSIAN_TRACER_RS_U32 +empty(::Type{HessianTracer{RecursiveSet{UInt64},UInt64}}) = EMPTY_HESSIAN_TRACER_RS_U64 diff --git a/src/sortedvector.jl b/src/settypes/sortedvector.jl similarity index 56% rename from src/sortedvector.jl rename to src/settypes/sortedvector.jl index a60ca3c2..364928ec 100644 --- a/src/sortedvector.jl +++ b/src/settypes/sortedvector.jl @@ -1,23 +1,7 @@ """ SortedVector -A wrapper for sorted vectors, designed for fast unions. - -# Constructor - - SortedVector(data::AbstractVector; sorted=false) - -# Example - -```jldoctest -x = SortedVector([3, 4, 2]) -x = SortedVector([1, 3, 5]; sorted=true) -z = union(x, y) - -# output - -SortedVector([1, 2, 3, 4, 5]) -```` +Sorted vector without duplicates, designed for fast set unions with merging. """ struct SortedVector{T<:Number} <: AbstractVector{T} data::Vector{T} @@ -40,7 +24,6 @@ function Base.convert(::Type{SortedVector{T}}, v::Vector{T}) where {T} return SortedVector{T}(v; sorted=false) end -Base.eltype(::SortedVector{T}) where {T} = T Base.size(v::SortedVector) = size(v.data) Base.getindex(v::SortedVector, i) = v.data[i] Base.IndexStyle(::Type{SortedVector{T}}) where {T} = IndexStyle(Vector{T}) @@ -80,3 +63,33 @@ function Base.union(v1::SortedVector{T}, v2::SortedVector{T}) where {T} resize!(result, result_index - 1) return SortedVector{T}(result; sorted=true) end + +## SCT tricks + +function keys2set(::Type{S}, d::Dict{I}) where {I<:Integer,S<:SortedVector{I}} + return S(collect(keys(d)); sorted=false) +end + +const EMPTY_CONNECTIVITY_TRACER_SV_U16 = ConnectivityTracer(SortedVector{UInt16}()) +const EMPTY_CONNECTIVITY_TRACER_SV_U32 = ConnectivityTracer(SortedVector{UInt32}()) +const EMPTY_CONNECTIVITY_TRACER_SV_U64 = ConnectivityTracer(SortedVector{UInt64}()) + +const EMPTY_JACOBIAN_TRACER_SV_U16 = JacobianTracer(SortedVector{UInt16}()) +const EMPTY_JACOBIAN_TRACER_SV_U32 = JacobianTracer(SortedVector{UInt32}()) +const EMPTY_JACOBIAN_TRACER_SV_U64 = JacobianTracer(SortedVector{UInt64}()) + +const EMPTY_HESSIAN_TRACER_SV_U16 = HessianTracer(Dict{UInt16,SortedVector{UInt16}}()) +const EMPTY_HESSIAN_TRACER_SV_U32 = HessianTracer(Dict{UInt32,SortedVector{UInt32}}()) +const EMPTY_HESSIAN_TRACER_SV_U64 = HessianTracer(Dict{UInt64,SortedVector{UInt64}}()) + +empty(::Type{ConnectivityTracer{SortedVector{UInt16}}}) = EMPTY_CONNECTIVITY_TRACER_SV_U16 +empty(::Type{ConnectivityTracer{SortedVector{UInt32}}}) = EMPTY_CONNECTIVITY_TRACER_SV_U32 +empty(::Type{ConnectivityTracer{SortedVector{UInt64}}}) = EMPTY_CONNECTIVITY_TRACER_SV_U64 + +empty(::Type{JacobianTracer{SortedVector{UInt16}}}) = EMPTY_JACOBIAN_TRACER_SV_U16 +empty(::Type{JacobianTracer{SortedVector{UInt32}}}) = EMPTY_JACOBIAN_TRACER_SV_U32 +empty(::Type{JacobianTracer{SortedVector{UInt64}}}) = EMPTY_JACOBIAN_TRACER_SV_U64 + +empty(::Type{HessianTracer{SortedVector{UInt16},UInt16}}) = EMPTY_HESSIAN_TRACER_SV_U16 +empty(::Type{HessianTracer{SortedVector{UInt32},UInt32}}) = EMPTY_HESSIAN_TRACER_SV_U32 +empty(::Type{HessianTracer{SortedVector{UInt64},UInt64}}) = EMPTY_HESSIAN_TRACER_SV_U64 diff --git a/src/tracers.jl b/src/tracers.jl index 9d19c159..a0fcb364 100644 --- a/src/tracers.jl +++ b/src/tracers.jl @@ -43,18 +43,12 @@ const EMPTY_CONNECTIVITY_TRACER_SET_U8 = ConnectivityTracer(Set{UInt8}()) const EMPTY_CONNECTIVITY_TRACER_SET_U16 = ConnectivityTracer(Set{UInt16}()) const EMPTY_CONNECTIVITY_TRACER_SET_U32 = ConnectivityTracer(Set{UInt32}()) const EMPTY_CONNECTIVITY_TRACER_SET_U64 = ConnectivityTracer(Set{UInt64}()) -const EMPTY_CONNECTIVITY_TRACER_SV_U16 = ConnectivityTracer(SortedVector{UInt16}()) -const EMPTY_CONNECTIVITY_TRACER_SV_U32 = ConnectivityTracer(SortedVector{UInt32}()) -const EMPTY_CONNECTIVITY_TRACER_SV_U64 = ConnectivityTracer(SortedVector{UInt64}()) - -empty(::Type{ConnectivityTracer{BitSet}}) = EMPTY_CONNECTIVITY_TRACER_BITSET -empty(::Type{ConnectivityTracer{Set{UInt8}}}) = EMPTY_CONNECTIVITY_TRACER_SET_U8 -empty(::Type{ConnectivityTracer{Set{UInt16}}}) = EMPTY_CONNECTIVITY_TRACER_SET_U16 -empty(::Type{ConnectivityTracer{Set{UInt32}}}) = EMPTY_CONNECTIVITY_TRACER_SET_U32 -empty(::Type{ConnectivityTracer{Set{UInt64}}}) = EMPTY_CONNECTIVITY_TRACER_SET_U64 -empty(::Type{ConnectivityTracer{SortedVector{UInt16}}}) = EMPTY_CONNECTIVITY_TRACER_SV_U16 -empty(::Type{ConnectivityTracer{SortedVector{UInt32}}}) = EMPTY_CONNECTIVITY_TRACER_SV_U32 -empty(::Type{ConnectivityTracer{SortedVector{UInt64}}}) = EMPTY_CONNECTIVITY_TRACER_SV_U64 + +empty(::Type{ConnectivityTracer{BitSet}}) = EMPTY_CONNECTIVITY_TRACER_BITSET +empty(::Type{ConnectivityTracer{Set{UInt8}}}) = EMPTY_CONNECTIVITY_TRACER_SET_U8 +empty(::Type{ConnectivityTracer{Set{UInt16}}}) = EMPTY_CONNECTIVITY_TRACER_SET_U16 +empty(::Type{ConnectivityTracer{Set{UInt32}}}) = EMPTY_CONNECTIVITY_TRACER_SET_U32 +empty(::Type{ConnectivityTracer{Set{UInt64}}}) = EMPTY_CONNECTIVITY_TRACER_SET_U64 # We have to be careful when defining constructors: # Generic code expecting "regular" numbers `x` will sometimes convert them @@ -99,18 +93,12 @@ const EMPTY_JACOBIAN_TRACER_SET_U8 = JacobianTracer(Set{UInt8}()) const EMPTY_JACOBIAN_TRACER_SET_U16 = JacobianTracer(Set{UInt16}()) const EMPTY_JACOBIAN_TRACER_SET_U32 = JacobianTracer(Set{UInt32}()) const EMPTY_JACOBIAN_TRACER_SET_U64 = JacobianTracer(Set{UInt64}()) -const EMPTY_JACOBIAN_TRACER_SV_U16 = JacobianTracer(SortedVector{UInt16}()) -const EMPTY_JACOBIAN_TRACER_SV_U32 = JacobianTracer(SortedVector{UInt32}()) -const EMPTY_JACOBIAN_TRACER_SV_U64 = JacobianTracer(SortedVector{UInt64}()) - -empty(::Type{JacobianTracer{BitSet}}) = EMPTY_JACOBIAN_TRACER_BITSET -empty(::Type{JacobianTracer{Set{UInt8}}}) = EMPTY_JACOBIAN_TRACER_SET_U8 -empty(::Type{JacobianTracer{Set{UInt16}}}) = EMPTY_JACOBIAN_TRACER_SET_U16 -empty(::Type{JacobianTracer{Set{UInt32}}}) = EMPTY_JACOBIAN_TRACER_SET_U32 -empty(::Type{JacobianTracer{Set{UInt64}}}) = EMPTY_JACOBIAN_TRACER_SET_U64 -empty(::Type{JacobianTracer{SortedVector{UInt16}}}) = EMPTY_JACOBIAN_TRACER_SV_U16 -empty(::Type{JacobianTracer{SortedVector{UInt32}}}) = EMPTY_JACOBIAN_TRACER_SV_U32 -empty(::Type{JacobianTracer{SortedVector{UInt64}}}) = EMPTY_JACOBIAN_TRACER_SV_U64 + +empty(::Type{JacobianTracer{BitSet}}) = EMPTY_JACOBIAN_TRACER_BITSET +empty(::Type{JacobianTracer{Set{UInt8}}}) = EMPTY_JACOBIAN_TRACER_SET_U8 +empty(::Type{JacobianTracer{Set{UInt16}}}) = EMPTY_JACOBIAN_TRACER_SET_U16 +empty(::Type{JacobianTracer{Set{UInt32}}}) = EMPTY_JACOBIAN_TRACER_SET_U32 +empty(::Type{JacobianTracer{Set{UInt64}}}) = EMPTY_JACOBIAN_TRACER_SET_U64 JacobianTracer{S}(::Number) where {S} = empty(JacobianTracer{S}) JacobianTracer(t::JacobianTracer) = t @@ -155,18 +143,12 @@ const EMPTY_HESSIAN_TRACER_SET_U8 = HessianTracer(Dict{UInt8,Set{UInt8}}()) const EMPTY_HESSIAN_TRACER_SET_U16 = HessianTracer(Dict{UInt16,Set{UInt16}}()) const EMPTY_HESSIAN_TRACER_SET_U32 = HessianTracer(Dict{UInt32,Set{UInt32}}()) const EMPTY_HESSIAN_TRACER_SET_U64 = HessianTracer(Dict{UInt64,Set{UInt64}}()) -const EMPTY_HESSIAN_TRACER_SV_U16 = HessianTracer(Dict{UInt16,SortedVector{UInt16}}()) -const EMPTY_HESSIAN_TRACER_SV_U32 = HessianTracer(Dict{UInt32,SortedVector{UInt32}}()) -const EMPTY_HESSIAN_TRACER_SV_U64 = HessianTracer(Dict{UInt64,SortedVector{UInt64}}()) - -empty(::Type{HessianTracer{BitSet,Int}}) = EMPTY_HESSIAN_TRACER_BITSET -empty(::Type{HessianTracer{Set{UInt8},UInt8}}) = EMPTY_HESSIAN_TRACER_SET_U8 -empty(::Type{HessianTracer{Set{UInt16},UInt16}}) = EMPTY_HESSIAN_TRACER_SET_U16 -empty(::Type{HessianTracer{Set{UInt32},UInt32}}) = EMPTY_HESSIAN_TRACER_SET_U32 -empty(::Type{HessianTracer{Set{UInt64},UInt64}}) = EMPTY_HESSIAN_TRACER_SET_U64 -empty(::Type{HessianTracer{SortedVector{UInt16},UInt16}}) = EMPTY_HESSIAN_TRACER_SV_U16 -empty(::Type{HessianTracer{SortedVector{UInt32},UInt32}}) = EMPTY_HESSIAN_TRACER_SV_U32 -empty(::Type{HessianTracer{SortedVector{UInt64},UInt64}}) = EMPTY_HESSIAN_TRACER_SV_U64 + +empty(::Type{HessianTracer{BitSet,Int}}) = EMPTY_HESSIAN_TRACER_BITSET +empty(::Type{HessianTracer{Set{UInt8},UInt8}}) = EMPTY_HESSIAN_TRACER_SET_U8 +empty(::Type{HessianTracer{Set{UInt16},UInt16}}) = EMPTY_HESSIAN_TRACER_SET_U16 +empty(::Type{HessianTracer{Set{UInt32},UInt32}}) = EMPTY_HESSIAN_TRACER_SET_U32 +empty(::Type{HessianTracer{Set{UInt64},UInt64}}) = EMPTY_HESSIAN_TRACER_SET_U64 HessianTracer{S,I}(::Number) where {S,I} = empty(HessianTracer{S,I}) HessianTracer(t::HessianTracer) = t @@ -174,9 +156,6 @@ HessianTracer(t::HessianTracer) = t function keys2set(::Type{S}, d::Dict{I}) where {I<:Integer,S<:AbstractSet{<:I}} return S(keys(d)) end -function keys2set(::Type{S}, d::Dict{I}) where {I<:Integer,S<:SortedVector{I}} - return S(collect(keys(d)); sorted=false) -end # Turn first-order interactions into second-order interactions function promote_order(t::HessianTracer{S}) where {S} @@ -222,6 +201,7 @@ Return input indices of a [`ConnectivityTracer`](@ref) or [`JacobianTracer`](@re """ inputs(t::ConnectivityTracer) = collect(t.inputs) inputs(t::JacobianTracer) = collect(t.inputs) +inputs(t::HessianTracer, i::Integer) = collect(t.inputs[i]) """ tracer(T, index) where {T<:AbstractTracer} diff --git a/test/adtypes.jl b/test/adtypes.jl index 25b5272c..6eb07dc5 100644 --- a/test/adtypes.jl +++ b/test/adtypes.jl @@ -1,4 +1,4 @@ -using ADTypes +using ADTypes: jacobian_sparsity, hessian_sparsity using SparseConnectivityTracer using SparseArrays using Test @@ -7,19 +7,19 @@ sd = TracerSparsityDetector(BitSet) x = rand(10) y = zeros(9) -J1 = ADTypes.jacobian_sparsity(diff, x, sd) -J2 = ADTypes.jacobian_sparsity((y, x) -> y .= diff(x), y, x, sd) +J1 = jacobian_sparsity(diff, x, sd) +J2 = jacobian_sparsity((y, x) -> y .= diff(x), y, x, sd) @test J1 == J2 @test J1 isa SparseMatrixCSC @test J2 isa SparseMatrixCSC @test nnz(J1) == nnz(J2) == 18 -H1 = ADTypes.hessian_sparsity(x -> sum(diff(x)), x, sd) +H1 = hessian_sparsity(x -> sum(diff(x)), x, sd) @test H1 ≈ zeros(10, 10) x = rand(5) f(x) = x[1] + x[2] * x[3] + 1 / x[4] + 1 * x[5] -H2 = ADTypes.hessian_sparsity(f, x, sd) +H2 = hessian_sparsity(f, x, sd) @test H2 ≈ [ 0 0 0 0 0 0 0 1 0 0 diff --git a/test/brusselator.jl b/test/brusselator.jl index 344527c4..ca71292b 100644 --- a/test/brusselator.jl +++ b/test/brusselator.jl @@ -2,32 +2,26 @@ using ADTypes using ADTypes: AbstractSparsityDetector using ReferenceTests using SparseConnectivityTracer -using SparseConnectivityTracer: SortedVector +using SparseConnectivityTracer: DuplicateVector, RecursiveSet, SortedVector using Test include("brusselator_definition.jl") function test_brusselator(method::AbstractSparsityDetector) N = 6 - dims = (N, N, 2) - A = 1.0 - B = 1.0 - alpha = 1.0 - xyd = fill(1.0, N) - dx = 1.0 - p = (A, B, alpha, xyd, dx, N) + f! = Brusselator!(N) + x = rand(N, N, 2) + y = similar(x) - u = rand(dims...) - du = similar(u) - f!(du, u) = brusselator_2d_loop(du, u, p, nothing) - - J = ADTypes.jacobian_sparsity(f!, du, u, method) + J = ADTypes.jacobian_sparsity(f!, y, x, method) @test_reference "references/pattern/jacobian/Brusselator.txt" BitMatrix(J) end @testset "$method" for method in ( TracerSparsityDetector(BitSet), TracerSparsityDetector(Set{UInt64}), + TracerSparsityDetector(DuplicateVector{UInt64}), + TracerSparsityDetector(RecursiveSet{UInt64}), TracerSparsityDetector(SortedVector{UInt64}), ) test_brusselator(method) diff --git a/test/brusselator_definition.jl b/test/brusselator_definition.jl index 47c434c1..31cc36d3 100644 --- a/test/brusselator_definition.jl +++ b/test/brusselator_definition.jl @@ -18,3 +18,23 @@ function brusselator_2d_loop(du, u, p, t) end end #! format: on + +struct Brusselator!{P} + N::Int + params::P +end + +Base.show(b!::Brusselator!) = "Brusselator(N=$(b!.N))" + +function Brusselator!(N::Integer) + dims = (N, N, 2) + A = 1.0 + B = 1.0 + alpha = 1.0 + xyd = fill(1.0, N) + dx = 1.0 + params = (; A, B, alpha, xyd, dx, N) + return Brusselator!(N, params) +end + +(b!::Brusselator!)(y, x) = brusselator_2d_loop(y, x, b!.params, nothing) diff --git a/test/first_order.jl b/test/first_order.jl index 21dcc9af..b6f13be7 100644 --- a/test/first_order.jl +++ b/test/first_order.jl @@ -1,10 +1,12 @@ using ReferenceTests using SparseConnectivityTracer using SparseConnectivityTracer: tracer, trace_input, inputs, empty -using SparseConnectivityTracer: SortedVector +using SparseConnectivityTracer: DuplicateVector, RecursiveSet, SortedVector using Test -@testset "Set type $S" for S in (BitSet, Set{UInt64}, SortedVector{UInt64}) +@testset "Set type $S" for S in ( + BitSet, Set{UInt64}, DuplicateVector{UInt64}, RecursiveSet{UInt64}, SortedVector{UInt64} +) CT = ConnectivityTracer{S} JT = JacobianTracer{S} diff --git a/test/nnlib.jl b/test/nnlib.jl index fdf88443..1853e1d9 100644 --- a/test/nnlib.jl +++ b/test/nnlib.jl @@ -1,9 +1,9 @@ using ADTypes using ADTypes: AbstractSparsityDetector +using NNlib using ReferenceTests using SparseConnectivityTracer -using SparseConnectivityTracer: SortedVector -using NNlib +using SparseConnectivityTracer: DuplicateVector, RecursiveSet, SortedVector using Test function test_nnlib_conv(method::AbstractSparsityDetector) @@ -18,6 +18,8 @@ end @testset "$method" for method in ( TracerSparsityDetector(BitSet), TracerSparsityDetector(Set{UInt64}), + TracerSparsityDetector(DuplicateVector{UInt64}), + TracerSparsityDetector(RecursiveSet{UInt64}), TracerSparsityDetector(SortedVector{UInt64}), ) test_nnlib_conv(method) diff --git a/test/references/show/ConnectivityTracer_DuplicateVector{UInt64}.txt b/test/references/show/ConnectivityTracer_DuplicateVector{UInt64}.txt new file mode 100644 index 00000000..e84637a4 --- /dev/null +++ b/test/references/show/ConnectivityTracer_DuplicateVector{UInt64}.txt @@ -0,0 +1 @@ +ConnectivityTracer{DuplicateVector{UInt64}}(2,) \ No newline at end of file diff --git a/test/references/show/ConnectivityTracer_RecursiveSet{UInt64}.txt b/test/references/show/ConnectivityTracer_RecursiveSet{UInt64}.txt new file mode 100644 index 00000000..e90ca8f8 --- /dev/null +++ b/test/references/show/ConnectivityTracer_RecursiveSet{UInt64}.txt @@ -0,0 +1 @@ +ConnectivityTracer{RecursiveSet{UInt64}}(2,) \ No newline at end of file diff --git a/test/references/show/HessianTracer_DuplicateVector{UInt64}.txt b/test/references/show/HessianTracer_DuplicateVector{UInt64}.txt new file mode 100644 index 00000000..baf1bcea --- /dev/null +++ b/test/references/show/HessianTracer_DuplicateVector{UInt64}.txt @@ -0,0 +1,3 @@ +HessianTracer{DuplicateVector{UInt64}}( + 2 => (), +) \ No newline at end of file diff --git a/test/references/show/HessianTracer_RecursiveSet{UInt64}.txt b/test/references/show/HessianTracer_RecursiveSet{UInt64}.txt new file mode 100644 index 00000000..fa015a48 --- /dev/null +++ b/test/references/show/HessianTracer_RecursiveSet{UInt64}.txt @@ -0,0 +1,3 @@ +HessianTracer{RecursiveSet{UInt64}}( + 2 => (), +) \ No newline at end of file diff --git a/test/references/show/JacobianTracer_DuplicateVector{UInt64}.txt b/test/references/show/JacobianTracer_DuplicateVector{UInt64}.txt new file mode 100644 index 00000000..8a564f63 --- /dev/null +++ b/test/references/show/JacobianTracer_DuplicateVector{UInt64}.txt @@ -0,0 +1 @@ +JacobianTracer{DuplicateVector{UInt64}}(2,) \ No newline at end of file diff --git a/test/references/show/JacobianTracer_RecursiveSet{UInt64}.txt b/test/references/show/JacobianTracer_RecursiveSet{UInt64}.txt new file mode 100644 index 00000000..80e416e4 --- /dev/null +++ b/test/references/show/JacobianTracer_RecursiveSet{UInt64}.txt @@ -0,0 +1 @@ +JacobianTracer{RecursiveSet{UInt64}}(2,) \ No newline at end of file diff --git a/test/runtests.jl b/test/runtests.jl index e1d313ec..42b2a38b 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -43,8 +43,14 @@ DocMeta.setdocmeta!( end @testset verbose = true "Set types" begin + @testset "DuplicateVector" begin + include("settypes/duplicatevector.jl") + end + @testset "RecursiveSet" begin + include("settypes/recursiveset.jl") + end @testset "SortedVector" begin - include("sortedvector.jl") + include("settypes/sortedvector.jl") end end diff --git a/test/second_order.jl b/test/second_order.jl index 85f4d50a..e9dc16dc 100644 --- a/test/second_order.jl +++ b/test/second_order.jl @@ -1,10 +1,12 @@ using ReferenceTests using SparseConnectivityTracer using SparseConnectivityTracer: tracer, trace_input, inputs, empty -using SparseConnectivityTracer: SortedVector +using SparseConnectivityTracer: DuplicateVector, RecursiveSet, SortedVector using Test -@testset "Set type $S" for S in (BitSet, Set{UInt64}, SortedVector{UInt64}) +@testset "Set type $S" for S in ( + BitSet, Set{UInt64}, DuplicateVector{UInt64}, RecursiveSet{UInt64}, SortedVector{UInt64} +) HT = HessianTracer{S} @test hessian_pattern(identity, rand(), S) ≈ [0;;] diff --git a/test/settypes/duplicatevector.jl b/test/settypes/duplicatevector.jl new file mode 100644 index 00000000..78f6e1e9 --- /dev/null +++ b/test/settypes/duplicatevector.jl @@ -0,0 +1,17 @@ +using SparseConnectivityTracer: DuplicateVector +using Test + +x = DuplicateVector{Int}.(1:10) + +y = union( + union(x[1], x[3]), # + union( # + x[3], # + union( # + union(x[5], x[7]), # + x[1], # + ), + ), +) + +@test sort(collect(y)) == [1, 3, 5, 7] diff --git a/test/settypes/recursiveset.jl b/test/settypes/recursiveset.jl new file mode 100644 index 00000000..5835556c --- /dev/null +++ b/test/settypes/recursiveset.jl @@ -0,0 +1,19 @@ +using SparseConnectivityTracer: RecursiveSet +using Test + +x = RecursiveSet{Int}.(1:10) + +y = union( + union(x[1], x[3]), # + union( # + x[3], # + union( # + union(x[5], x[7]), # + x[1], # + ), + ), +) + +string(y) + +@test sort(collect(y)) == [1, 3, 5, 7] diff --git a/test/sortedvector.jl b/test/settypes/sortedvector.jl similarity index 100% rename from test/sortedvector.jl rename to test/settypes/sortedvector.jl