From 63273ef721f2123192d6f17403a336f47fe9085a Mon Sep 17 00:00:00 2001 From: adrhill Date: Wed, 26 Jun 2024 14:02:14 +0200 Subject: [PATCH 01/10] Add pattern abstraction --- src/SparseConnectivityTracer.jl | 4 + src/interface.jl | 8 +- src/patterns.jl | 147 ++++++++++++++++++++++++++++++++ src/tracers.jl | 84 ++++++------------ test/test_constructors.jl | 27 +++--- 5 files changed, 199 insertions(+), 71 deletions(-) create mode 100644 src/patterns.jl diff --git a/src/SparseConnectivityTracer.jl b/src/SparseConnectivityTracer.jl index 846f8d81..0cff835d 100644 --- a/src/SparseConnectivityTracer.jl +++ b/src/SparseConnectivityTracer.jl @@ -19,6 +19,10 @@ include("settypes/duplicatevector.jl") include("settypes/recursiveset.jl") include("settypes/sortedvector.jl") +abstract type AbstractPattern end +abstract type AbstractTracer{P<:AbstractPattern} <: Real end + +include("patterns.jl") include("tracers.jl") include("exceptions.jl") include("operators.jl") diff --git a/src/interface.jl b/src/interface.jl index 9e3f85de..6e290258 100644 --- a/src/interface.jl +++ b/src/interface.jl @@ -1,6 +1,8 @@ -const DEFAULT_CONNECTIVITY_TRACER = ConnectivityTracer{BitSet} -const DEFAULT_GRADIENT_TRACER = GradientTracer{BitSet} -const DEFAULT_HESSIAN_TRACER = HessianTracer{BitSet,Set{Tuple{Int,Int}}} +const DEFAULT_CONNECTIVITY_TRACER = ConnectivityTracer{IndexSetVector{Int,BitSet}} +const DEFAULT_GRADIENT_TRACER = GradientTracer{IndexSetVector{Int,BitSet}} +const DEFAULT_HESSIAN_TRACER = HessianTracer{ + IndexSetHessian{Int,BitSet,Set{Tuple{Int,Int}}} +} #==================# # Enumerate inputs # diff --git a/src/patterns.jl b/src/patterns.jl new file mode 100644 index 00000000..67e94b3c --- /dev/null +++ b/src/patterns.jl @@ -0,0 +1,147 @@ +""" + AbstractPattern + +Abstract supertype of all sparsity pattern representations. + +## Type hierarchy +``` +AbstractPattern +├── AbstractVectorPattern: used in GradientTracer, ConnectivityTracer +│ └── IndexSetVector +└── AbstractHessianPattern: used in HessianTracer + └── IndexSetHessian +``` +""" +AbstractPattern + +""" + myempty(P) + +Constructor for an empty pattern of type `P` representing a new number (usually an empty pattern). +""" +myempty(::P) where {P<:AbstractPattern} = myempty(P) +myempty(::T) where {P<:AbstractPattern,T<:AbstractTracer{P}} = T(myempty(P), true) +myempty(::Type{T}) where {P<:AbstractPattern,T<:AbstractTracer{P}} = T(myempty(P), true) + +""" +seed(P, i) + +Constructor for a pattern of type `P` that only contains the given index `i`. +""" +seed(::P, i) where {P<:AbstractPattern} = seed(P, i) +seed(::T, i) where {P<:AbstractPattern,T<:AbstractTracer{P}} = T(seed(P, i)) +seed(::Type{T}, i) where {P<:AbstractPattern,T<:AbstractTracer{P}} = T(seed(P, i)) + +#==========================# +# Utilities on AbstractSet # +#==========================# + +myempty(::Type{S}) where {S<:AbstractSet} = S() +seed(::Type{S}, i::Integer) where {S<:AbstractSet} = S(i) + +"""" + product(a::S{T}, b::S{T})::S{Tuple{T,T}} + +Inner product of set-like inputs `a` and `b`. +""" +product(a::AbstractSet{I}, b::AbstractSet{I}) where {I<:Integer} = + Set((i, j) for i in a, j in b) + +function union_product!( + hessian::SH, gradient_x::SG, gradient_y::SG +) where {I<:Integer,SG<:AbstractSet{I},SH<:AbstractSet{Tuple{I,I}}} + hxy = product(gradient_x, gradient_y) + return union!(hessian, hxy) +end + +#=======================# +# AbstractVectorPattern # +#=======================# + +# For use with ConnectivityTracer and GradientTracer. + +""" + AbstractVectorPattern <: AbstractPattern + +Abstract supertype of sparsity patterns representing a vector. +For use with [`ConnectivityTracer`](@ref) and [`GradientTracer`](@ref). + +## Expected interface + +* `myempty(::Type{MyPattern})`: return a pattern representing a new number (usually an empty pattern) +* `seed(::Type{MyPattern}, i::Integer)`: return an pattern that only contains the given index `i` +* `inputs(p::MyPattern)`: return non-zero indices `i` for use with `ConnectivityTracer` +* `gradient(p::MyPattern)`: return non-zero indices `i` for use with `GradientTracer` + +Note that besides their names, the last two functions are usually identical. +""" +abstract type AbstractVectorPattern <: AbstractPattern end + +""" +$(TYPEDEF) + +Vector sparsity pattern represented by an `AbstractSet` of indices ``{i}`` of non-zero values. + +## Fields +$(TYPEDFIELDS) +""" +struct IndexSetVector{I<:Integer,S<:AbstractSet{I}} <: AbstractVectorPattern + "Set of indices represting non-zero entries ``i`` in a vector." + vector::S +end + +Base.show(io::IO, s::IndexSetVector) = Base.show(io, s.vector) + +function myempty(::Type{IndexSetVector{I,S}}) where {I,S} + return IndexSetVector{I,S}(myempty(S)) +end +function seed(::Type{IndexSetVector{I,S}}, i) where {I,S} + return IndexSetVector{I,S}(seed(S, i)) +end + +# Tracer compatibility +inputs(s::IndexSetVector) = s.vector +gradient(s::IndexSetVector) = s.vector + +#========================# +# AbstractHessianPattern # +#========================# + +# For use with HessianTracer. + +""" + AbstractHessianPattern <: AbstractPattern + +Abstract supertype of sparsity patterns representing both gradient and Hessian sparsity. +For use with [`HessianTracer`](@ref). + +## Expected interface + +* `myempty(::Type{MyPattern})`: return a pattern representing a new number (usually an empty pattern) +* `seed(::Type{MyPattern}, i::Integer)`: return an pattern that only contains the given index `i` in the first-order representation +* `gradient(p::MyPattern)`: return non-zero indices `i` in the first-order representation +* `hessian(p::MyPattern)`: return non-zero indices `(i, j)` in the second-order representation +""" +abstract type AbstractHessianPattern <: AbstractPattern end + +""" + IndexSetHessian(vector::AbstractVectorPattern, mat::AbstractMatrixPattern) + +Gradient and Hessian sparsity patterns constructed by combining two AbstractSets. +""" +struct IndexSetHessian{I<:Integer,SG<:AbstractSet{I},SH<:AbstractSet{Tuple{I,I}}} <: + AbstractHessianPattern + gradient::SG + hessian::SH +end + +function myempty(::Type{IndexSetHessian{I,SG,SH}}) where {I,SG,SH} + return IndexSetHessian{I,SG,SH}(myempty(SG), myempty(SH)) +end +function seed(::Type{IndexSetHessian{I,SG,SH}}, index) where {I,SG,SH} + return IndexSetHessian{I,SG,SH}(seed(SG, index), myempty(SH)) +end + +# Tracer compatibility +gradient(s::IndexSetHessian) = s.gradient +hessian(s::IndexSetHessian) = s.hessian diff --git a/src/tracers.jl b/src/tracers.jl index 672d9a42..66fae3b6 100644 --- a/src/tracers.jl +++ b/src/tracers.jl @@ -1,21 +1,3 @@ -abstract type AbstractTracer <: Real end - -#===================# -# Set operations # -#===================# - -myempty(::Type{S}) where {S<:AbstractSet} = S() -seed(::Type{S}, i::Integer) where {S<:AbstractSet} = S(i) - -product(a::AbstractSet{I}, b::AbstractSet{I}) where {I} = Set((i, j) for i in a, j in b) - -function union_product!( - h::H, gx::G, gy::G -) where {I<:Integer,G<:AbstractSet{I},H<:AbstractSet{Tuple{I,I}}} - hxy = product(gx, gy) - return union!(h, hxy) -end - #====================# # ConnectivityTracer # #====================# @@ -30,14 +12,14 @@ For a higher-level interface, refer to [`connectivity_pattern`](@ref). ## Fields $(TYPEDFIELDS) """ -struct ConnectivityTracer{I} <: AbstractTracer +struct ConnectivityTracer{P<:AbstractVectorPattern} <: AbstractTracer{P} "Sparse representation of connected inputs." - inputs::I + pattern::P "Indicator whether pattern in tracer contains only zeros." isempty::Bool - function ConnectivityTracer{I}(inputs::I, isempty::Bool=false) where {I} - return new{I}(inputs, isempty) + function ConnectivityTracer{P}(inputs::P, isempty::Bool=false) where {P} + return new{P}(inputs, isempty) end end @@ -45,11 +27,11 @@ end # Generic code expecting "regular" numbers `x` will sometimes convert them # by calling `T(x)` (instead of `convert(T, x)`), where `T` can be `ConnectivityTracer`. # When this happens, we create a new empty tracer with no input pattern. -ConnectivityTracer{I}(::Real) where {I} = myempty(ConnectivityTracer{I}) -ConnectivityTracer{I}(t::ConnectivityTracer{I}) where {I} = t +ConnectivityTracer{P}(::Real) where {P} = myempty(ConnectivityTracer{P}) +ConnectivityTracer{P}(t::ConnectivityTracer{P}) where {P} = t ConnectivityTracer(t::ConnectivityTracer) = t -inputs(t::ConnectivityTracer) = t.inputs +inputs(t::ConnectivityTracer) = inputs(t.pattern) isemptytracer(t::ConnectivityTracer) = t.isempty function Base.show(io::IO, t::ConnectivityTracer) @@ -77,22 +59,22 @@ For a higher-level interface, refer to [`jacobian_pattern`](@ref). ## Fields $(TYPEDFIELDS) """ -struct GradientTracer{G} <: AbstractTracer +struct GradientTracer{P<:AbstractVectorPattern} <: AbstractTracer{P} "Sparse representation of non-zero entries in the gradient." - gradient::G + pattern::P "Indicator whether gradient in tracer contains only zeros." isempty::Bool - function GradientTracer{G}(gradient::G, isempty::Bool=false) where {G} - return new{G}(gradient, isempty) + function GradientTracer{P}(gradient::P, isempty::Bool=false) where {P} + return new{P}(gradient, isempty) end end -GradientTracer{G}(::Real) where {G} = myempty(GradientTracer{G}) -GradientTracer{G}(t::GradientTracer{G}) where {G} = t +GradientTracer{P}(::Real) where {P} = myempty(GradientTracer{P}) +GradientTracer{P}(t::GradientTracer{P}) where {P} = t GradientTracer(t::GradientTracer) = t -gradient(t::GradientTracer) = t.gradient +gradient(t::GradientTracer) = gradient(t.pattern) isemptytracer(t::GradientTracer) = t.isempty function Base.show(io::IO, t::GradientTracer) @@ -120,25 +102,23 @@ For a higher-level interface, refer to [`hessian_pattern`](@ref). ## Fields $(TYPEDFIELDS) """ -struct HessianTracer{G,H} <: AbstractTracer +struct HessianTracer{P<:AbstractHessianPattern} <: AbstractTracer{P} "Sparse representation of non-zero entries in the gradient and the Hessian." - gradient::G - "Sparse representation of non-zero entries in the Hessian." - hessian::H + pattern::P "Indicator whether gradient and Hessian in tracer both contain only zeros." isempty::Bool - function HessianTracer{G,H}(gradient::G, hessian::H, isempty::Bool=false) where {G,H} - return new{G,H}(gradient, hessian, isempty) + function HessianTracer{P}(pattern::P, isempty::Bool=false) where {P} + return new{P}(pattern, isempty) end end -HessianTracer{G,H}(::Real) where {G,H} = myempty(HessianTracer{G,H}) -HessianTracer{G,H}(t::HessianTracer{G,H}) where {G,H} = t +HessianTracer{P}(::Real) where {P} = myempty(HessianTracer{P}) +HessianTracer{P}(t::HessianTracer{P}) where {P} = t HessianTracer(t::HessianTracer) = t -gradient(t::HessianTracer) = t.gradient -hessian(t::HessianTracer) = t.hessian +gradient(t::HessianTracer) = gradient(t.pattern) +hessian(t::HessianTracer) = hessian(t.pattern) isemptytracer(t::HessianTracer) = t.isempty function Base.show(io::IO, t::HessianTracer) @@ -199,27 +179,19 @@ end # Utilities # #===========# -myempty(::Type{ConnectivityTracer{I}}) where {I} = ConnectivityTracer{I}(myempty(I), true) -myempty(::Type{GradientTracer{G}}) where {G} = GradientTracer{G}(myempty(G), true) -myempty(::Type{HessianTracer{G,H}}) where {G,H} = HessianTracer{G,H}(myempty(G), myempty(H), true) - """ create_tracer(T, index) where {T<:AbstractTracer} Convenience constructor for [`ConnectivityTracer`](@ref), [`GradientTracer`](@ref) and [`HessianTracer`](@ref) from input indices. """ -function create_tracer(::Type{Dual{P,T}}, primal::Real, index::Integer) where {P,T} - return Dual(primal, create_tracer(T, primal, index)) +function create_tracer( + ::Type{T}, ::Real, index::Integer +) where {P<:AbstractPattern,T<:AbstractTracer{P}} + return T(seed(P, index)) end -function create_tracer(::Type{ConnectivityTracer{I}}, ::Real, index::Integer) where {I} - return ConnectivityTracer{I}(seed(I, index)) -end -function create_tracer(::Type{GradientTracer{G}}, ::Real, index::Integer) where {G} - return GradientTracer{G}(seed(G, index)) -end -function create_tracer(::Type{HessianTracer{G,H}}, ::Real, index::Integer) where {G,H} - return HessianTracer{G,H}(seed(G, index), myempty(H)) +function create_tracer(::Type{Dual{P,T}}, primal::Real, index::Integer) where {P,T} + return Dual(primal, create_tracer(T, primal, index)) end # Pretty-printing of Dual tracers diff --git a/test/test_constructors.jl b/test/test_constructors.jl index cb6f479c..c7fcbdb8 100644 --- a/test/test_constructors.jl +++ b/test/test_constructors.jl @@ -1,30 +1,33 @@ # Test construction and conversions of internal tracer types using SparseConnectivityTracer: AbstractTracer, ConnectivityTracer, GradientTracer, HessianTracer, Dual +using SparseConnectivityTracer: IndexSetVector, IndexSetHessian using SparseConnectivityTracer: inputs, primal, tracer, isemptytracer using SparseConnectivityTracer: myempty, name using SparseConnectivityTracer: DuplicateVector, RecursiveSet, SortedVector using Test CONNECTIVITY_TRACERS = ( - ConnectivityTracer{BitSet}, - ConnectivityTracer{Set{Int}}, - ConnectivityTracer{DuplicateVector{Int}}, - ConnectivityTracer{SortedVector{Int}}, + ConnectivityTracer{IndexSetVector{Int,BitSet}}, + ConnectivityTracer{IndexSetVector{Int,Set{Int}}}, + ConnectivityTracer{IndexSetVector{Int,DuplicateVector{Int}}}, + ConnectivityTracer{IndexSetVector{Int,SortedVector{Int}}}, ) GRADIENT_TRACERS = ( - GradientTracer{BitSet}, - GradientTracer{Set{Int}}, - GradientTracer{DuplicateVector{Int}}, - GradientTracer{SortedVector{Int}}, + GradientTracer{IndexSetVector{Int,BitSet}}, + GradientTracer{IndexSetVector{Int,Set{Int}}}, + GradientTracer{IndexSetVector{Int,DuplicateVector{Int}}}, + GradientTracer{IndexSetVector{Int,SortedVector{Int}}}, ) HESSIAN_TRACERS = ( - HessianTracer{BitSet,Set{Tuple{Int,Int}}}, - HessianTracer{Set{Int},Set{Tuple{Int,Int}}}, - HessianTracer{DuplicateVector{Int},DuplicateVector{Tuple{Int,Int}}}, - HessianTracer{SortedVector{Int},SortedVector{Tuple{Int,Int}}}, + HessianTracer{IndexSetHessian{Int,BitSet,Set{Tuple{Int,Int}}}}, + HessianTracer{IndexSetHessian{Int,Set{Int},Set{Tuple{Int,Int}}}}, + HessianTracer{ + IndexSetHessian{Int,DuplicateVector{Int},DuplicateVector{Tuple{Int,Int}}} + }, + HessianTracer{IndexSetHessian{Int,SortedVector{Int},SortedVector{Tuple{Int,Int}}}}, # TODO: test on RecursiveSet ) From 8601c431d1f2c0741f2572d83bf53ae037b0cb7a Mon Sep 17 00:00:00 2001 From: adrhill Date: Wed, 26 Jun 2024 14:26:11 +0200 Subject: [PATCH 02/10] Put testing tracer defs in one place --- test/brusselator.jl | 8 ++------ test/test_connectivity.jl | 9 ++------- test/test_constructors.jl | 27 ++------------------------- test/test_gradient.jl | 9 ++------- test/test_hessian.jl | 10 ++-------- test/tracers_definitions.jl | 23 +++++++++++++++++++++++ 6 files changed, 33 insertions(+), 53 deletions(-) create mode 100644 test/tracers_definitions.jl diff --git a/test/brusselator.jl b/test/brusselator.jl index 5cadfd5e..16972d89 100644 --- a/test/brusselator.jl +++ b/test/brusselator.jl @@ -6,12 +6,8 @@ using SparseConnectivityTracer: DuplicateVector, RecursiveSet, SortedVector using SparseConnectivityTracerBenchmarks.ODE: Brusselator! using Test -GRADIENT_TRACERS = ( - GradientTracer{BitSet}, - GradientTracer{Set{Int}}, - GradientTracer{DuplicateVector{Int}}, - GradientTracer{SortedVector{Int}}, -) +# Load definitions of CONNECTIVITY_TRACERS, GRADIENT_TRACERS, HESSIAN_TRACERS +include("tracers_definitions.jl") function test_brusselator(method::AbstractSparsityDetector) N = 6 diff --git a/test/test_connectivity.jl b/test/test_connectivity.jl index 46f263b8..1c7f78bf 100644 --- a/test/test_connectivity.jl +++ b/test/test_connectivity.jl @@ -1,17 +1,12 @@ using SparseConnectivityTracer using SparseConnectivityTracer: ConnectivityTracer, Dual, MissingPrimalError, trace_input -using SparseConnectivityTracer: DuplicateVector, RecursiveSet, SortedVector using LinearAlgebra: det, dot, logdet using SpecialFunctions: erf, beta using NNlib: NNlib using Test -CONNECTIVITY_TRACERS = ( - ConnectivityTracer{BitSet}, - ConnectivityTracer{Set{Int}}, - ConnectivityTracer{DuplicateVector{Int}}, - ConnectivityTracer{SortedVector{Int}}, -) +# Load definitions of CONNECTIVITY_TRACERS, GRADIENT_TRACERS, HESSIAN_TRACERS +include("tracers_definitions.jl") NNLIB_ACTIVATIONS_S = ( NNlib.σ, diff --git a/test/test_constructors.jl b/test/test_constructors.jl index c7fcbdb8..470502c1 100644 --- a/test/test_constructors.jl +++ b/test/test_constructors.jl @@ -1,35 +1,12 @@ # Test construction and conversions of internal tracer types using SparseConnectivityTracer: AbstractTracer, ConnectivityTracer, GradientTracer, HessianTracer, Dual -using SparseConnectivityTracer: IndexSetVector, IndexSetHessian using SparseConnectivityTracer: inputs, primal, tracer, isemptytracer using SparseConnectivityTracer: myempty, name -using SparseConnectivityTracer: DuplicateVector, RecursiveSet, SortedVector using Test -CONNECTIVITY_TRACERS = ( - ConnectivityTracer{IndexSetVector{Int,BitSet}}, - ConnectivityTracer{IndexSetVector{Int,Set{Int}}}, - ConnectivityTracer{IndexSetVector{Int,DuplicateVector{Int}}}, - ConnectivityTracer{IndexSetVector{Int,SortedVector{Int}}}, -) - -GRADIENT_TRACERS = ( - GradientTracer{IndexSetVector{Int,BitSet}}, - GradientTracer{IndexSetVector{Int,Set{Int}}}, - GradientTracer{IndexSetVector{Int,DuplicateVector{Int}}}, - GradientTracer{IndexSetVector{Int,SortedVector{Int}}}, -) - -HESSIAN_TRACERS = ( - HessianTracer{IndexSetHessian{Int,BitSet,Set{Tuple{Int,Int}}}}, - HessianTracer{IndexSetHessian{Int,Set{Int},Set{Tuple{Int,Int}}}}, - HessianTracer{ - IndexSetHessian{Int,DuplicateVector{Int},DuplicateVector{Tuple{Int,Int}}} - }, - HessianTracer{IndexSetHessian{Int,SortedVector{Int},SortedVector{Tuple{Int,Int}}}}, - # TODO: test on RecursiveSet -) +# Load definitions of CONNECTIVITY_TRACERS, GRADIENT_TRACERS, HESSIAN_TRACERS +include("tracers_definitions.jl") function test_nested_duals(::Type{T}) where {T<:AbstractTracer} # Putting Duals into Duals is prohibited diff --git a/test/test_gradient.jl b/test/test_gradient.jl index 8f5aea5e..29f3dc71 100644 --- a/test/test_gradient.jl +++ b/test/test_gradient.jl @@ -1,18 +1,13 @@ using SparseConnectivityTracer using SparseConnectivityTracer: GradientTracer, Dual, MissingPrimalError, trace_input -using SparseConnectivityTracer: DuplicateVector, RecursiveSet, SortedVector using ADTypes: jacobian_sparsity using LinearAlgebra: det, dot, logdet using SpecialFunctions: erf, beta using NNlib: NNlib using Test -GRADIENT_TRACERS = ( - GradientTracer{BitSet}, - GradientTracer{Set{Int}}, - GradientTracer{DuplicateVector{Int}}, - GradientTracer{SortedVector{Int}}, -) +# Load definitions of CONNECTIVITY_TRACERS, GRADIENT_TRACERS, HESSIAN_TRACERS +include("tracers_definitions.jl") NNLIB_ACTIVATIONS_S = ( NNlib.σ, diff --git a/test/test_hessian.jl b/test/test_hessian.jl index 6075e38d..609085d8 100644 --- a/test/test_hessian.jl +++ b/test/test_hessian.jl @@ -1,17 +1,11 @@ using SparseConnectivityTracer using SparseConnectivityTracer: Dual, HessianTracer, MissingPrimalError, trace_input, empty -using SparseConnectivityTracer: DuplicateVector, RecursiveSet, SortedVector using ADTypes: hessian_sparsity using SpecialFunctions: erf, beta using Test -HESSIAN_TRACERS = ( - HessianTracer{BitSet,Set{Tuple{Int,Int}}}, - HessianTracer{Set{Int},Set{Tuple{Int,Int}}}, - HessianTracer{DuplicateVector{Int},DuplicateVector{Tuple{Int,Int}}}, - HessianTracer{SortedVector{Int},SortedVector{Tuple{Int,Int}}}, - # TODO: test on RecursiveSet -) +# Load definitions of CONNECTIVITY_TRACERS, GRADIENT_TRACERS, HESSIAN_TRACERS +include("tracers_definitions.jl") @testset "Global Hessian" begin @testset "Default hessian_pattern" begin diff --git a/test/tracers_definitions.jl b/test/tracers_definitions.jl new file mode 100644 index 00000000..8b2a84d4 --- /dev/null +++ b/test/tracers_definitions.jl @@ -0,0 +1,23 @@ +using SparseConnectivityTracer: + AbstractTracer, ConnectivityTracer, GradientTracer, HessianTracer, Dual +using SparseConnectivityTracer: IndexSetVector, IndexSetHessian +using SparseConnectivityTracer: DuplicateVector, RecursiveSet, SortedVector + +VECTOR_PATTERNS = ( + IndexSetVector{Int,BitSet}, + IndexSetVector{Int,Set{Int}}, + IndexSetVector{Int,DuplicateVector{Int}}, + IndexSetVector{Int,SortedVector{Int}}, +) + +HESSIAN_PATTERNS = ( + IndexSetHessian{Int,BitSet,Set{Tuple{Int,Int}}}, + IndexSetHessian{Int,Set{Int},Set{Tuple{Int,Int}}}, + IndexSetHessian{Int,DuplicateVector{Int},DuplicateVector{Tuple{Int,Int}}}, + IndexSetHessian{Int,SortedVector{Int},SortedVector{Tuple{Int,Int}}}, + # TODO: test on RecursiveSet +) + +CONNECTIVITY_TRACERS = (ConnectivityTracer{P} for P in VECTOR_PATTERNS) +GRADIENT_TRACERS = (GradientTracer{P} for P in VECTOR_PATTERNS) +HESSIAN_TRACERS = (HessianTracer{P} for P in HESSIAN_PATTERNS) From ddc9b29d84684507bb1a07371bae37932de6ebb6 Mon Sep 17 00:00:00 2001 From: adrhill Date: Wed, 26 Jun 2024 14:57:54 +0200 Subject: [PATCH 03/10] Update tests --- test/flux.jl | 8 ++------ test/test_arrays.jl | 25 +++++++++++++------------ 2 files changed, 15 insertions(+), 18 deletions(-) diff --git a/test/flux.jl b/test/flux.jl index e428f552..2cbf33ed 100644 --- a/test/flux.jl +++ b/test/flux.jl @@ -6,12 +6,8 @@ using SparseConnectivityTracer using SparseConnectivityTracer: DuplicateVector, RecursiveSet, SortedVector using Test -GRADIENT_TRACERS = ( - GradientTracer{BitSet}, - GradientTracer{Set{Int}}, - GradientTracer{DuplicateVector{Int}}, - GradientTracer{SortedVector{Int}}, -) +# Load definitions of CONNECTIVITY_TRACERS, GRADIENT_TRACERS, HESSIAN_TRACERS +include("tracers_definitions.jl") const INPUT_FLUX = reshape( [ diff --git a/test/test_arrays.jl b/test/test_arrays.jl index 90b224e6..636aaa9d 100644 --- a/test/test_arrays.jl +++ b/test/test_arrays.jl @@ -18,7 +18,8 @@ TEST_SQUARE_MATRICES = Dict( TEST_MATRICES = merge(TEST_SQUARE_MATRICES, Dict("`Matrix` (3×4)" => rand(3, 4))) S = BitSet -TG = GradientTracer{S} +P = IndexSetVector{Int,S} +TG = GradientTracer{P} # NOTE: we currently test for conservative patterns on array overloads # Changes making array overloads less convervative will break these tests, but are welcome! @@ -141,10 +142,10 @@ end end @testset "Matrix division" begin - t1 = TG(S([1, 3, 4])) - t2 = TG(S([2, 4])) - t3 = TG(S([8, 9])) - t4 = TG(S([8, 9])) + t1 = TG(P(S([1, 3, 4]))) + t2 = TG(P(S([2, 4]))) + t3 = TG(P(S([8, 9]))) + t4 = TG(P(S([8, 9]))) A = [t1 t2; t3 t4] s_out = S([1, 2, 3, 4, 8, 9]) @@ -154,10 +155,10 @@ end end @testset "Eigenvalues" begin - t1 = TG(S([1, 3, 4])) - t2 = TG(S([2, 4])) - t3 = TG(S([8, 9])) - t4 = TG(S([8, 9])) + t1 = TG(P(S([1, 3, 4]))) + t2 = TG(P(S([2, 4]))) + t3 = TG(P(S([8, 9]))) + t4 = TG(P(S([8, 9]))) A = [t1 t2; t3 t4] s_out = S([1, 2, 3, 4, 8, 9]) values, vectors = eigen(A) @@ -168,9 +169,9 @@ end end @testset "SparseMatrixCSC construction" begin - t1 = TG(S(1)) - t2 = TG(S(2)) - t3 = TG(S(3)) + t1 = TG(P(S(1))) + t2 = TG(P(S(2))) + t3 = TG(P(S(3))) SA = sparse([t1 t2; t3 0]) @test length(SA.nzval) == 3 From 6a753d2be285f4e7a90a721a714f863fbda4df01 Mon Sep 17 00:00:00 2001 From: adrhill Date: Wed, 26 Jun 2024 15:14:35 +0200 Subject: [PATCH 04/10] yield a few times --- test/brusselator.jl | 1 + test/classification.jl | 3 +++ test/nlpmodels.jl | 1 + test/test_connectivity.jl | 2 ++ test/test_gradient.jl | 2 ++ test/test_hessian.jl | 2 ++ 6 files changed, 11 insertions(+) diff --git a/test/brusselator.jl b/test/brusselator.jl index 16972d89..6229ff20 100644 --- a/test/brusselator.jl +++ b/test/brusselator.jl @@ -22,4 +22,5 @@ end @testset "$T" for T in GRADIENT_TRACERS method = TracerSparsityDetector(; gradient_tracer_type=T) test_brusselator(method) + yield() end diff --git a/test/classification.jl b/test/classification.jl index f4aee69c..f25909f9 100644 --- a/test/classification.jl +++ b/test/classification.jl @@ -89,6 +89,7 @@ end correct_classification_1_to_1(op, random_input(op); atol=DEFAULT_ATOL) for _ in 1:DEFAULT_TRIALS ) + yield() end end end; @@ -132,6 +133,7 @@ end op, random_first_input(op), random_second_input(op); atol=DEFAULT_ATOL ) for _ in 1:DEFAULT_TRIALS ) + yield() end end end; @@ -170,6 +172,7 @@ end correct_classification_1_to_2(op, random_input(op); atol=DEFAULT_ATOL) for _ in 1:DEFAULT_TRIALS ) + yield() end end end; diff --git a/test/nlpmodels.jl b/test/nlpmodels.jl index 940d2e78..87ec57c8 100644 --- a/test/nlpmodels.jl +++ b/test/nlpmodels.jl @@ -67,6 +67,7 @@ hess_inconsistencies = [] push!(hess_inconsistencies, (name, message)) end end + yield() end; if !isempty(jac_inconsistencies) || !isempty(hess_inconsistencies) diff --git a/test/test_connectivity.jl b/test/test_connectivity.jl index 1c7f78bf..5d6e6812 100644 --- a/test/test_connectivity.jl +++ b/test/test_connectivity.jl @@ -116,6 +116,7 @@ NNLIB_ACTIVATIONS = union(NNLIB_ACTIVATIONS_S, NNLIB_ACTIVATIONS_F) @test_throws TypeError connectivity_pattern( x -> x[1] > x[2] ? x[3] : x[4], [1.0, 2.0, 3.0, 4.0], T ) == [0 0 1 1;] + yield() end end @@ -128,5 +129,6 @@ end x -> ifelse(x[2] < x[3], x[1] + x[2], x[3] * x[4]), [1 3 2 4], T ) == [0 0 1 1] @test local_connectivity_pattern(x -> 0, 1, T) ≈ [0;;] + yield() end end diff --git a/test/test_gradient.jl b/test/test_gradient.jl index 29f3dc71..1f783fa5 100644 --- a/test/test_gradient.jl +++ b/test/test_gradient.jl @@ -125,6 +125,7 @@ NNLIB_ACTIVATIONS = union(NNLIB_ACTIVATIONS_S, NNLIB_ACTIVATIONS_F) @test_throws TypeError jacobian_sparsity( x -> x[1] > x[2] ? x[3] : x[4], [1.0, 2.0, 3.0, 4.0], method ) == [0 0 1 1;] + yield() end end @@ -249,5 +250,6 @@ end @test jacobian_sparsity(NNlib.softshrink, -1, method) ≈ [1;;] @test jacobian_sparsity(NNlib.softshrink, 0, method) ≈ [0;;] @test jacobian_sparsity(NNlib.softshrink, 1, method) ≈ [1;;] + yield() end end diff --git a/test/test_hessian.jl b/test/test_hessian.jl index 609085d8..68cf5f08 100644 --- a/test/test_hessian.jl +++ b/test/test_hessian.jl @@ -208,6 +208,7 @@ include("tracers_definitions.jl") 1 1 0 0 0 0 ] + yield() end end @@ -262,5 +263,6 @@ end @test hessian_sparsity(x -> (2//3)^zero(x), 1, method) ≈ [0;;] @test hessian_sparsity(x -> zero(x)^ℯ, 1, method) ≈ [0;;] @test hessian_sparsity(x -> ℯ^zero(x), 1, method) ≈ [0;;] + yield() end end From bec0d5eae7099f545f5cdde59c4348a8cec41419 Mon Sep 17 00:00:00 2001 From: adrhill Date: Wed, 26 Jun 2024 15:16:05 +0200 Subject: [PATCH 05/10] Fix overloads --- src/overloads/connectivity_tracer.jl | 14 +++--- src/overloads/gradient_tracer.jl | 19 +++++++- src/overloads/hessian_tracer.jl | 70 ++++++++++++++-------------- src/overloads/ifelse_global.jl | 16 +++---- src/patterns.jl | 6 ++- src/tracers.jl | 11 +++-- 6 files changed, 77 insertions(+), 59 deletions(-) diff --git a/src/overloads/connectivity_tracer.jl b/src/overloads/connectivity_tracer.jl index eb666229..b1dc5d25 100644 --- a/src/overloads/connectivity_tracer.jl +++ b/src/overloads/connectivity_tracer.jl @@ -49,23 +49,23 @@ end return connectivity_tracer_1_to_1(ty, is_infl_arg2_zero) else i_out = connectivity_tracer_2_to_1_inner( - inputs(tx), inputs(ty), is_infl_arg1_zero, is_infl_arg2_zero + pattern(tx), pattern(ty), is_infl_arg1_zero, is_infl_arg2_zero ) return T(i_out) # return tracer end end function connectivity_tracer_2_to_1_inner( - sx::S, sy::S, is_infl_arg1_zero::Bool, is_infl_arg2_zero::Bool -) where {S<:AbstractSet{<:Integer}} + px::P, py::P, is_infl_arg1_zero::Bool, is_infl_arg2_zero::Bool +) where {P<:IndexSetVector} if is_infl_arg1_zero && is_infl_arg2_zero - return myempty(S) + return myempty(P) elseif !is_infl_arg1_zero && is_infl_arg2_zero - return sx + return px elseif is_infl_arg1_zero && !is_infl_arg2_zero - return sy + return py else - return union(sx, sy) # return set + return P(union(set(px), set(py))) # return pattern end end diff --git a/src/overloads/gradient_tracer.jl b/src/overloads/gradient_tracer.jl index b339078c..a01f64f7 100644 --- a/src/overloads/gradient_tracer.jl +++ b/src/overloads/gradient_tracer.jl @@ -10,7 +10,12 @@ end end -# Called by HessianTracer with AbstractSet +function gradient_tracer_1_to_1_inner(p::P, is_der1_zero::Bool) where {P<:IndexSetVector} + return P(gradient_tracer_1_to_1_inner(set(p), is_der1_zero)) # return pattern +end + +# This is only required because it is called by HessianTracer with IndexSetHessian +# Otherwise, we would just have the method on IndexSetVector above. function gradient_tracer_1_to_1_inner( s::S, is_der1_zero::Bool ) where {S<:AbstractSet{<:Integer}} @@ -60,12 +65,22 @@ end return gradient_tracer_1_to_1(ty, is_der1_arg2_zero) else g_out = gradient_tracer_2_to_1_inner( - gradient(tx), gradient(ty), is_der1_arg1_zero, is_der1_arg2_zero + pattern(tx), pattern(ty), is_der1_arg1_zero, is_der1_arg2_zero ) return T(g_out) # return tracer end end +function gradient_tracer_2_to_1_inner( + px::P, py::P, is_der1_arg1_zero::Bool, is_der1_arg2_zero::Bool +) where {P<:IndexSetVector} + return P( + gradient_tracer_2_to_1_inner(set(px), set(py), is_der1_arg1_zero, is_der1_arg2_zero) + ) # return pattern +end + +# This is only required because it is called by HessianTracer with IndexSetHessian +# Otherwise, we would just have the method on IndexSetVector above. function gradient_tracer_2_to_1_inner( sx::S, sy::S, is_der1_arg1_zero::Bool, is_der1_arg2_zero::Bool ) where {S<:AbstractSet{<:Integer}} diff --git a/src/overloads/hessian_tracer.jl b/src/overloads/hessian_tracer.jl index c15d7ee2..8634f6a3 100644 --- a/src/overloads/hessian_tracer.jl +++ b/src/overloads/hessian_tracer.jl @@ -1,32 +1,32 @@ ## 1-to-1 @noinline function hessian_tracer_1_to_1( - t::T, is_der1_zero::Bool, is_secondder_zero::Bool + t::T, is_der1_zero::Bool, is_der2_zero::Bool ) where {T<:HessianTracer} if isemptytracer(t) # TODO: add test return t else - g_out, h_out = hessian_tracer_1_to_1_inner( - gradient(t), hessian(t), is_der1_zero, is_secondder_zero - ) - return T(g_out, h_out) # return tracer + p_out = hessian_tracer_1_to_1_inner(pattern(t), is_der1_zero, is_der2_zero) + return T(p_out) # return tracer end end function hessian_tracer_1_to_1_inner( - sg::G, sh::H, is_der1_zero::Bool, is_secondder_zero::Bool -) where {I<:Integer,G<:AbstractSet{I},H<:AbstractSet{Tuple{I,I}}} + p::P, is_der1_zero::Bool, is_der2_zero::Bool +) where {I,SG,SH,P<:IndexSetHessian{I,SG,SH}} + sg = gradient(p) + sh = hessian(p) sg_out = gradient_tracer_1_to_1_inner(sg, is_der1_zero) - sh_out = if is_der1_zero && is_secondder_zero - myempty(H) - elseif !is_der1_zero && is_secondder_zero + sh_out = if is_der1_zero && is_der2_zero + myempty(SH) + elseif !is_der1_zero && is_der2_zero sh - elseif is_der1_zero && !is_secondder_zero - union_product!(myempty(H), sg, sg) + elseif is_der1_zero && !is_der2_zero + union_product!(myempty(SH), sg, sg) else union_product!(copy(sh), sg, sg) end - return sg_out, sh_out # return sets + return P(sg_out, sh_out) # return pattern end function overload_hessian_1_to_1(M, op) @@ -62,54 +62,52 @@ end tx::T, ty::T, is_der1_arg1_zero::Bool, - is_secondder_arg1_zero::Bool, + is_der2_arg1_zero::Bool, is_der1_arg2_zero::Bool, - is_secondder_arg2_zero::Bool, + is_der2_arg2_zero::Bool, is_der_cross_zero::Bool, ) where {T<:HessianTracer} # TODO: add tests for isempty if tx.isempty && ty.isempty return tx # empty tracer elseif ty.isempty - return hessian_tracer_1_to_1(tx, is_der1_arg1_zero, is_secondder_arg1_zero) + return hessian_tracer_1_to_1(tx, is_der1_arg1_zero, is_der2_arg1_zero) elseif tx.isempty - return hessian_tracer_1_to_1(ty, is_der1_arg2_zero, is_secondder_arg2_zero) + return hessian_tracer_1_to_1(ty, is_der1_arg2_zero, is_der2_arg2_zero) else - g_out, h_out = hessian_tracer_2_to_1_inner( - gradient(tx), - hessian(tx), - gradient(ty), - hessian(ty), + p_out = hessian_tracer_2_to_1_inner( + pattern(tx), + pattern(ty), is_der1_arg1_zero, - is_secondder_arg1_zero, + is_der2_arg1_zero, is_der1_arg2_zero, - is_secondder_arg2_zero, + is_der2_arg2_zero, is_der_cross_zero, ) - return T(g_out, h_out) # return tracer + return T(p_out) # return tracer end end function hessian_tracer_2_to_1_inner( - sgx::G, - shx::H, - sgy::G, - shy::H, + px::P, + py::P, is_der1_arg1_zero::Bool, - is_secondder_arg1_zero::Bool, + is_der2_arg1_zero::Bool, is_der1_arg2_zero::Bool, - is_secondder_arg2_zero::Bool, + is_der2_arg2_zero::Bool, is_der_cross_zero::Bool, -) where {I<:Integer,G<:AbstractSet{I},H<:AbstractSet{Tuple{I,I}}} +) where {I,SG,SH,P<:IndexSetHessian{I,SG,SH}} + sgx, shx = gradient(px), hessian(px) + sgy, shy = gradient(py), hessian(py) sg_out = gradient_tracer_2_to_1_inner(sgx, sgy, is_der1_arg1_zero, is_der1_arg2_zero) - sh_out = myempty(H) + sh_out = myempty(SH) !is_der1_arg1_zero && union!(sh_out, shx) # hessian alpha !is_der1_arg2_zero && union!(sh_out, shy) # hessian beta - !is_secondder_arg1_zero && union_product!(sh_out, sgx, sgx) # product alpha - !is_secondder_arg2_zero && union_product!(sh_out, sgy, sgy) # product beta + !is_der2_arg1_zero && union_product!(sh_out, sgx, sgx) # product alpha + !is_der2_arg2_zero && union_product!(sh_out, sgy, sgy) # product beta !is_der_cross_zero && union_product!(sh_out, sgx, sgy) # cross product 1 !is_der_cross_zero && union_product!(sh_out, sgy, sgx) # cross product 2 - return sg_out, sh_out # return sets + return P(sg_out, sh_out) # return pattern end function overload_hessian_2_to_1(M, op) diff --git a/src/overloads/ifelse_global.jl b/src/overloads/ifelse_global.jl index f9ad5836..dbf49add 100644 --- a/src/overloads/ifelse_global.jl +++ b/src/overloads/ifelse_global.jl @@ -9,16 +9,16 @@ end ## output union on scalar outputs - function output_union(tx::T, ty::T) where {T<:ConnectivityTracer} - return T(union(inputs(tx), inputs(ty))) + function output_union(tx::T, ty::T) where {T<:AbstractTracer} + return T(output_union(pattern(tx), pattern(ty))) # return tracer end - function output_union(tx::T, ty::T) where {T<:GradientTracer} - return T(union(gradient(tx), gradient(ty))) + function output_union(px::P, py::P) where {P<:IndexSetVector} + return P(union(set(px), set(py))) # return pattern end - function output_union(tx::T, ty::T) where {T<:HessianTracer} - g_out = union(gradient(tx), gradient(ty)) - h_out = union(hessian(tx), hessian(ty)) - return T(g_out, h_out) + function output_union(px::P, py::P) where {P<:IndexSetHessian} + g_out = union(gradient(px), gradient(py)) + h_out = union(hessian(px), hessian(py)) + return P(g_out, h_out) # return pattern end output_union(tx::AbstractTracer, y) = tx diff --git a/src/patterns.jl b/src/patterns.jl index 67e94b3c..4c5ff378 100644 --- a/src/patterns.jl +++ b/src/patterns.jl @@ -20,8 +20,8 @@ AbstractPattern Constructor for an empty pattern of type `P` representing a new number (usually an empty pattern). """ myempty(::P) where {P<:AbstractPattern} = myempty(P) -myempty(::T) where {P<:AbstractPattern,T<:AbstractTracer{P}} = T(myempty(P), true) -myempty(::Type{T}) where {P<:AbstractPattern,T<:AbstractTracer{P}} = T(myempty(P), true) +myempty(::T) where {P,T<:AbstractTracer{P}} = T(myempty(P), true) +myempty(::Type{T}) where {P,T<:AbstractTracer{P}} = T(myempty(P), true) """ seed(P, i) @@ -90,6 +90,8 @@ struct IndexSetVector{I<:Integer,S<:AbstractSet{I}} <: AbstractVectorPattern vector::S end +set(v::IndexSetVector) = v.vector + Base.show(io::IO, s::IndexSetVector) = Base.show(io, s.vector) function myempty(::Type{IndexSetVector{I,S}}) where {I,S} diff --git a/src/tracers.jl b/src/tracers.jl index 66fae3b6..daef5118 100644 --- a/src/tracers.jl +++ b/src/tracers.jl @@ -31,8 +31,9 @@ ConnectivityTracer{P}(::Real) where {P} = myempty(ConnectivityTracer{P}) ConnectivityTracer{P}(t::ConnectivityTracer{P}) where {P} = t ConnectivityTracer(t::ConnectivityTracer) = t -inputs(t::ConnectivityTracer) = inputs(t.pattern) isemptytracer(t::ConnectivityTracer) = t.isempty +pattern(t::ConnectivityTracer) = t.pattern +inputs(t::ConnectivityTracer) = inputs(pattern(t)) function Base.show(io::IO, t::ConnectivityTracer) print(io, typeof(t)) @@ -74,8 +75,9 @@ GradientTracer{P}(::Real) where {P} = myempty(GradientTracer{P}) GradientTracer{P}(t::GradientTracer{P}) where {P} = t GradientTracer(t::GradientTracer) = t -gradient(t::GradientTracer) = gradient(t.pattern) isemptytracer(t::GradientTracer) = t.isempty +pattern(t::GradientTracer) = t.pattern +gradient(t::GradientTracer) = gradient(pattern(t)) function Base.show(io::IO, t::GradientTracer) print(io, typeof(t)) @@ -117,9 +119,10 @@ HessianTracer{P}(::Real) where {P} = myempty(HessianTracer{P}) HessianTracer{P}(t::HessianTracer{P}) where {P} = t HessianTracer(t::HessianTracer) = t -gradient(t::HessianTracer) = gradient(t.pattern) -hessian(t::HessianTracer) = hessian(t.pattern) isemptytracer(t::HessianTracer) = t.isempty +pattern(t::HessianTracer) = t.pattern +gradient(t::HessianTracer) = gradient(pattern(t)) +hessian(t::HessianTracer) = hessian(pattern(t)) function Base.show(io::IO, t::HessianTracer) print(io, typeof(t)) From c7830674b6ab869a9926f31002ebf22312d07e2e Mon Sep 17 00:00:00 2001 From: adrhill Date: Wed, 26 Jun 2024 15:21:29 +0200 Subject: [PATCH 06/10] Verbose tests --- test/runtests.jl | 3 +++ 1 file changed, 3 insertions(+) diff --git a/test/runtests.jl b/test/runtests.jl index 89afe3b4..f9e70e64 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -31,11 +31,13 @@ GROUP = get(ENV, "JULIA_SCT_TEST_GROUP", "Core") @info "Testing formalities..." if VERSION >= v"1.10" @testset "Code formatting" begin + @info "...with JuliaFormatter.jl" @test JuliaFormatter.format( SparseConnectivityTracer; verbose=false, overwrite=false ) end @testset "Aqua tests" begin + @info "...with Aqua.jl" Aqua.test_all( SparseConnectivityTracer; ambiguities=false, @@ -45,6 +47,7 @@ GROUP = get(ENV, "JULIA_SCT_TEST_GROUP", "Core") ) end @testset "JET tests" begin + @info "...with JET.jl" JET.test_package(SparseConnectivityTracer; target_defined_modules=true) end end From 25533094b9cfc50fbbc8fbd54552ab3b0f8f609a Mon Sep 17 00:00:00 2001 From: adrhill Date: Wed, 26 Jun 2024 15:25:35 +0200 Subject: [PATCH 07/10] Rename for Guillaume --- src/interface.jl | 6 ++--- src/overloads/connectivity_tracer.jl | 2 +- src/overloads/gradient_tracer.jl | 14 +++++----- src/overloads/hessian_tracer.jl | 4 +-- src/overloads/ifelse_global.jl | 4 +-- src/patterns.jl | 38 ++++++++++++++-------------- test/test_arrays.jl | 2 +- test/tracers_definitions.jl | 18 ++++++------- 8 files changed, 45 insertions(+), 43 deletions(-) diff --git a/src/interface.jl b/src/interface.jl index 6e290258..be4642f5 100644 --- a/src/interface.jl +++ b/src/interface.jl @@ -1,7 +1,7 @@ -const DEFAULT_CONNECTIVITY_TRACER = ConnectivityTracer{IndexSetVector{Int,BitSet}} -const DEFAULT_GRADIENT_TRACER = GradientTracer{IndexSetVector{Int,BitSet}} +const DEFAULT_CONNECTIVITY_TRACER = ConnectivityTracer{IndexSetVectorPattern{Int,BitSet}} +const DEFAULT_GRADIENT_TRACER = GradientTracer{IndexSetVectorPattern{Int,BitSet}} const DEFAULT_HESSIAN_TRACER = HessianTracer{ - IndexSetHessian{Int,BitSet,Set{Tuple{Int,Int}}} + IndexSetHessianPattern{Int,BitSet,Set{Tuple{Int,Int}}} } #==================# diff --git a/src/overloads/connectivity_tracer.jl b/src/overloads/connectivity_tracer.jl index b1dc5d25..0f45a58d 100644 --- a/src/overloads/connectivity_tracer.jl +++ b/src/overloads/connectivity_tracer.jl @@ -57,7 +57,7 @@ end function connectivity_tracer_2_to_1_inner( px::P, py::P, is_infl_arg1_zero::Bool, is_infl_arg2_zero::Bool -) where {P<:IndexSetVector} +) where {P<:IndexSetVectorPattern} if is_infl_arg1_zero && is_infl_arg2_zero return myempty(P) elseif !is_infl_arg1_zero && is_infl_arg2_zero diff --git a/src/overloads/gradient_tracer.jl b/src/overloads/gradient_tracer.jl index a01f64f7..1a5a7bdd 100644 --- a/src/overloads/gradient_tracer.jl +++ b/src/overloads/gradient_tracer.jl @@ -10,12 +10,14 @@ end end -function gradient_tracer_1_to_1_inner(p::P, is_der1_zero::Bool) where {P<:IndexSetVector} +function gradient_tracer_1_to_1_inner( + p::P, is_der1_zero::Bool +) where {P<:IndexSetVectorPattern} return P(gradient_tracer_1_to_1_inner(set(p), is_der1_zero)) # return pattern end -# This is only required because it is called by HessianTracer with IndexSetHessian -# Otherwise, we would just have the method on IndexSetVector above. +# This is only required because it is called by HessianTracer with IndexSetHessianPattern +# Otherwise, we would just have the method on IndexSetVectorPattern above. function gradient_tracer_1_to_1_inner( s::S, is_der1_zero::Bool ) where {S<:AbstractSet{<:Integer}} @@ -73,14 +75,14 @@ end function gradient_tracer_2_to_1_inner( px::P, py::P, is_der1_arg1_zero::Bool, is_der1_arg2_zero::Bool -) where {P<:IndexSetVector} +) where {P<:IndexSetVectorPattern} return P( gradient_tracer_2_to_1_inner(set(px), set(py), is_der1_arg1_zero, is_der1_arg2_zero) ) # return pattern end -# This is only required because it is called by HessianTracer with IndexSetHessian -# Otherwise, we would just have the method on IndexSetVector above. +# This is only required because it is called by HessianTracer with IndexSetHessianPattern +# Otherwise, we would just have the method on IndexSetVectorPattern above. function gradient_tracer_2_to_1_inner( sx::S, sy::S, is_der1_arg1_zero::Bool, is_der1_arg2_zero::Bool ) where {S<:AbstractSet{<:Integer}} diff --git a/src/overloads/hessian_tracer.jl b/src/overloads/hessian_tracer.jl index 8634f6a3..7b845f9d 100644 --- a/src/overloads/hessian_tracer.jl +++ b/src/overloads/hessian_tracer.jl @@ -13,7 +13,7 @@ end function hessian_tracer_1_to_1_inner( p::P, is_der1_zero::Bool, is_der2_zero::Bool -) where {I,SG,SH,P<:IndexSetHessian{I,SG,SH}} +) where {I,SG,SH,P<:IndexSetHessianPattern{I,SG,SH}} sg = gradient(p) sh = hessian(p) sg_out = gradient_tracer_1_to_1_inner(sg, is_der1_zero) @@ -96,7 +96,7 @@ function hessian_tracer_2_to_1_inner( is_der1_arg2_zero::Bool, is_der2_arg2_zero::Bool, is_der_cross_zero::Bool, -) where {I,SG,SH,P<:IndexSetHessian{I,SG,SH}} +) where {I,SG,SH,P<:IndexSetHessianPattern{I,SG,SH}} sgx, shx = gradient(px), hessian(px) sgy, shy = gradient(py), hessian(py) sg_out = gradient_tracer_2_to_1_inner(sgx, sgy, is_der1_arg1_zero, is_der1_arg2_zero) diff --git a/src/overloads/ifelse_global.jl b/src/overloads/ifelse_global.jl index dbf49add..65200b7b 100644 --- a/src/overloads/ifelse_global.jl +++ b/src/overloads/ifelse_global.jl @@ -12,10 +12,10 @@ function output_union(tx::T, ty::T) where {T<:AbstractTracer} return T(output_union(pattern(tx), pattern(ty))) # return tracer end - function output_union(px::P, py::P) where {P<:IndexSetVector} + function output_union(px::P, py::P) where {P<:IndexSetVectorPattern} return P(union(set(px), set(py))) # return pattern end - function output_union(px::P, py::P) where {P<:IndexSetHessian} + function output_union(px::P, py::P) where {P<:IndexSetHessianPattern} g_out = union(gradient(px), gradient(py)) h_out = union(hessian(px), hessian(py)) return P(g_out, h_out) # return pattern diff --git a/src/patterns.jl b/src/patterns.jl index 4c5ff378..9705c9a3 100644 --- a/src/patterns.jl +++ b/src/patterns.jl @@ -7,9 +7,9 @@ Abstract supertype of all sparsity pattern representations. ``` AbstractPattern ├── AbstractVectorPattern: used in GradientTracer, ConnectivityTracer -│ └── IndexSetVector +│ └── IndexSetVectorPattern └── AbstractHessianPattern: used in HessianTracer - └── IndexSetHessian + └── IndexSetHessianPattern ``` """ AbstractPattern @@ -85,25 +85,25 @@ Vector sparsity pattern represented by an `AbstractSet` of indices ``{i}`` of no ## Fields $(TYPEDFIELDS) """ -struct IndexSetVector{I<:Integer,S<:AbstractSet{I}} <: AbstractVectorPattern +struct IndexSetVectorPattern{I<:Integer,S<:AbstractSet{I}} <: AbstractVectorPattern "Set of indices represting non-zero entries ``i`` in a vector." vector::S end -set(v::IndexSetVector) = v.vector +set(v::IndexSetVectorPattern) = v.vector -Base.show(io::IO, s::IndexSetVector) = Base.show(io, s.vector) +Base.show(io::IO, s::IndexSetVectorPattern) = Base.show(io, s.vector) -function myempty(::Type{IndexSetVector{I,S}}) where {I,S} - return IndexSetVector{I,S}(myempty(S)) +function myempty(::Type{IndexSetVectorPattern{I,S}}) where {I,S} + return IndexSetVectorPattern{I,S}(myempty(S)) end -function seed(::Type{IndexSetVector{I,S}}, i) where {I,S} - return IndexSetVector{I,S}(seed(S, i)) +function seed(::Type{IndexSetVectorPattern{I,S}}, i) where {I,S} + return IndexSetVectorPattern{I,S}(seed(S, i)) end # Tracer compatibility -inputs(s::IndexSetVector) = s.vector -gradient(s::IndexSetVector) = s.vector +inputs(s::IndexSetVectorPattern) = s.vector +gradient(s::IndexSetVectorPattern) = s.vector #========================# # AbstractHessianPattern # @@ -127,23 +127,23 @@ For use with [`HessianTracer`](@ref). abstract type AbstractHessianPattern <: AbstractPattern end """ - IndexSetHessian(vector::AbstractVectorPattern, mat::AbstractMatrixPattern) + IndexSetHessianPattern(vector::AbstractVectorPattern, mat::AbstractMatrixPattern) Gradient and Hessian sparsity patterns constructed by combining two AbstractSets. """ -struct IndexSetHessian{I<:Integer,SG<:AbstractSet{I},SH<:AbstractSet{Tuple{I,I}}} <: +struct IndexSetHessianPattern{I<:Integer,SG<:AbstractSet{I},SH<:AbstractSet{Tuple{I,I}}} <: AbstractHessianPattern gradient::SG hessian::SH end -function myempty(::Type{IndexSetHessian{I,SG,SH}}) where {I,SG,SH} - return IndexSetHessian{I,SG,SH}(myempty(SG), myempty(SH)) +function myempty(::Type{IndexSetHessianPattern{I,SG,SH}}) where {I,SG,SH} + return IndexSetHessianPattern{I,SG,SH}(myempty(SG), myempty(SH)) end -function seed(::Type{IndexSetHessian{I,SG,SH}}, index) where {I,SG,SH} - return IndexSetHessian{I,SG,SH}(seed(SG, index), myempty(SH)) +function seed(::Type{IndexSetHessianPattern{I,SG,SH}}, index) where {I,SG,SH} + return IndexSetHessianPattern{I,SG,SH}(seed(SG, index), myempty(SH)) end # Tracer compatibility -gradient(s::IndexSetHessian) = s.gradient -hessian(s::IndexSetHessian) = s.hessian +gradient(s::IndexSetHessianPattern) = s.gradient +hessian(s::IndexSetHessianPattern) = s.hessian diff --git a/test/test_arrays.jl b/test/test_arrays.jl index 636aaa9d..cb92c2f1 100644 --- a/test/test_arrays.jl +++ b/test/test_arrays.jl @@ -18,7 +18,7 @@ TEST_SQUARE_MATRICES = Dict( TEST_MATRICES = merge(TEST_SQUARE_MATRICES, Dict("`Matrix` (3×4)" => rand(3, 4))) S = BitSet -P = IndexSetVector{Int,S} +P = IndexSetVectorPattern{Int,S} TG = GradientTracer{P} # NOTE: we currently test for conservative patterns on array overloads diff --git a/test/tracers_definitions.jl b/test/tracers_definitions.jl index 8b2a84d4..4947dc02 100644 --- a/test/tracers_definitions.jl +++ b/test/tracers_definitions.jl @@ -1,20 +1,20 @@ using SparseConnectivityTracer: AbstractTracer, ConnectivityTracer, GradientTracer, HessianTracer, Dual -using SparseConnectivityTracer: IndexSetVector, IndexSetHessian +using SparseConnectivityTracer: IndexSetVectorPattern, IndexSetHessianPattern using SparseConnectivityTracer: DuplicateVector, RecursiveSet, SortedVector VECTOR_PATTERNS = ( - IndexSetVector{Int,BitSet}, - IndexSetVector{Int,Set{Int}}, - IndexSetVector{Int,DuplicateVector{Int}}, - IndexSetVector{Int,SortedVector{Int}}, + IndexSetVectorPattern{Int,BitSet}, + IndexSetVectorPattern{Int,Set{Int}}, + IndexSetVectorPattern{Int,DuplicateVector{Int}}, + IndexSetVectorPattern{Int,SortedVector{Int}}, ) HESSIAN_PATTERNS = ( - IndexSetHessian{Int,BitSet,Set{Tuple{Int,Int}}}, - IndexSetHessian{Int,Set{Int},Set{Tuple{Int,Int}}}, - IndexSetHessian{Int,DuplicateVector{Int},DuplicateVector{Tuple{Int,Int}}}, - IndexSetHessian{Int,SortedVector{Int},SortedVector{Tuple{Int,Int}}}, + IndexSetHessianPattern{Int,BitSet,Set{Tuple{Int,Int}}}, + IndexSetHessianPattern{Int,Set{Int},Set{Tuple{Int,Int}}}, + IndexSetHessianPattern{Int,DuplicateVector{Int},DuplicateVector{Tuple{Int,Int}}}, + IndexSetHessianPattern{Int,SortedVector{Int},SortedVector{Tuple{Int,Int}}}, # TODO: test on RecursiveSet ) From 225a3506895acb1e82e2738146817bb33435252a Mon Sep 17 00:00:00 2001 From: adrhill Date: Wed, 26 Jun 2024 16:05:53 +0200 Subject: [PATCH 08/10] Fix benchmarks --- benchmark/bench_jogger.jl | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/benchmark/bench_jogger.jl b/benchmark/bench_jogger.jl index 525a384e..fd84198a 100644 --- a/benchmark/bench_jogger.jl +++ b/benchmark/bench_jogger.jl @@ -4,6 +4,7 @@ Pkg.develop(; path=joinpath(@__DIR__, "SparseConnectivityTracerBenchmarks")) using BenchmarkTools using SparseConnectivityTracer using SparseConnectivityTracer: GradientTracer, HessianTracer +using SparseConnectivityTracer: IndexSetVectorPattern, IndexSetHessianPattern using SparseConnectivityTracer: DuplicateVector, SortedVector, RecursiveSet SET_TYPES = (BitSet, Set{Int}, DuplicateVector{Int}, RecursiveSet{Int}, SortedVector{Int}) @@ -19,8 +20,11 @@ suite["OptimizationProblems"] = optbench([:britgas]) for S1 in SET_TYPES S2 = Set{Tuple{Int,Int}} - G = GradientTracer{S1} - H = HessianTracer{S1,S2} + PG = IndexSetVectorPattern{Int,S1} + PH = IndexSetHessianPattern{Int,S1,S2} + + G = GradientTracer{PG} + H = HessianTracer{PH} suite["Jacobian"]["Global"][nameof(S1)] = jacbench(TracerSparsityDetector(G, H)) suite["Jacobian"]["Local"][nameof(S1)] = jacbench(TracerLocalSparsityDetector(G, H)) From ec8a9c36346ec9a3988e694467fe7991144602ae Mon Sep 17 00:00:00 2001 From: adrhill Date: Wed, 26 Jun 2024 17:47:05 +0200 Subject: [PATCH 09/10] Spell stuff out for JET so it stops complaining --- src/SparseConnectivityTracer.jl | 3 --- src/patterns.jl | 20 +------------------ src/tracers.jl | 35 ++++++++++++++++++++++++++++++--- 3 files changed, 33 insertions(+), 25 deletions(-) diff --git a/src/SparseConnectivityTracer.jl b/src/SparseConnectivityTracer.jl index 0cff835d..a2791a79 100644 --- a/src/SparseConnectivityTracer.jl +++ b/src/SparseConnectivityTracer.jl @@ -19,9 +19,6 @@ include("settypes/duplicatevector.jl") include("settypes/recursiveset.jl") include("settypes/sortedvector.jl") -abstract type AbstractPattern end -abstract type AbstractTracer{P<:AbstractPattern} <: Real end - include("patterns.jl") include("tracers.jl") include("exceptions.jl") diff --git a/src/patterns.jl b/src/patterns.jl index 9705c9a3..01116566 100644 --- a/src/patterns.jl +++ b/src/patterns.jl @@ -12,25 +12,7 @@ AbstractPattern └── IndexSetHessianPattern ``` """ -AbstractPattern - -""" - myempty(P) - -Constructor for an empty pattern of type `P` representing a new number (usually an empty pattern). -""" -myempty(::P) where {P<:AbstractPattern} = myempty(P) -myempty(::T) where {P,T<:AbstractTracer{P}} = T(myempty(P), true) -myempty(::Type{T}) where {P,T<:AbstractTracer{P}} = T(myempty(P), true) - -""" -seed(P, i) - -Constructor for a pattern of type `P` that only contains the given index `i`. -""" -seed(::P, i) where {P<:AbstractPattern} = seed(P, i) -seed(::T, i) where {P<:AbstractPattern,T<:AbstractTracer{P}} = T(seed(P, i)) -seed(::Type{T}, i) where {P<:AbstractPattern,T<:AbstractTracer{P}} = T(seed(P, i)) +abstract type AbstractPattern end #==========================# # Utilities on AbstractSet # diff --git a/src/tracers.jl b/src/tracers.jl index daef5118..f2d2a1c2 100644 --- a/src/tracers.jl +++ b/src/tracers.jl @@ -1,3 +1,5 @@ +abstract type AbstractTracer{P<:AbstractPattern} <: Real end + #====================# # ConnectivityTracer # #====================# @@ -182,14 +184,41 @@ end # Utilities # #===========# +""" + myempty(T) + myempty(tracer) + myempty(pattern) + + +Constructor for an empty tracer or pattern of type `T` representing a new number (usually an empty pattern). +""" +myempty(::T) where {T<:AbstractTracer} = myempty(T) + +# myempty(::Type{T}) where {P,T<:AbstractTracer{P}} = T(myempty(P), true) # JET complains about this +myempty(::Type{T}) where {P,T<:ConnectivityTracer{P}} = T(myempty(P), true) +myempty(::Type{T}) where {P,T<:GradientTracer{P}} = T(myempty(P), true) +myempty(::Type{T}) where {P,T<:HessianTracer{P}} = T(myempty(P), true) + +""" + seed(T, i) + seed(tracer, i) + seed(pattern, i) + +Constructor for a tracer or pattern of type `T` that only contains the given index `i`. +""" +seed(::T, i) where {T<:AbstractTracer} = seed(T, i) + +# seed(::Type{T}, i) where {P,T<:AbstractTracer{P}} = T(seed(P, i)) # JET complains about this +seed(::Type{T}, i) where {P,T<:ConnectivityTracer{P}} = T(seed(P, i)) +seed(::Type{T}, i) where {P,T<:GradientTracer{P}} = T(seed(P, i)) +seed(::Type{T}, i) where {P,T<:HessianTracer{P}} = T(seed(P, i)) + """ create_tracer(T, index) where {T<:AbstractTracer} Convenience constructor for [`ConnectivityTracer`](@ref), [`GradientTracer`](@ref) and [`HessianTracer`](@ref) from input indices. """ -function create_tracer( - ::Type{T}, ::Real, index::Integer -) where {P<:AbstractPattern,T<:AbstractTracer{P}} +function create_tracer(::Type{T}, ::Real, index::Integer) where {P,T<:AbstractTracer{P}} return T(seed(P, index)) end From dbf60710262349ca5beb006d266775909efcf7da Mon Sep 17 00:00:00 2001 From: adrhill Date: Thu, 27 Jun 2024 16:56:25 +0200 Subject: [PATCH 10/10] Rename to `IndexSetGradientPattern` --- benchmark/bench_jogger.jl | 4 +- src/interface.jl | 4 +- src/overloads/connectivity_tracer.jl | 2 +- src/overloads/gradient_tracer.jl | 8 ++-- src/overloads/ifelse_global.jl | 2 +- src/patterns.jl | 56 ++++++++++++++++++---------- src/tracers.jl | 19 +--------- test/test_arrays.jl | 2 +- test/tracers_definitions.jl | 10 ++--- 9 files changed, 55 insertions(+), 52 deletions(-) diff --git a/benchmark/bench_jogger.jl b/benchmark/bench_jogger.jl index fd84198a..25e153ca 100644 --- a/benchmark/bench_jogger.jl +++ b/benchmark/bench_jogger.jl @@ -4,7 +4,7 @@ Pkg.develop(; path=joinpath(@__DIR__, "SparseConnectivityTracerBenchmarks")) using BenchmarkTools using SparseConnectivityTracer using SparseConnectivityTracer: GradientTracer, HessianTracer -using SparseConnectivityTracer: IndexSetVectorPattern, IndexSetHessianPattern +using SparseConnectivityTracer: IndexSetGradientPattern, IndexSetHessianPattern using SparseConnectivityTracer: DuplicateVector, SortedVector, RecursiveSet SET_TYPES = (BitSet, Set{Int}, DuplicateVector{Int}, RecursiveSet{Int}, SortedVector{Int}) @@ -20,7 +20,7 @@ suite["OptimizationProblems"] = optbench([:britgas]) for S1 in SET_TYPES S2 = Set{Tuple{Int,Int}} - PG = IndexSetVectorPattern{Int,S1} + PG = IndexSetGradientPattern{Int,S1} PH = IndexSetHessianPattern{Int,S1,S2} G = GradientTracer{PG} diff --git a/src/interface.jl b/src/interface.jl index be4642f5..d7e80138 100644 --- a/src/interface.jl +++ b/src/interface.jl @@ -1,5 +1,5 @@ -const DEFAULT_CONNECTIVITY_TRACER = ConnectivityTracer{IndexSetVectorPattern{Int,BitSet}} -const DEFAULT_GRADIENT_TRACER = GradientTracer{IndexSetVectorPattern{Int,BitSet}} +const DEFAULT_CONNECTIVITY_TRACER = ConnectivityTracer{IndexSetGradientPattern{Int,BitSet}} +const DEFAULT_GRADIENT_TRACER = GradientTracer{IndexSetGradientPattern{Int,BitSet}} const DEFAULT_HESSIAN_TRACER = HessianTracer{ IndexSetHessianPattern{Int,BitSet,Set{Tuple{Int,Int}}} } diff --git a/src/overloads/connectivity_tracer.jl b/src/overloads/connectivity_tracer.jl index 0f45a58d..6b58073a 100644 --- a/src/overloads/connectivity_tracer.jl +++ b/src/overloads/connectivity_tracer.jl @@ -57,7 +57,7 @@ end function connectivity_tracer_2_to_1_inner( px::P, py::P, is_infl_arg1_zero::Bool, is_infl_arg2_zero::Bool -) where {P<:IndexSetVectorPattern} +) where {P<:IndexSetGradientPattern} if is_infl_arg1_zero && is_infl_arg2_zero return myempty(P) elseif !is_infl_arg1_zero && is_infl_arg2_zero diff --git a/src/overloads/gradient_tracer.jl b/src/overloads/gradient_tracer.jl index 1a5a7bdd..3a5ad831 100644 --- a/src/overloads/gradient_tracer.jl +++ b/src/overloads/gradient_tracer.jl @@ -12,12 +12,12 @@ end function gradient_tracer_1_to_1_inner( p::P, is_der1_zero::Bool -) where {P<:IndexSetVectorPattern} +) where {P<:IndexSetGradientPattern} return P(gradient_tracer_1_to_1_inner(set(p), is_der1_zero)) # return pattern end # This is only required because it is called by HessianTracer with IndexSetHessianPattern -# Otherwise, we would just have the method on IndexSetVectorPattern above. +# Otherwise, we would just have the method on IndexSetGradientPattern above. function gradient_tracer_1_to_1_inner( s::S, is_der1_zero::Bool ) where {S<:AbstractSet{<:Integer}} @@ -75,14 +75,14 @@ end function gradient_tracer_2_to_1_inner( px::P, py::P, is_der1_arg1_zero::Bool, is_der1_arg2_zero::Bool -) where {P<:IndexSetVectorPattern} +) where {P<:IndexSetGradientPattern} return P( gradient_tracer_2_to_1_inner(set(px), set(py), is_der1_arg1_zero, is_der1_arg2_zero) ) # return pattern end # This is only required because it is called by HessianTracer with IndexSetHessianPattern -# Otherwise, we would just have the method on IndexSetVectorPattern above. +# Otherwise, we would just have the method on IndexSetGradientPattern above. function gradient_tracer_2_to_1_inner( sx::S, sy::S, is_der1_arg1_zero::Bool, is_der1_arg2_zero::Bool ) where {S<:AbstractSet{<:Integer}} diff --git a/src/overloads/ifelse_global.jl b/src/overloads/ifelse_global.jl index 65200b7b..2609acc1 100644 --- a/src/overloads/ifelse_global.jl +++ b/src/overloads/ifelse_global.jl @@ -12,7 +12,7 @@ function output_union(tx::T, ty::T) where {T<:AbstractTracer} return T(output_union(pattern(tx), pattern(ty))) # return tracer end - function output_union(px::P, py::P) where {P<:IndexSetVectorPattern} + function output_union(px::P, py::P) where {P<:IndexSetGradientPattern} return P(union(set(px), set(py))) # return pattern end function output_union(px::P, py::P) where {P<:IndexSetHessianPattern} diff --git a/src/patterns.jl b/src/patterns.jl index 01116566..afea743c 100644 --- a/src/patterns.jl +++ b/src/patterns.jl @@ -6,14 +6,33 @@ Abstract supertype of all sparsity pattern representations. ## Type hierarchy ``` AbstractPattern -├── AbstractVectorPattern: used in GradientTracer, ConnectivityTracer -│ └── IndexSetVectorPattern +├── AbstractGradientPattern: used in GradientTracer, ConnectivityTracer +│ └── IndexSetGradientPattern └── AbstractHessianPattern: used in HessianTracer └── IndexSetHessianPattern ``` """ abstract type AbstractPattern end +""" + myempty(T) + myempty(tracer) + myempty(pattern) + + +Constructor for an empty tracer or pattern of type `T` representing a new number (usually an empty pattern). +""" +myempty + +""" + seed(T, i) + seed(tracer, i) + seed(pattern, i) + +Constructor for a tracer or pattern of type `T` that only contains the given index `i`. +""" +seed + #==========================# # Utilities on AbstractSet # #==========================# @@ -37,27 +56,26 @@ function union_product!( end #=======================# -# AbstractVectorPattern # +# AbstractGradientPattern # #=======================# -# For use with ConnectivityTracer and GradientTracer. +# For use with GradientTracer. """ - AbstractVectorPattern <: AbstractPattern + AbstractGradientPattern <: AbstractPattern Abstract supertype of sparsity patterns representing a vector. -For use with [`ConnectivityTracer`](@ref) and [`GradientTracer`](@ref). +For use with [`GradientTracer`](@ref). ## Expected interface * `myempty(::Type{MyPattern})`: return a pattern representing a new number (usually an empty pattern) * `seed(::Type{MyPattern}, i::Integer)`: return an pattern that only contains the given index `i` -* `inputs(p::MyPattern)`: return non-zero indices `i` for use with `ConnectivityTracer` * `gradient(p::MyPattern)`: return non-zero indices `i` for use with `GradientTracer` Note that besides their names, the last two functions are usually identical. """ -abstract type AbstractVectorPattern <: AbstractPattern end +abstract type AbstractGradientPattern <: AbstractPattern end """ $(TYPEDEF) @@ -67,25 +85,25 @@ Vector sparsity pattern represented by an `AbstractSet` of indices ``{i}`` of no ## Fields $(TYPEDFIELDS) """ -struct IndexSetVectorPattern{I<:Integer,S<:AbstractSet{I}} <: AbstractVectorPattern +struct IndexSetGradientPattern{I<:Integer,S<:AbstractSet{I}} <: AbstractGradientPattern "Set of indices represting non-zero entries ``i`` in a vector." - vector::S + gradient::S end -set(v::IndexSetVectorPattern) = v.vector +set(v::IndexSetGradientPattern) = v.gradient -Base.show(io::IO, s::IndexSetVectorPattern) = Base.show(io, s.vector) +Base.show(io::IO, p::IndexSetGradientPattern) = Base.show(io, set(p)) -function myempty(::Type{IndexSetVectorPattern{I,S}}) where {I,S} - return IndexSetVectorPattern{I,S}(myempty(S)) +function myempty(::Type{IndexSetGradientPattern{I,S}}) where {I,S} + return IndexSetGradientPattern{I,S}(myempty(S)) end -function seed(::Type{IndexSetVectorPattern{I,S}}, i) where {I,S} - return IndexSetVectorPattern{I,S}(seed(S, i)) +function seed(::Type{IndexSetGradientPattern{I,S}}, i) where {I,S} + return IndexSetGradientPattern{I,S}(seed(S, i)) end # Tracer compatibility -inputs(s::IndexSetVectorPattern) = s.vector -gradient(s::IndexSetVectorPattern) = s.vector +inputs(s::IndexSetGradientPattern) = s.gradient +gradient(s::IndexSetGradientPattern) = s.gradient #========================# # AbstractHessianPattern # @@ -109,7 +127,7 @@ For use with [`HessianTracer`](@ref). abstract type AbstractHessianPattern <: AbstractPattern end """ - IndexSetHessianPattern(vector::AbstractVectorPattern, mat::AbstractMatrixPattern) + IndexSetHessianPattern(vector::AbstractGradientPattern, mat::AbstractMatrixPattern) Gradient and Hessian sparsity patterns constructed by combining two AbstractSets. """ diff --git a/src/tracers.jl b/src/tracers.jl index f2d2a1c2..94345b1e 100644 --- a/src/tracers.jl +++ b/src/tracers.jl @@ -14,7 +14,7 @@ For a higher-level interface, refer to [`connectivity_pattern`](@ref). ## Fields $(TYPEDFIELDS) """ -struct ConnectivityTracer{P<:AbstractVectorPattern} <: AbstractTracer{P} +struct ConnectivityTracer{P<:AbstractGradientPattern} <: AbstractTracer{P} "Sparse representation of connected inputs." pattern::P "Indicator whether pattern in tracer contains only zeros." @@ -62,7 +62,7 @@ For a higher-level interface, refer to [`jacobian_pattern`](@ref). ## Fields $(TYPEDFIELDS) """ -struct GradientTracer{P<:AbstractVectorPattern} <: AbstractTracer{P} +struct GradientTracer{P<:AbstractGradientPattern} <: AbstractTracer{P} "Sparse representation of non-zero entries in the gradient." pattern::P "Indicator whether gradient in tracer contains only zeros." @@ -184,14 +184,6 @@ end # Utilities # #===========# -""" - myempty(T) - myempty(tracer) - myempty(pattern) - - -Constructor for an empty tracer or pattern of type `T` representing a new number (usually an empty pattern). -""" myempty(::T) where {T<:AbstractTracer} = myempty(T) # myempty(::Type{T}) where {P,T<:AbstractTracer{P}} = T(myempty(P), true) # JET complains about this @@ -199,13 +191,6 @@ myempty(::Type{T}) where {P,T<:ConnectivityTracer{P}} = T(myempty(P), true) myempty(::Type{T}) where {P,T<:GradientTracer{P}} = T(myempty(P), true) myempty(::Type{T}) where {P,T<:HessianTracer{P}} = T(myempty(P), true) -""" - seed(T, i) - seed(tracer, i) - seed(pattern, i) - -Constructor for a tracer or pattern of type `T` that only contains the given index `i`. -""" seed(::T, i) where {T<:AbstractTracer} = seed(T, i) # seed(::Type{T}, i) where {P,T<:AbstractTracer{P}} = T(seed(P, i)) # JET complains about this diff --git a/test/test_arrays.jl b/test/test_arrays.jl index cb92c2f1..336a6326 100644 --- a/test/test_arrays.jl +++ b/test/test_arrays.jl @@ -18,7 +18,7 @@ TEST_SQUARE_MATRICES = Dict( TEST_MATRICES = merge(TEST_SQUARE_MATRICES, Dict("`Matrix` (3×4)" => rand(3, 4))) S = BitSet -P = IndexSetVectorPattern{Int,S} +P = IndexSetGradientPattern{Int,S} TG = GradientTracer{P} # NOTE: we currently test for conservative patterns on array overloads diff --git a/test/tracers_definitions.jl b/test/tracers_definitions.jl index 4947dc02..c7a3514f 100644 --- a/test/tracers_definitions.jl +++ b/test/tracers_definitions.jl @@ -1,13 +1,13 @@ using SparseConnectivityTracer: AbstractTracer, ConnectivityTracer, GradientTracer, HessianTracer, Dual -using SparseConnectivityTracer: IndexSetVectorPattern, IndexSetHessianPattern +using SparseConnectivityTracer: IndexSetGradientPattern, IndexSetHessianPattern using SparseConnectivityTracer: DuplicateVector, RecursiveSet, SortedVector VECTOR_PATTERNS = ( - IndexSetVectorPattern{Int,BitSet}, - IndexSetVectorPattern{Int,Set{Int}}, - IndexSetVectorPattern{Int,DuplicateVector{Int}}, - IndexSetVectorPattern{Int,SortedVector{Int}}, + IndexSetGradientPattern{Int,BitSet}, + IndexSetGradientPattern{Int,Set{Int}}, + IndexSetGradientPattern{Int,DuplicateVector{Int}}, + IndexSetGradientPattern{Int,SortedVector{Int}}, ) HESSIAN_PATTERNS = (