diff --git a/src/Catlab.jl b/src/Catlab.jl index 4ede053f2..6a57e9955 100644 --- a/src/Catlab.jl +++ b/src/Catlab.jl @@ -2,11 +2,11 @@ module Catlab using Reexport -include("theories/Theories.jl") +include("theories/module.jl") include("ACSetsGATsInterop.jl") include("graphs/Graphs.jl") -include("basic_sets/BasicSets.jl") -include("categorical_algebra/CategoricalAlgebra.jl") +include("basic_sets/module.jl") +include("categorical_algebra/module.jl") include("wiring_diagrams/WiringDiagrams.jl") include("graphics/Graphics.jl") include("adts/ADTs.jl") diff --git a/src/sheaves/FVect.jl b/src/sheaves/FVect.jl index 1d4784d68..454d5d28f 100644 --- a/src/sheaves/FVect.jl +++ b/src/sheaves/FVect.jl @@ -1,16 +1,24 @@ -struct FinVect <: Category{FinSet, Function, SmallCatSize} end +using GATlab + +@struct_hash_equal struct FinVect end + +# The tests do not currently use the category structure of FinVect +@instance ThCategoryExplicitSets{FinSet, Function, AbsSet} [model::FinVect] begin + dom(f::FinSet) = error() + codom(f::FinSet) = error() + id(f::FinSet) = error() + compose(f::Function, g::Function) = error() + ob_set() = SetOb(FinSet) + hom_set() = SetOb(Function) +end """ FVectPullback{T} where T <: Number The contravariant free vector space functor. The returned function f✶ restricts via precomposition. """ -struct FVectPullback <: Functor{FinSetOpT, FinVect} end -dom(::FVectPullback) = FinSetOpT -codom(::FVectPullback) = FinVect -do_ob_map(::FVectPullback, n::FinSet) = n -do_hom_map(::FVectPullback, f::FinFunction) = (v->v[f.(dom(f))]) -# as a callable functor this would be: FVectPullback = Functor(identity, f->(v->v[f.(dom(f))]), OppositeCat(FinSetCat()), FinVect()) +FVectPullback = Functor(identity, f->(v->v[f.(dom(f))]), + op(Category(FinSetC())), Category(FinVect())) # end {FinSetOpT, FinVect} end """ FreeVect{T} where T <: Number @@ -23,11 +31,15 @@ FVectPushforward = Functor(identity, # identity on objects sum(v[j] for j in preimage(f,i)) end), # covariant functor from FinSetCat to FinVect - FinSetCat(), FinVect() + Category(FinSetC()), Category(FinVect()) ) -const FinMat = TypeCat(MatrixDom, Matrix) -const FinMatT = typeof(FinMat) +@instance ThCategoryExplicitSets{Int, AbstractMatrix{T}, AbsSet + } [model::MatC{T}] where T begin + + ob_set() = SetOb(PredicatedSet{Int}(i -> i≥0)) + hom_set() = SetOb(AbstractMatrix{T}) +end # call a matrix on a vector multiplies by it. function (M::SparseArrays.SparseMatrixCSC{Int64, Int64})(x::AbstractVector) @@ -35,33 +47,42 @@ function (M::SparseArrays.SparseMatrixCSC{Int64, Int64})(x::AbstractVector) end function pullback_matrix(f::FinFunction) - n = length(dom(f)) - sparse(1:n, f.(dom(f)), ones(Int,n), dom(f).n, codom(f).n) + n = length(dom(f)) + sparse(1:n, f.(dom(f)), ones(Int,n), length(dom(f)), length(codom(f))) end function pushforward_matrix(f::FinFunction) pullback_matrix(f)' end -struct FMatPullback <: Functor{FinSetOpT, FinMatT} end -dom(::FMatPullback) = FinSetOpT -codom(::FMatPullback) = FinMat -do_ob_map(::FMatPullback, n::FinSet) = MatrixDom{AbstractMatrix}(n.n) -do_hom_map(::FMatPullback, f::FinFunction) = pullback_matrix(f) +FMatPullback = Functor(n -> length(n), f->pullback_matrix(f), + Category(SkelFinSet()), Category(MatC{Number}())) + FMatPushforward = Functor(n->MatrixDom(n.n), pushforward_matrix, - FinSetCat(), FinVect() + Category(FinSetC()), Category(FinVect()) ) -""" extend(X::Sheaf{T, FVectPullback}, cover::ColimCover, sections::Vector{Vector{R}}; check=true, debug=false) where {T<:DiagramTopology, R} +extend(X::Sheaf, cover, sections; kw...) = if functor(X) == FMatPullback + extend_mat(X,cover,sections; kw...) +elseif functor(X) == FVectPullback + extend_vect(X,cover,sections; kw...) +else + error("Cannot extend $X") +end + +""" extend(X::Sheaf{T}, cover::ColimCover, sections::Vector{Vector{R}}; check=true, debug=false) where {T<:DiagramTopology, R} This method implements the extension operation for the diagram topology on FinSet for the Free Vector Space functor. The implementation does copies the value of the ith section into the jth spot as indicated by the legs of the cocone. """ -function extend(X::Sheaf{T, FVectPullback}, cover::ColimCover, sections::Vector{Vector{R}}; check=true, debug=false) where {T<:DiagramTopology, R} - length(sections) == length(legs(cover)) || throw(ArgumentError("There are $(length(sections)) but only $(length(legs(cover))) legs in the cover")) - v = zeros(R, apex(cover)) +function extend_vect(X::Sheaf{T}, cover::ColimCover, + sections::Vector{Vector{R}}; check=true, debug=false + ) where {T<:DiagramTopology, R} + length(sections) == length(legs(cover)) || throw(ArgumentError( + "There are $(length(sections)) but only $(length(legs(cover))) legs in the cover")) + v = zeros(R, length(apex(cover))) if check match_errors = diagnose_match(X, cover, sections; debug=debug) length(match_errors) == 0 || throw(MatchingError(match_errors)) @@ -77,14 +98,18 @@ function extend(X::Sheaf{T, FVectPullback}, cover::ColimCover, sections::Vector{ return v end -function extend(X::Sheaf{T, FMatPullback}, cover::ColimCover, sections::Vector{Vector{R}};check=true, debug=false) where {T<:DiagramTopology, R} - length(sections) == length(legs(cover)) || throw(ArgumentError("There are $(length(sections)) but only $(length(legs(cover))) legs in the cover")) - v = zeros(R, apex(cover)) + +function extend_mat(X::Sheaf{T}, cover::ColimCover, + sections::Vector{Vector{R}};check=true, debug=false + ) where {T<:DiagramTopology, R} + length(sections) == length(legs(cover)) || throw(ArgumentError( + "There are $(length(sections)) but only $(length(legs(cover))) legs in the cover")) + v = zeros(R, length(apex(cover))) if check match_errors = diagnose_match(X, cover, sections; debug=debug) length(match_errors) == 0 || throw(MatchingError(match_errors)) end - f = copair(legs(cover)) - M = do_hom_map(functor(X), f) + f = copair[TypedCatWithCoproducts(SkelFinSet())](legs(cover)) + M = hom_map(functor(X), f) return Float64.(M) \ direct_sum(sections) end diff --git a/src/sheaves/Sheaves.jl b/src/sheaves/Sheaves.jl index 7981d6a72..f854d3013 100644 --- a/src/sheaves/Sheaves.jl +++ b/src/sheaves/Sheaves.jl @@ -1,15 +1,13 @@ module Sheaves + +using StructEquality using LinearAlgebra using SparseArrays -using ...CategoricalAlgebra -using ...CategoricalAlgebra.Categories -using ...CategoricalAlgebra.FinSets -using ...CategoricalAlgebra.Matrices +using ...BasicSets, ...CategoricalAlgebra +using ...CategoricalAlgebra.Misc.Matrices using ...Theories -import ..CategoricalAlgebra.Categories: CatSize import ...Theories: dom, codom, id, ob, hom import ...CategoricalAlgebra: legs, apex -import ...CategoricalAlgebra.Categories: do_ob_map, do_hom_map export AbstractSheaf, AbstractFunctor, AbstractCover, AbstractCoverage, FinSetCat, FinVect, FinSetOp, FinSetOpT, @@ -18,8 +16,6 @@ export AbstractSheaf, AbstractFunctor, AbstractCover, AbstractCoverage, ColimCover, DiagramTopology, is_coverage, Sheaf, diagnose_match, extend, restrict, MatchingError, MatchingFailure - -abstract type SmallCatSize <: CatSize end Base.zeros(T, n::FinSet) = zeros(T, length(n)) direct_sum(vs) = reduce(vcat, vs) @@ -28,12 +24,7 @@ abstract type AbstractFunctor end abstract type AbstractCover end abstract type AbstractCoverage end -struct FinSetCat <: Category{FinSet, FinFunction, SmallCatSize} end - -const FinSetOp = op(FinSetCat()) -const FinSetOpT = typeof(FinSetOp) - -struct Sieve{T} <: AbstractCover +@struct_hash_equal struct Sieve{T} <: AbstractCover basis::T end @@ -48,17 +39,17 @@ end legs(s::Sieve) = legs(s.basis) apex(s::Sieve) = apex(s.basis) -struct ColimCover <: AbstractCover - colimit +@struct_hash_equal struct ColimCover <: AbstractCover + colimit::AbsColimit end -ColimCover(d::FreeDiagram) = ColimCover(colimit(d)) +ColimCover(d::FreeDiagram) = ColimCover(colimit[SkelFinSet()](getvalue(d))) legs(s::ColimCover) = legs(s.colimit) apex(s::ColimCover) = apex(s.colimit) Base.enumerate(s::ColimCover) = enumerate(legs(s)) -struct DiagramTopology <: AbstractCoverage end +@struct_hash_equal struct DiagramTopology <: AbstractCoverage end function is_coverage(top::AbstractCoverage, S::AbstractCover, object) error("To implement a GTopology, you have to be able to check if a Sieve covers an object.") @@ -68,7 +59,7 @@ function is_coverage(::DiagramTopology, S::ColimCover, object) apex(S) == object end -struct Sheaf{T<:AbstractCoverage,F<:Functor} <: AbstractSheaf +@struct_hash_equal struct Sheaf{T<:AbstractCoverage,F<:Functor} <: AbstractSheaf coverage::T functor::F end @@ -78,7 +69,7 @@ functor(s::Sheaf) = s.functor abstract type AbstractSection end -struct Section{S,D,V} <: AbstractSection +@struct_hash_equal struct Section{S,D,V} <: AbstractSection sheaf::S domain::D value::V @@ -96,27 +87,33 @@ end """ restrict(X::AbstractSheaf, s::Data, f::Hom) where {Data, Hom} Restrict a section along a morphism in the sheaf. -This is to apply the sheaf's functor to the morphism f and then apply that function to the data supplied. -We can assume that you can directly call that applied functor on data, because sheaves take C to **Set**. +This is to apply the sheaf's functor to the morphism f and then apply that +function to the data supplied. We can assume that you can directly call that +applied functor on data, because sheaves take C to **Set**. """ function restrict(X::AbstractSheaf, s::Data, f::Hom) where {Data, Hom} - do_hom_map(functor(X), f)(s) + hom_map(functor(X), f)(s) end """ extend(X::AbstractSheaf, cover::AbstractCover, sections::AbstractVector) -Extend a collection of sections to the unique section that restricts to the sections provided. -The `sections` vector needs to be indexed in the same order as `enumerate(cover)`. +Extend a collection of sections to the unique section that restricts to the +sections provided. The `sections` vector needs to be indexed in the same order +as `enumerate(cover)`. """ -function extend(X::AbstractSheaf, cover::AbstractCover, sections::AbstractVector) - error("In order to define a sheaf, you must implement restrict and extend") -end +################################## +# THIS SHOULD BE DONE WITH A GAT # +################################## +# function extend(X::AbstractSheaf, cover::AbstractCover, sections::AbstractVector) +# error("In order to define a sheaf, you must implement restrict and extend") +# end """ MatchingFailure -An type for when sections over a sheaf fail to match, that is when they don't agree on the overlaps implied by a cover. +A type for when sections over a sheaf fail to match, that is when they don't +agree on the overlaps implied by a cover. """ -struct MatchingFailure +@struct_hash_equal struct MatchingFailure sheaf::AbstractSheaf hom1 hom2 @@ -133,7 +130,7 @@ Base.show(io::IO, m::MatchingFailure) = println(io, "$(typeof(m).name.name): Sec An Exception type for when sections over a sheaf fail to match, that is when they don't agree on the overlaps implied by a cover. This stores the list MatchingFailures encountered when walking the cover. """ -struct MatchingError{T} <: Exception where T<:MatchingFailure +@struct_hash_equal struct MatchingError{T} <: Exception where T<:MatchingFailure failures::Vector{T} end @@ -159,11 +156,9 @@ function diagnose_match(X::Sheaf, cover, sections; debug=false) if i >= j continue end - P = pullback(l₁,l₂) + P = pullback[SkelFinSet()](l₁,l₂) if debug println("Computing intersection of opens $i,$j") - @show l₁ - @show l₂ @show apex(P) end v₁ = restrict(X, sections[i], legs(P)[1]) @@ -176,4 +171,4 @@ end include("FVect.jl") -end \ No newline at end of file +end # module diff --git a/test/runtests.jl b/test/runtests.jl index 0bac502df..83b8abe2d 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -1,7 +1,5 @@ using Test -# include("aqua.jl") # can uncomment once PR is more complete - @testset "Theories" begin include("theories/runtests.jl") # TO SAVE TIME end @@ -27,7 +25,7 @@ end end @testset "Programs" begin - include("programs/Programs.jl") + include("programs/runtests.jl") end @testset "Parsers" begin diff --git a/test/sheaves/sheaves.jl b/test/sheaves/sheaves.jl index 6f25d07cd..3c2bc50f3 100644 --- a/test/sheaves/sheaves.jl +++ b/test/sheaves/sheaves.jl @@ -1,37 +1,36 @@ -using Test -using Catlab.CategoricalAlgebra -using Catlab.CategoricalAlgebra.Categories -using Catlab.Sheaves +module TestSheaves + +using Test, Catlab +using Catlab.CategoricalAlgebra.Misc.Matrices -import Catlab.CategoricalAlgebra.Categories: do_ob_map, do_hom_map -using Catlab.CategoricalAlgebra.Matrices: MatrixDom import Catlab.Sheaves: pullback_matrix, FinSetCat -VectSheaf = Sheaf(DiagramTopology(), FVectPullback()) -VectSheafMat = Sheaf(DiagramTopology(), FMatPullback()) +VectSheaf = Sheaf(DiagramTopology(), FVectPullback) +VectSheafMat = Sheaf(DiagramTopology(), FMatPullback) f = FinFunction([1,2], 3) g = FinFunction([1,2], 3) -@test isa(FinSetCat(), Category) -@test isa(FinVect(), Category) -@test do_hom_map(FVectPullback(), FinFunction([1,2,2],4))(1:4) == [1,2,2] +@test implements(FinSetC(), ThCategory) +@test implements(FinVect(), ThCategory) + +@test hom_map(FVectPullback, FinFunction([1,2,2],4))(1:4) == [1,2,2] @test pullback_matrix(FinFunction([1,2,2], 4)) == [1 0 0 0; 0 1 0 0; 0 1 0 0] -@test do_ob_map(FMatPullback(), FinSet(3)) == MatrixDom{AbstractMatrix}(3) -@test do_hom_map(FMatPullback(), FinFunction([1,2,2], 4)) == [1 0 0 0; 0 1 0 0; 0 1 0 0] -S = ColimCover(pushout(f,g)) +@test ob_map(FMatPullback, FinSetInt(3)) == 3 +@test hom_map(FMatPullback, FinFunction([1,2,2], 4)) == [1 0 0 0; 0 1 0 0; 0 1 0 0] +S = ColimCover(pushout[SkelFinSet()](f,g)) extend(VectSheaf, S, [[1.0, 2,3], [1,2.0,6]]) @test_throws MatchingError extend(VectSheaf, S, [[1.0, 2,3], [1,3.0,6]]) # extend(VectSheaf, S, [[1.0, 2,3], [1,3.0,6]]) -D = FreeDiagram(FinSet.([3,2,3]), # list of objects +D = FreeGraph(FinSetInt.([3,2,3]), # list of objects [ # list of (hom, src, tgt) tuples (FinFunction([1,2], 3), 2,1), (FinFunction([1,2], 3), 2,3), - ] -) + ]; cat=SkelFinSet() +) |> FreeDiagram K = ColimCover(D) @@ -51,4 +50,6 @@ section_data_bad = [Float64[1,2,3], @test_throws MatchingError extend(VectSheafMat, K, section_data_bad) # if we disable the checks, VectSheafMat will solve a least squares problem instead of last write wins. -@test extend(VectSheafMat, K, section_data_bad, check=false) != extend(VectSheaf, K, section_data_bad, check=false) \ No newline at end of file +@test extend(VectSheafMat, K, section_data_bad, check=false) != extend(VectSheaf, K, section_data_bad, check=false) + +end # module