From 99f5e0269b8a989ec614c6c7ab9c0ecf1410f747 Mon Sep 17 00:00:00 2001 From: Evan Patterson Date: Mon, 27 Sep 2021 18:31:22 -0700 Subject: [PATCH] BUILD: Upgrade to Catlab v0.13. --- Project.toml | 2 +- src/CombinatorialMaps.jl | 25 ++-- src/DiscreteExteriorCalculus.jl | 199 ++++++++++++++++---------------- src/MeshGraphics.jl | 2 +- src/SimplicialSets.jl | 134 ++++++++++----------- test/SimplicialSets.jl | 2 +- 6 files changed, 184 insertions(+), 180 deletions(-) diff --git a/Project.toml b/Project.toml index c4648570..90fb2aa8 100644 --- a/Project.toml +++ b/Project.toml @@ -17,7 +17,7 @@ SparseArrays = "2f01184e-e22b-5df5-ae63-d93ebab69eaf" StaticArrays = "90137ffa-7385-5640-81b9-e52037218182" [compat] -Catlab = "0.12" +Catlab = "0.13.1" FileIO = "^1" GeometryBasics = "0.3, 0.4" LazyArrays = "0.20, 0.21, 0.22" diff --git a/src/CombinatorialMaps.jl b/src/CombinatorialMaps.jl index 6074f884..68654850 100644 --- a/src/CombinatorialMaps.jl +++ b/src/CombinatorialMaps.jl @@ -21,30 +21,30 @@ using Catlab.Permutations: cycles """ Vertex permutation of combinatorial map or similar structure. """ -σ(x::AbstractACSet, args...) = subpart(x, args..., :σ) +σ(x::ACSet, args...) = subpart(x, args..., :σ) """ Edge permutation of combinatorial map or similar structure. """ -α(x::AbstractACSet, args...) = subpart(x, args..., :α) +α(x::ACSet, args...) = subpart(x, args..., :α) """ Face permutation of combinatorial map or similar structure. """ -ϕ(x::AbstractACSet, args...) = subpart(x, args..., :ϕ) +ϕ(x::ACSet, args...) = subpart(x, args..., :ϕ) """ Trace vertices of combinatorial map or similar, returning a list of cycles. """ -trace_vertices(x::AbstractACSet) = cycles(σ(x)) +trace_vertices(x::ACSet) = cycles(σ(x)) """ Trace edges of combinatorial map or similar, return a listing of cycles. Usually the cycles will be pairs of half edges but in a hypermap the cycles can be arbitrary. """ -trace_edges(x::AbstractACSet) = cycles(α(x)) +trace_edges(x::ACSet) = cycles(α(x)) """ Trace faces of combinatorial map or similar, returning list of cycles. """ -trace_faces(x::AbstractACSet) = cycles(ϕ(x)) +trace_faces(x::ACSet) = cycles(ϕ(x)) # Rotation graphs ################# @@ -55,8 +55,9 @@ trace_faces(x::AbstractACSet) = cycles(ϕ(x)) compose(σ, vertex) == vertex end -const AbstractRotationGraph = AbstractACSetType(TheoryRotationGraph) -const RotationGraph = CSetType(TheoryRotationGraph, index=[:vertex]) +@abstract_acset_type AbstractRotationGraph <: AbstractHalfEdgeGraph +@acset_type RotationGraph(TheoryRotationGraph, + index=[:vertex]) <: AbstractRotationGraph α(g::AbstractRotationGraph) = inv(g) ϕ(g::AbstractRotationGraph) = sortperm(inv(g)[σ(g)]) # == (σ ⋅ inv)⁻¹ @@ -89,8 +90,8 @@ pair_half_edges!(g::AbstractRotationGraph, h, h′) = compose(α, α) == id(H) end -const AbstractRotationSystem = AbstractACSetType(TheoryRotationSystem) -const RotationSystem = CSetType(TheoryRotationSystem) +@abstract_acset_type AbstractRotationSystem +@acset_type RotationSystem(TheoryRotationSystem) <: AbstractRotationSystem # ϕ == (σ⋅α)⁻¹ == α⁻¹ ⋅ σ⁻¹ ϕ(sys::AbstractRotationSystem) = sortperm(α(sys)[σ(sys)]) @@ -119,8 +120,8 @@ end compose(α, α) == id(H) end -const AbstractCombinatorialMap = AbstractACSetType(TheoryCombinatorialMap) -const CombinatorialMap = CSetType(TheoryCombinatorialMap) +@abstract_acset_type AbstractCombinatorialMap +@acset_type CombinatorialMap(TheoryCombinatorialMap) <: AbstractCombinatorialMap # TODO: What kind of interface should we have for maps and hypermaps? diff --git a/src/DiscreteExteriorCalculus.jl b/src/DiscreteExteriorCalculus.jl index d3fe0545..e52c5d79 100644 --- a/src/DiscreteExteriorCalculus.jl +++ b/src/DiscreteExteriorCalculus.jl @@ -28,6 +28,7 @@ using StaticArrays: @SVector, SVector using Catlab, Catlab.CategoricalAlgebra.CSets using Catlab.CategoricalAlgebra.FinSets: deleteat +using Catlab.Graphs: HasGraph import Catlab.Theories: Δ using ..ArrayUtils, ..SimplicialSets using ..SimplicialSets: DeltaCategory1D, DeltaCategory2D, CayleyMengerDet, @@ -78,28 +79,28 @@ end """ Abstract type for dual complex of a 1D delta set. """ -const AbstractDeltaDualComplex1D = AbstractACSetType(SchemaDualComplex1D) +@abstract_acset_type AbstractDeltaDualComplex1D <: HasGraph """ Dual complex of a one-dimensional delta set. The data structure includes both the primal complex and the dual complex, as well as the mapping between them. """ -const DeltaDualComplex1D = CSetType(SchemaDualComplex1D, - index=[:src,:tgt,:D_∂v0,:D_∂v1]) +@acset_type DeltaDualComplex1D(SchemaDualComplex1D, + index=[:src,:tgt,:D_∂v0,:D_∂v1]) <: AbstractDeltaDualComplex1D """ Dual vertex corresponding to center of primal vertex. """ -vertex_center(s::AbstractACSet, args...) = s[args..., :vertex_center] +vertex_center(s::ACSet, args...) = s[args..., :vertex_center] """ Dual vertex corresponding to center of primal edge. """ -edge_center(s::AbstractACSet, args...) = s[args..., :edge_center] +edge_center(s::ACSet, args...) = s[args..., :edge_center] -subsimplices(::Type{Val{1}}, s::AbstractACSet, e::Int) = +subsimplices(::Type{Val{1}}, s::ACSet, e::Int) = SVector{2}(incident(s, edge_center(s, e), :D_∂v0)) -primal_vertex(::Type{Val{1}}, s::AbstractACSet, e...) = s[e..., :D_∂v1] +primal_vertex(::Type{Val{1}}, s::ACSet, e...) = s[e..., :D_∂v1] elementary_duals(::Type{Val{0}}, s::AbstractDeltaDualComplex1D, v::Int) = incident(s, vertex_center(s,v), :D_∂v1) @@ -110,7 +111,7 @@ elementary_duals(::Type{Val{1}}, s::AbstractDeltaDualComplex1D, e::Int) = This accessor assumes that the simplicial identities for the dual hold. """ -function dual_triangle_vertices(s::AbstractACSet, t...) +function dual_triangle_vertices(s::ACSet, t...) SVector(s[s[t..., :D_∂e1], :D_∂v1], s[s[t..., :D_∂e0], :D_∂v1], s[s[t..., :D_∂e0], :D_∂v0]) @@ -120,15 +121,15 @@ end #------------------------- @present SchemaOrientedDualComplex1D <: SchemaDualComplex1D begin - Orientation::Data + Orientation::AttrType edge_orientation::Attr(E, Orientation) D_edge_orientation::Attr(DualE, Orientation) end """ Oriented dual complex of an oriented 1D delta set. """ -const OrientedDeltaDualComplex1D = ACSetType(SchemaOrientedDualComplex1D, - index=[:src,:tgt,:D_∂v0,:D_∂v1]) +@acset_type OrientedDeltaDualComplex1D(SchemaOrientedDualComplex1D, + index=[:src,:tgt,:D_∂v0,:D_∂v1]) <: AbstractDeltaDualComplex1D dual_boundary_nz(::Type{Val{1}}, s::AbstractDeltaDualComplex1D, x::Int) = # Boundary vertices of dual 1-cell ↔ @@ -159,7 +160,7 @@ If the primal complex is oriented, an orientation is induced on the dual complex. The dual edges are oriented relative to the primal edges they subdivide (Hirani 2003, PhD thesis, Ch. 2, last sentence of Remark 2.5.1). """ -function make_dual_simplices_1d!(s::AbstractACSet) +function make_dual_simplices_1d!(s::ACSet) # Make dual vertices and edges. s[:vertex_center] = vcenters = add_parts!(s, :DualV, nv(s)) s[:edge_center] = ecenters = add_parts!(s, :DualV, ne(s)) @@ -182,7 +183,7 @@ end #------------------------- @present SchemaEmbeddedDualComplex1D <: SchemaOrientedDualComplex1D begin - (Real, Point)::Data + (Real, Point)::AttrType point::Attr(V, Point) length::Attr(E, Real) dual_point::Attr(DualV, Point) @@ -194,12 +195,12 @@ end Although they are redundant information, the lengths of the primal and dual edges are precomputed and stored. """ -const EmbeddedDeltaDualComplex1D = ACSetType(SchemaEmbeddedDualComplex1D, - index=[:src,:tgt,:D_∂v0,:D_∂v1]) +@acset_type EmbeddedDeltaDualComplex1D(SchemaEmbeddedDualComplex1D, + index=[:src,:tgt,:D_∂v0,:D_∂v1]) <: AbstractDeltaDualComplex1D """ Point associated with dual vertex of complex. """ -dual_point(s::AbstractACSet, args...) = s[args..., :dual_point] +dual_point(s::ACSet, args...) = s[args..., :dual_point] struct PrecomputedVol end @@ -208,11 +209,11 @@ volume(::Type{Val{n}}, s::EmbeddedDeltaDualComplex1D, x) where n = dual_volume(::Type{Val{n}}, s::EmbeddedDeltaDualComplex1D, x) where n = dual_volume(Val{n}, s, x, PrecomputedVol()) -volume(::Type{Val{1}}, s::AbstractACSet, e, ::PrecomputedVol) = s[e, :length] -dual_volume(::Type{Val{1}}, s::AbstractACSet, e, ::PrecomputedVol) = +volume(::Type{Val{1}}, s::ACSet, e, ::PrecomputedVol) = s[e, :length] +dual_volume(::Type{Val{1}}, s::ACSet, e, ::PrecomputedVol) = s[e, :dual_length] -dual_volume(::Type{Val{1}}, s::AbstractACSet, e::Int, ::CayleyMengerDet) = +dual_volume(::Type{Val{1}}, s::ACSet, e::Int, ::CayleyMengerDet) = volume(dual_point(s, SVector(s[e,:D_∂v0], s[e,:D_∂v1]))) hodge_diag(::Type{Val{0}}, s::AbstractDeltaDualComplex1D, v::Int) = @@ -231,7 +232,7 @@ function subdivide_duals!(s::EmbeddedDeltaDualComplex1D, args...) precompute_volumes_1d!(s) end -function subdivide_duals_1d!(s::AbstractACSet, alg) +function subdivide_duals_1d!(s::ACSet, alg) for v in vertices(s) s[vertex_center(s,v), :dual_point] = point(s, v) end @@ -241,7 +242,7 @@ function subdivide_duals_1d!(s::AbstractACSet, alg) end end -function precompute_volumes_1d!(s::AbstractACSet) +function precompute_volumes_1d!(s::ACSet) for e in edges(s) s[e, :length] = volume(1,s,e,CayleyMengerDet()) end @@ -275,21 +276,21 @@ end """ Abstract type for dual complex of a 2D delta set. """ -const AbstractDeltaDualComplex2D = AbstractACSetType(SchemaDualComplex2D) +@abstract_acset_type AbstractDeltaDualComplex2D <: HasGraph """ Dual complex of a two-dimensional delta set. """ -const DeltaDualComplex2D = CSetType(SchemaDualComplex2D, - index=[:src, :tgt, :∂e0, :∂e1, :∂e2, :D_∂v0, :D_∂v1, :D_∂e0, :D_∂e1, :D_∂e2]) +@acset_type DeltaDualComplex2D(SchemaDualComplex2D, + index=[:src,:tgt,:∂e0,:∂e1,:∂e2,:D_∂v0,:D_∂v1,:D_∂e0,:D_∂e1,:D_∂e2]) <: AbstractDeltaDualComplex2D """ Dual vertex corresponding to center of primal triangle. """ -triangle_center(s::AbstractACSet, args...) = s[args..., :tri_center] +triangle_center(s::ACSet, args...) = s[args..., :tri_center] -subsimplices(::Type{Val{2}}, s::AbstractACSet, t::Int) = +subsimplices(::Type{Val{2}}, s::ACSet, t::Int) = SVector{6}(incident(s, triangle_center(s,t), @SVector [:D_∂e1, :D_∂v0])) -primal_vertex(::Type{Val{2}}, s::AbstractACSet, t...) = +primal_vertex(::Type{Val{2}}, s::ACSet, t...) = primal_vertex(Val{1}, s, s[t..., :D_∂e2]) elementary_duals(::Type{Val{0}}, s::AbstractDeltaDualComplex2D, v::Int) = @@ -303,7 +304,7 @@ elementary_duals(::Type{Val{2}}, s::AbstractDeltaDualComplex2D, t::Int) = #------------------------- @present SchemaOrientedDualComplex2D <: SchemaDualComplex2D begin - Orientation::Data + Orientation::AttrType edge_orientation::Attr(E, Orientation) tri_orientation::Attr(Tri, Orientation) D_edge_orientation::Attr(DualE, Orientation) @@ -312,8 +313,8 @@ end """ Oriented dual complex of an oriented 2D delta set. """ -const OrientedDeltaDualComplex2D = ACSetType(SchemaOrientedDualComplex2D, - index=[:src, :tgt, :∂e0, :∂e1, :∂e2, :D_∂v0, :D_∂v1, :D_∂e0, :D_∂e1, :D_∂e2]) +@acset_type OrientedDeltaDualComplex2D(SchemaOrientedDualComplex2D, + index=[:src,:tgt,:∂e0,:∂e1,:∂e2,:D_∂v0,:D_∂v1,:D_∂e0,:D_∂e1,:D_∂e2]) <: AbstractDeltaDualComplex2D dual_boundary_nz(::Type{Val{1}}, s::AbstractDeltaDualComplex2D, x::Int) = # Boundary vertices of dual 1-cell ↔ @@ -345,7 +346,7 @@ complex. The elementary dual edges are oriented following (Hirani, 2003, Example 2.5.2) or (Desbrun et al, 2005, Table 1) and the dual triangles are oriented relative to the primal triangles they subdivide. """ -function make_dual_simplices_2d!(s::AbstractACSet) +function make_dual_simplices_2d!(s::ACSet) # Make dual vertices and edges. D_edges01 = make_dual_simplices_1d!(s) s[:tri_center] = tri_centers = add_parts!(s, :DualV, ntriangles(s)) @@ -395,7 +396,7 @@ relative_sign(x::Bool, y::Bool) = (x && y) || (!x && !y) #------------------------- @present SchemaEmbeddedDualComplex2D <: SchemaOrientedDualComplex2D begin - (Real, Point)::Data + (Real, Point)::AttrType point::Attr(V, Point) length::Attr(E, Real) area::Attr(Tri, Real) @@ -409,19 +410,19 @@ end Although they are redundant information, the lengths and areas of the primal/dual edges and triangles are precomputed and stored. """ -const EmbeddedDeltaDualComplex2D = ACSetType(SchemaEmbeddedDualComplex2D, - index=[:src, :tgt, :∂e0, :∂e1, :∂e2, :D_∂v0, :D_∂v1, :D_∂e0, :D_∂e1, :D_∂e2]) +@acset_type EmbeddedDeltaDualComplex2D(SchemaEmbeddedDualComplex2D, + index=[:src,:tgt,:∂e0,:∂e1,:∂e2,:D_∂v0,:D_∂v1,:D_∂e0,:D_∂e1,:D_∂e2]) <: AbstractDeltaDualComplex2D volume(::Type{Val{n}}, s::EmbeddedDeltaDualComplex2D, x) where n = volume(Val{n}, s, x, PrecomputedVol()) dual_volume(::Type{Val{n}}, s::EmbeddedDeltaDualComplex2D, x) where n = dual_volume(Val{n}, s, x, PrecomputedVol()) -volume(::Type{Val{2}}, s::AbstractACSet, t, ::PrecomputedVol) = s[t, :area] -dual_volume(::Type{Val{2}}, s::AbstractACSet, t, ::PrecomputedVol) = +volume(::Type{Val{2}}, s::ACSet, t, ::PrecomputedVol) = s[t, :area] +dual_volume(::Type{Val{2}}, s::ACSet, t, ::PrecomputedVol) = s[t, :dual_area] -function dual_volume(::Type{Val{2}}, s::AbstractACSet, t::Int, ::CayleyMengerDet) +function dual_volume(::Type{Val{2}}, s::ACSet, t::Int, ::CayleyMengerDet) dual_vs = SVector(s[s[t, :D_∂e1], :D_∂v1], s[s[t, :D_∂e2], :D_∂v0], s[s[t, :D_∂e0], :D_∂v0]) @@ -477,7 +478,7 @@ function ♯(s::AbstractDeltaDualComplex2D, α::AbstractVector, ::PPSharp) α♯ end -function ∧(::Type{Tuple{1,1}}, s::AbstractACSet, α, β, x::Int) +function ∧(::Type{Tuple{1,1}}, s::ACSet, α, β, x::Int) # XXX: This calculation of the volume coefficients is awkward due to the # design decision described in `SchemaDualComplex1D`. dual_vs = vertex_center(s, triangle_vertices(s, x)) @@ -501,7 +502,7 @@ function subdivide_duals!(s::EmbeddedDeltaDualComplex2D, args...) precompute_volumes_2d!(s) end -function subdivide_duals_2d!(s::AbstractACSet, alg) +function subdivide_duals_2d!(s::ACSet, alg) subdivide_duals_1d!(s, alg) for t in triangles(s) s[triangle_center(s,t), :dual_point] = geometric_center( @@ -509,7 +510,7 @@ function subdivide_duals_2d!(s::AbstractACSet, alg) end end -function precompute_volumes_2d!(s::AbstractACSet) +function precompute_volumes_2d!(s::ACSet) precompute_volumes_1d!(s) for t in triangles(s) s[t, :area] = volume(2,s,t,CayleyMengerDet()) @@ -571,9 +572,9 @@ this correspondence, a basis for primal ``n``-chains defines the basis for dual ndims(s::AbstractDeltaDualComplex1D) = 1 ndims(s::AbstractDeltaDualComplex2D) = 2 -volume(s::AbstractACSet, x::DualSimplex{n}, args...) where n = +volume(s::ACSet, x::DualSimplex{n}, args...) where n = dual_volume(Val{n}, s, x.data, args...) -@inline dual_volume(n::Int, s::AbstractACSet, args...) = +@inline dual_volume(n::Int, s::ACSet, args...) = dual_volume(Val{n}, s, args...) """ List of dual simplices comprising the subdivision of a primal simplex. @@ -585,16 +586,16 @@ dimension. The returned list is ordered such that subsimplices with the same primal vertex appear consecutively. """ -subsimplices(s::AbstractACSet, x::Simplex{n}) where n = +subsimplices(s::ACSet, x::Simplex{n}) where n = DualSimplex{n}(subsimplices(Val{n}, s, x.data)) -@inline subsimplices(n::Int, s::AbstractACSet, args...) = +@inline subsimplices(n::Int, s::ACSet, args...) = subsimplices(Val{n}, s, args...) """ Primal vertex associated with a dual simplex. """ -primal_vertex(s::AbstractACSet, x::DualSimplex{n}) where n = +primal_vertex(s::ACSet, x::DualSimplex{n}) where n = V(primal_vertex(Val{n}, s, x.data)) -@inline primal_vertex(n::Int, s::AbstractACSet, args...) = +@inline primal_vertex(n::Int, s::ACSet, args...) = primal_vertex(Val{n}, s, args...) """ List of elementary dual simplices corresponding to primal simplex. @@ -612,21 +613,21 @@ In 2D dual complexes, the elementary duals of... - primal edges are dual edges - primal triangles are (single) dual triangles """ -elementary_duals(s::AbstractACSet, x::Simplex{n}) where n = +elementary_duals(s::ACSet, x::Simplex{n}) where n = DualSimplex{ndims(s)-n}(elementary_duals(Val{n}, s, x.data)) -@inline elementary_duals(n::Int, s::AbstractACSet, args...) = +@inline elementary_duals(n::Int, s::ACSet, args...) = elementary_duals(Val{n}, s, args...) """ Boundary of chain of dual cells. Transpose of [`dual_derivative`](@ref). """ -@inline dual_boundary(n::Int, s::AbstractACSet, args...) = +@inline dual_boundary(n::Int, s::ACSet, args...) = dual_boundary(Val{n}, s, args...) -∂(s::AbstractACSet, x::DualChain{n}) where n = +∂(s::ACSet, x::DualChain{n}) where n = DualChain{n-1}(dual_boundary(Val{n}, s, x.data)) -function dual_boundary(::Type{Val{n}}, s::AbstractACSet, args...) where n +function dual_boundary(::Type{Val{n}}, s::ACSet, args...) where n operator_nz(Int, nsimplices(ndims(s)-n+1,s), nsimplices(ndims(s)-n,s), args...) do x dual_boundary_nz(Val{n}, s, x) @@ -638,12 +639,12 @@ end Transpose of [`dual_boundary`](@ref). For more info, see (Desbrun, Kanso, Tong, 2008: Discrete differential forms for computational modeling, §4.5). """ -@inline dual_derivative(n::Int, s::AbstractACSet, args...) = +@inline dual_derivative(n::Int, s::ACSet, args...) = dual_derivative(Val{n}, s, args...) -d(s::AbstractACSet, x::DualForm{n}) where n = +d(s::ACSet, x::DualForm{n}) where n = DualForm{n+1}(dual_derivative(Val{n}, s, x.data)) -function dual_derivative(::Type{Val{n}}, s::AbstractACSet, args...) where n +function dual_derivative(::Type{Val{n}}, s::ACSet, args...) where n operator_nz(Int, nsimplices(ndims(s)-n-1,s), nsimplices(ndims(s)-n,s), args...) do x dual_derivative_nz(Val{n}, s, x) @@ -659,17 +660,17 @@ end operator on cochains. We do not explicitly define the duality operator and we use the symbol ``⋆`` for the Hodge star. """ -⋆(s::AbstractACSet, x::SimplexForm{n}; kw...) where n = +⋆(s::ACSet, x::SimplexForm{n}; kw...) where n = DualForm{ndims(s)-n}(⋆(Val{n}, s, x.data; kw...)) -@inline ⋆(n::Int, s::AbstractACSet, args...; kw...) = ⋆(Val{n}, s, args...; kw...) -@inline ⋆(::Type{Val{n}}, s::AbstractACSet; hodge=GeometricHodge()) where n = +@inline ⋆(n::Int, s::ACSet, args...; kw...) = ⋆(Val{n}, s, args...; kw...) +@inline ⋆(::Type{Val{n}}, s::ACSet; hodge=GeometricHodge()) where n = ⋆(Val{n}, s, hodge) -@inline ⋆(::Type{Val{n}}, s::AbstractACSet, form::AbstractVector; +@inline ⋆(::Type{Val{n}}, s::ACSet, form::AbstractVector; hodge=GeometricHodge()) where n = ⋆(Val{n}, s, form, hodge) -⋆(::Type{Val{n}}, s::AbstractACSet, form::AbstractVector, ::DiagonalHodge) where n = +⋆(::Type{Val{n}}, s::ACSet, form::AbstractVector, ::DiagonalHodge) where n = applydiag(form) do x, a; a * hodge_diag(Val{n},s,x) end -⋆(::Type{Val{n}}, s::AbstractACSet, ::DiagonalHodge) where n = +⋆(::Type{Val{n}}, s::ACSet, ::DiagonalHodge) where n = Diagonal([ hodge_diag(Val{n},s,x) for x in simplices(n,s) ]) # Note that this cross product defines the positive direction for flux to @@ -757,14 +758,14 @@ Confusingly, this is *not* the operator inverse of the Hodge star [`⋆`](@ref) because it carries an extra global sign, in analogy to the smooth case (Gillette, 2009, Notes on the DEC, Definition 2.27). """ -@inline inv_hodge_star(n::Int, s::AbstractACSet, args...; kw...) = +@inline inv_hodge_star(n::Int, s::ACSet, args...; kw...) = inv_hodge_star(Val{n}, s, args...; kw...) -@inline inv_hodge_star(::Type{Val{n}}, s::AbstractACSet; hodge=GeometricHodge()) where n = +@inline inv_hodge_star(::Type{Val{n}}, s::ACSet; hodge=GeometricHodge()) where n = inv_hodge_star(Val{n}, s, hodge) -@inline inv_hodge_star(::Type{Val{n}}, s::AbstractACSet, form::AbstractVector; +@inline inv_hodge_star(::Type{Val{n}}, s::ACSet, form::AbstractVector; hodge=GeometricHodge()) where n = inv_hodge_star(Val{n}, s, form, hodge) -function inv_hodge_star(::Type{Val{n}}, s::AbstractACSet, +function inv_hodge_star(::Type{Val{n}}, s::ACSet, form::AbstractVector, ::DiagonalHodge) where n if iseven(n*(ndims(s)-n)) applydiag(form) do x, a; a / hodge_diag(Val{n},s,x) end @@ -773,7 +774,7 @@ function inv_hodge_star(::Type{Val{n}}, s::AbstractACSet, end end -function inv_hodge_star(::Type{Val{n}}, s::AbstractACSet, +function inv_hodge_star(::Type{Val{n}}, s::ACSet, ::DiagonalHodge) where n if iseven(n*(ndims(s)-n)) Diagonal([ 1 / hodge_diag(Val{n},s,x) for x in simplices(n,s) ]) @@ -812,18 +813,18 @@ inv_hodge_star(::Type{Val{n}}, s::AbstractDeltaDualComplex1D, """ Codifferential operator from primal ``n`` forms to primal ``n-1``-forms. """ -δ(s::AbstractACSet, x::SimplexForm{n}; kw...) where n = +δ(s::ACSet, x::SimplexForm{n}; kw...) where n = SimplexForm{n-1}(δ(Val{n}, s, GeometricHodge(), x.data; kw...)) -@inline δ(n::Int, s::AbstractACSet, args...; kw...) = +@inline δ(n::Int, s::ACSet, args...; kw...) = δ(Val{n}, s, args...; kw...) -@inline δ(::Type{Val{n}}, s::AbstractACSet; hodge=GeometricHodge(), +@inline δ(::Type{Val{n}}, s::ACSet; hodge=GeometricHodge(), matrix_type::Type=SparseMatrixCSC{Float64}) where n = δ(Val{n}, s, hodge, matrix_type) -@inline δ(::Type{Val{n}}, s::AbstractACSet, form::AbstractVector; +@inline δ(::Type{Val{n}}, s::ACSet, form::AbstractVector; hodge=GeometricHodge()) where n = δ(Val{n}, s, hodge, form) -function δ(::Type{Val{n}}, s::AbstractACSet, ::DiagonalHodge, args...) where n +function δ(::Type{Val{n}}, s::ACSet, ::DiagonalHodge, args...) where n # TODO: What is the right global sign? # sgn = iseven((n-1)*(ndims(s)-n+1)) ? +1 : -1 operator_nz(Float64, nsimplices(n-1,s), nsimplices(n,s), args...) do x @@ -836,11 +837,11 @@ function δ(::Type{Val{n}}, s::AbstractACSet, ::DiagonalHodge, args...) where n end end -function δ(::Type{Val{n}}, s::AbstractACSet, ::GeometricHodge, matrix_type) where n +function δ(::Type{Val{n}}, s::ACSet, ::GeometricHodge, matrix_type) where n inv_hodge_star(n-1, s) * dual_derivative(ndims(s)-n, s) * ⋆(n, s) end -function δ(::Type{Val{n}}, s::AbstractACSet, ::GeometricHodge, form::AbstractVector) where n +function δ(::Type{Val{n}}, s::ACSet, ::GeometricHodge, form::AbstractVector) where n Vector(inv_hodge_star(n - 1, s, dual_derivative(ndims(s)-n, s, ⋆(n, s, form)))) end @@ -861,13 +862,13 @@ This linear operator on primal ``n``-forms defined by ``∇² α := -δ d α``, such as (Hirani 2003), take the opposite convention, which has the advantage of being consistent with the Laplace-de Rham operator [`Δ`](@ref). """ -∇²(s::AbstractACSet, x::SimplexForm{n}; kw...) where n = +∇²(s::ACSet, x::SimplexForm{n}; kw...) where n = SimplexForm{n}(∇²(Val{n}, s, x.data; kw...)) -@inline ∇²(n::Int, s::AbstractACSet, args...; kw...) = ∇²(Val{n}, s, args...; kw...) +@inline ∇²(n::Int, s::ACSet, args...; kw...) = ∇²(Val{n}, s, args...; kw...) -∇²(::Type{Val{n}}, s::AbstractACSet, form::AbstractVector; kw...) where n = +∇²(::Type{Val{n}}, s::ACSet, form::AbstractVector; kw...) where n = -δ(n+1, s, d(Val{n}, s, form); kw...) -∇²(::Type{Val{n}}, s::AbstractACSet; matrix_type::Type=SparseMatrixCSC{Float64}, kw...) where n = +∇²(::Type{Val{n}}, s::ACSet; matrix_type::Type=SparseMatrixCSC{Float64}, kw...) where n = -δ(n+1, s; matrix_type=matrix_type, kw...) * d(Val{n}, s, matrix_type) """ Alias for the Laplace-Beltrami operator [`∇²`](@ref). @@ -880,18 +881,18 @@ This linear operator on primal ``n``-forms is defined by ``Δ := δ d + d δ``. Restricted to 0-forms, it reduces to the negative of the Laplace-Beltrami operator [`∇²`](@ref): ``Δ f = -∇² f``. """ -Δ(s::AbstractACSet, x::SimplexForm{n}; kw...) where n = +Δ(s::ACSet, x::SimplexForm{n}; kw...) where n = SimplexForm{n}(Δ(Val{n}, s, x.data; kw...)) -@inline Δ(n::Int, s::AbstractACSet, args...; kw...) = Δ(Val{n}, s, args...; kw...) +@inline Δ(n::Int, s::ACSet, args...; kw...) = Δ(Val{n}, s, args...; kw...) -Δ(::Type{Val{0}}, s::AbstractACSet, form::AbstractVector; kw...) = +Δ(::Type{Val{0}}, s::ACSet, form::AbstractVector; kw...) = δ(1, s, d(Val{0}, s, form); kw...) -Δ(::Type{Val{0}}, s::AbstractACSet; matrix_type::Type=SparseMatrixCSC{Float64}, kw...) = +Δ(::Type{Val{0}}, s::ACSet; matrix_type::Type=SparseMatrixCSC{Float64}, kw...) = δ(1,s; matrix_type=matrix_type, kw...) * d(Val{0},s,matrix_type) -Δ(::Type{Val{n}}, s::AbstractACSet, form::AbstractVector; kw...) where n = +Δ(::Type{Val{n}}, s::ACSet, form::AbstractVector; kw...) where n = δ(n+1, s, d(Val{n}, s, form); kw...) + d(Val{n-1}, s, δ(n, s, form; kw...)) -Δ(::Type{Val{n}}, s::AbstractACSet; matrix_type::Type=SparseMatrixCSC{Float64}, kw...) where n = +Δ(::Type{Val{n}}, s::ACSet; matrix_type::Type=SparseMatrixCSC{Float64}, kw...) where n = δ(n+1,s; matrix_type=matrix_type, kw...) * d(Val{n},s,matrix_type) + d(Val{n-1},s,matrix_type) * δ(n,s; matrix_type=matrix_type, kw...) @@ -916,7 +917,7 @@ implemented. See also: the sharp operator [`♯`](@ref). """ -♭(s::AbstractACSet, X::DualVectorField) = EForm(♭(s, X.data, DPPFlat())) +♭(s::ACSet, X::DualVectorField) = EForm(♭(s, X.data, DPPFlat())) """ Alias for the flat operator [`♭`](@ref). """ @@ -942,7 +943,7 @@ implemented. See also: the flat operator [`♭`](@ref). """ -♯(s::AbstractACSet, α::EForm) = PrimalVectorField(♯(s, α.data, PPSharp())) +♯(s::ACSet, α::EForm) = PrimalVectorField(♯(s, α.data, PPSharp())) """ Alias for the sharp operator [`♯`](@ref). """ @@ -957,25 +958,25 @@ the discrete primal-primal wedge product introduced in (Hirani, 2003, Chapter 7) and (Desbrun et al 2005, Section 8). It depends on the geometric embedding and requires the dual complex. """ -∧(s::AbstractACSet, α::SimplexForm{k}, β::SimplexForm{l}) where {k,l} = +∧(s::ACSet, α::SimplexForm{k}, β::SimplexForm{l}) where {k,l} = SimplexForm{k+l}(∧(Tuple{k,l}, s, α.data, β.data)) -@inline ∧(k::Int, l::Int, s::AbstractACSet, args...) = ∧(Tuple{k,l}, s, args...) +@inline ∧(k::Int, l::Int, s::ACSet, args...) = ∧(Tuple{k,l}, s, args...) -function ∧(::Type{Tuple{k,l}}, s::AbstractACSet, α, β) where {k,l} +function ∧(::Type{Tuple{k,l}}, s::ACSet, α, β) where {k,l} map(simplices(k+l, s)) do x ∧(Tuple{k,l}, s, α, β, x) end end -∧(::Type{Tuple{0,0}}, s::AbstractACSet, f, g, x::Int) = f[x]*g[x] -∧(::Type{Tuple{k,0}}, s::AbstractACSet, α, g, x::Int) where k = +∧(::Type{Tuple{0,0}}, s::ACSet, f, g, x::Int) = f[x]*g[x] +∧(::Type{Tuple{k,0}}, s::ACSet, α, g, x::Int) where k = wedge_product_zero(Val{k}, s, g, α, x) -∧(::Type{Tuple{0,k}}, s::AbstractACSet, f, β, x::Int) where k = +∧(::Type{Tuple{0,k}}, s::ACSet, f, β, x::Int) where k = wedge_product_zero(Val{k}, s, f, β, x) """ Wedge product of a 0-form and a ``k``-form. """ -function wedge_product_zero(::Type{Val{k}}, s::AbstractACSet, +function wedge_product_zero(::Type{Val{k}}, s::ACSet, f, α, x::Int) where k subs = subsimplices(k, s, x) vs = primal_vertex(k, s, subs) @@ -994,7 +995,7 @@ Specifically, this operation is the primal-dual interior product defined in primal vector field (or primal 1-form) and a dual ``n``-forms and then returns a dual ``(n-1)``-form. """ -interior_product(s::AbstractACSet, X♭::EForm, α::DualForm{n}; kw...) where n = +interior_product(s::ACSet, X♭::EForm, α::DualForm{n}; kw...) where n = DualForm{n-1}(interior_product_flat(Val{n}, s, X♭.data, α.data); kw...) """ Interior product of a 1-form and a ``n``-form, yielding an ``(n-1)``-form. @@ -1003,10 +1004,10 @@ Usually, the interior product is defined for vector fields; this function assumes that the flat operator [`♭`](@ref) (not yet implemented for primal vector fields) has already been applied to yield a 1-form. """ -@inline interior_product_flat(n::Int, s::AbstractACSet, args...; kw...) = +@inline interior_product_flat(n::Int, s::ACSet, args...; kw...) = interior_product_flat(Val{n}, s, args...; kw...) -function interior_product_flat(::Type{Val{n}}, s::AbstractACSet, +function interior_product_flat(::Type{Val{n}}, s::ACSet, X♭::AbstractVector, α::AbstractVector; kw...) where n # TODO: Global sign `iseven(n*n′) ? +1 : -1` @@ -1019,7 +1020,7 @@ end Specifically, this is the primal-dual Lie derivative defined in (Hirani 2003, Section 8.4) and (Desbrun et al 2005, Section 10). """ -ℒ(s::AbstractACSet, X♭::EForm, α::DualForm{n}; kw...) where n = +ℒ(s::ACSet, X♭::EForm, α::DualForm{n}; kw...) where n = DualForm{n}(lie_derivative_flat(Val{n}, s, X♭, α.data; kw...)) """ Alias for Lie derivative operator [`ℒ`](@ref). @@ -1031,21 +1032,21 @@ const lie_derivative = ℒ Assumes that the flat operator [`♭`](@ref) has already been applied to the vector field. """ -@inline lie_derivative_flat(n::Int, s::AbstractACSet, args...; kw...) = +@inline lie_derivative_flat(n::Int, s::ACSet, args...; kw...) = lie_derivative_flat(Val{n}, s, args...; kw...) -function lie_derivative_flat(::Type{Val{0}}, s::AbstractACSet, +function lie_derivative_flat(::Type{Val{0}}, s::ACSet, X♭::AbstractVector, α::AbstractVector; kw...) interior_product_flat(1, s, X♭, dual_derivative(0, s, α); kw...) end -function lie_derivative_flat(::Type{Val{1}}, s::AbstractACSet, +function lie_derivative_flat(::Type{Val{1}}, s::ACSet, X♭::AbstractVector, α::AbstractVector; kw...) interior_product_flat(2, s, X♭, dual_derivative(1, s, α); kw...) + dual_derivative(0, s, interior_product_flat(1, s, X♭, α; kw...)) end -function lie_derivative_flat(::Type{Val{2}}, s::AbstractACSet, +function lie_derivative_flat(::Type{Val{2}}, s::ACSet, X♭::AbstractVector, α::AbstractVector; kw...) dual_derivative(1, s, interior_product_flat(2, s, X♭, α; kw...)) end diff --git a/src/MeshGraphics.jl b/src/MeshGraphics.jl index 5df189ea..a2e867c1 100644 --- a/src/MeshGraphics.jl +++ b/src/MeshGraphics.jl @@ -25,7 +25,7 @@ an embedded deltaset into arguments that can be passed into Makie.mesh function convert_arguments(P::Union{Type{<:Makie.Wireframe}, Type{<:Makie.Mesh}, Type{<:Makie.Scatter}}, - dset::AbstractACSet) + dset::ACSet) convert_arguments(P, Mesh(dset)) end diff --git a/src/SimplicialSets.jl b/src/SimplicialSets.jl index 148d5266..0aaa1c70 100644 --- a/src/SimplicialSets.jl +++ b/src/SimplicialSets.jl @@ -56,24 +56,24 @@ const DeltaSet1D = Graph nsimplices(::Type{Val{0}}, s) = nv(s) nsimplices(::Type{Val{1}}, s) = ne(s) -face(::Type{Val{(1,0)}}, s::AbstractACSet, args...) = subpart(s, args..., :tgt) -face(::Type{Val{(1,1)}}, s::AbstractACSet, args...) = subpart(s, args..., :src) +face(::Type{Val{(1,0)}}, s::ACSet, args...) = subpart(s, args..., :tgt) +face(::Type{Val{(1,1)}}, s::ACSet, args...) = subpart(s, args..., :src) -coface(::Type{Val{(1,0)}}, s::AbstractACSet, args...) = incident(s, args..., :tgt) -coface(::Type{Val{(1,1)}}, s::AbstractACSet, args...) = incident(s, args..., :src) +coface(::Type{Val{(1,0)}}, s::ACSet, args...) = incident(s, args..., :tgt) +coface(::Type{Val{(1,1)}}, s::ACSet, args...) = incident(s, args..., :src) """ Boundary vertices of an edge. """ -edge_vertices(s::AbstractACSet, e...) = SVector(∂(1,0,s,e...), ∂(1,1,s,e...)) +edge_vertices(s::ACSet, e...) = SVector(∂(1,0,s,e...), ∂(1,1,s,e...)) """ Add edge to simplicial set, respecting the order of the vertex IDs. """ -add_sorted_edge!(s::AbstractACSet, v₀::Int, v₁::Int; kw...) = +add_sorted_edge!(s::ACSet, v₀::Int, v₁::Int; kw...) = add_edge!(s, min(v₀, v₁), max(v₀, v₁); kw...) """ Add edges to simplicial set, respecting the order of the vertex IDs. """ -function add_sorted_edges!(s::AbstractACSet, vs₀::AbstractVector{Int}, +function add_sorted_edges!(s::ACSet, vs₀::AbstractVector{Int}, vs₁::AbstractVector{Int}; kw...) add_edges!(s, min.(vs₀, vs₁), max.(vs₀, vs₁); kw...) end @@ -82,7 +82,7 @@ end #---------------------------- @present OrientedDeltaSchema1D <: DeltaCategory1D begin - Orientation::Data + Orientation::AttrType edge_orientation::Attr(E,Orientation) end @@ -91,18 +91,19 @@ end Edges are oriented from source to target when `edge_orientation` is true/positive and from target to source when it is false/negative. """ -const OrientedDeltaSet1D = ACSetType(OrientedDeltaSchema1D, index=[:src,:tgt]) +@acset_type OrientedDeltaSet1D(OrientedDeltaSchema1D, + index=[:src,:tgt]) <: AbstractDeltaSet1D -orientation(::Type{Val{1}}, s::AbstractACSet, args...) = +orientation(::Type{Val{1}}, s::ACSet, args...) = s[args..., :edge_orientation] -set_orientation!(::Type{Val{1}}, s::AbstractACSet, e, orientation) = +set_orientation!(::Type{Val{1}}, s::ACSet, e, orientation) = (s[e, :edge_orientation] = orientation) -function ∂_nz(::Type{Val{1}}, s::AbstractACSet, e::Int) +function ∂_nz(::Type{Val{1}}, s::ACSet, e::Int) (edge_vertices(s, e), sign(1,s,e) * @SVector([1,-1])) end -function d_nz(::Type{Val{0}}, s::AbstractACSet, v::Int) +function d_nz(::Type{Val{0}}, s::ACSet, v::Int) e₀, e₁ = coface(1,0,s,v), coface(1,1,s,v) (lazy(vcat, e₀, e₁), lazy(vcat, sign(1,s,e₀), -sign(1,s,e₁))) end @@ -111,23 +112,24 @@ end #---------------------------- @present EmbeddedDeltaSchema1D <: OrientedDeltaSchema1D begin - Point::Data + Point::AttrType point::Attr(V, Point) end """ A one-dimensional, embedded, oriented delta set. """ -const EmbeddedDeltaSet1D = ACSetType(EmbeddedDeltaSchema1D, index=[:src,:tgt]) +@acset_type EmbeddedDeltaSet1D(EmbeddedDeltaSchema1D, + index=[:src,:tgt]) <: AbstractDeltaSet1D """ Point associated with vertex of complex. """ -point(s::AbstractACSet, args...) = s[args..., :point] +point(s::ACSet, args...) = s[args..., :point] struct CayleyMengerDet end volume(::Type{Val{n}}, s::EmbeddedDeltaSet1D, x) where n = volume(Val{n}, s, x, CayleyMengerDet()) -volume(::Type{Val{1}}, s::AbstractACSet, e::Int, ::CayleyMengerDet) = +volume(::Type{Val{1}}, s::ACSet, e::Int, ::CayleyMengerDet) = volume(point(s, edge_vertices(s, e))) # 2D simplicial sets @@ -145,7 +147,7 @@ end """ Abstract type for 2D delta sets. """ -const AbstractDeltaSet2D = AbstractACSetType(DeltaCategory2D) +@abstract_acset_type AbstractDeltaSet2D <: HasGraph """ A 2D delta set, aka semi-simplicial set. @@ -159,24 +161,24 @@ higher-dimensional link or morphism, going from two edges in sequence (which might be called `src2_first` and `src2_last`) to a transitive edge (say `tgt2`). This is the shape of the binary composition operation in a category. """ -const DeltaSet2D = CSetType(DeltaCategory2D, - index=[:src, :tgt, :∂e0, :∂e1, :∂e2]) +@acset_type DeltaSet2D(DeltaCategory2D, + index=[:src,:tgt,:∂e0,:∂e1,:∂e2]) <: AbstractDeltaSet2D -triangles(s::AbstractACSet) = parts(s, :Tri) -ntriangles(s::AbstractACSet) = nparts(s, :Tri) +triangles(s::ACSet) = parts(s, :Tri) +ntriangles(s::ACSet) = nparts(s, :Tri) nsimplices(::Type{Val{2}}, s) = ntriangles(s) -face(::Type{Val{(2,0)}}, s::AbstractACSet, args...) = subpart(s, args..., :∂e0) -face(::Type{Val{(2,1)}}, s::AbstractACSet, args...) = subpart(s, args..., :∂e1) -face(::Type{Val{(2,2)}}, s::AbstractACSet, args...) = subpart(s, args..., :∂e2) +face(::Type{Val{(2,0)}}, s::ACSet, args...) = subpart(s, args..., :∂e0) +face(::Type{Val{(2,1)}}, s::ACSet, args...) = subpart(s, args..., :∂e1) +face(::Type{Val{(2,2)}}, s::ACSet, args...) = subpart(s, args..., :∂e2) -coface(::Type{Val{(2,0)}}, s::AbstractACSet, args...) = incident(s, args..., :∂e0) -coface(::Type{Val{(2,1)}}, s::AbstractACSet, args...) = incident(s, args..., :∂e1) -coface(::Type{Val{(2,2)}}, s::AbstractACSet, args...) = incident(s, args..., :∂e2) +coface(::Type{Val{(2,0)}}, s::ACSet, args...) = incident(s, args..., :∂e0) +coface(::Type{Val{(2,1)}}, s::ACSet, args...) = incident(s, args..., :∂e1) +coface(::Type{Val{(2,2)}}, s::ACSet, args...) = incident(s, args..., :∂e2) """ Boundary edges of a triangle. """ -function triangle_edges(s::AbstractACSet, t...) +function triangle_edges(s::ACSet, t...) SVector(∂(2,0,s,t...), ∂(2,1,s,t...), ∂(2,2,s,t...)) end @@ -184,7 +186,7 @@ end This accessor assumes that the simplicial identities hold. """ -function triangle_vertices(s::AbstractACSet, t...) +function triangle_vertices(s::ACSet, t...) SVector(s[s[t..., :∂e1], :src], s[s[t..., :∂e2], :tgt], s[s[t..., :∂e1], :tgt]) @@ -202,7 +204,7 @@ In the arguments to this function, the boundary edges have the order ``0 → 1`` using the function [`glue_triangle!`](@ref) always satisfy the simplicial identities, by construction. Thus it is often easier to use this function. """ -add_triangle!(s::AbstractACSet, src2_first::Int, src2_last::Int, tgt2::Int; kw...) = +add_triangle!(s::ACSet, src2_first::Int, src2_last::Int, tgt2::Int; kw...) = add_part!(s, :Tri; ∂e0=src2_last, ∂e1=tgt2, ∂e2=src2_first, kw...) """ Glue a triangle onto a simplicial set, given its boundary vertices. @@ -210,19 +212,19 @@ add_triangle!(s::AbstractACSet, src2_first::Int, src2_last::Int, tgt2::Int; kw.. If a needed edge between two vertices exists, it is reused (hence the "gluing"); otherwise, it is created. """ -function glue_triangle!(s::AbstractACSet, v₀::Int, v₁::Int, v₂::Int; kw...) +function glue_triangle!(s::ACSet, v₀::Int, v₁::Int, v₂::Int; kw...) add_triangle!(s, get_edge!(s, v₀, v₁), get_edge!(s, v₁, v₂), get_edge!(s, v₀, v₂); kw...) end -function get_edge!(s::AbstractACSet, src::Int, tgt::Int) +function get_edge!(s::ACSet, src::Int, tgt::Int) es = edges(s, src, tgt) isempty(es) ? add_edge!(s, src, tgt) : first(es) end """ Glue a triangle onto a simplicial set, respecting the order of the vertices. """ -function glue_sorted_triangle!(s::AbstractACSet, v₀::Int, v₁::Int, v₂::Int; kw...) +function glue_sorted_triangle!(s::ACSet, v₀::Int, v₁::Int, v₂::Int; kw...) v₀, v₁, v₂ = sort(SVector(v₀, v₁, v₂)) glue_triangle!(s, v₀, v₁, v₂; kw...) end @@ -231,7 +233,7 @@ end #---------------------------- @present OrientedDeltaSchema2D <: DeltaCategory2D begin - Orientation::Data + Orientation::AttrType edge_orientation::Attr(E,Orientation) tri_orientation::Attr(Tri,Orientation) end @@ -241,20 +243,20 @@ end Triangles are ordered in the cyclic order ``(0,1,2)`` when `tri_orientation` is true/positive and in the reverse order when it is false/negative. """ -const OrientedDeltaSet2D = ACSetType(OrientedDeltaSchema2D, - index=[:src, :tgt, :∂e0, :∂e1, :∂e2]) +@acset_type OrientedDeltaSet2D(OrientedDeltaSchema2D, + index=[:src,:tgt,:∂e0,:∂e1,:∂e2]) <: AbstractDeltaSet2D -orientation(::Type{Val{2}}, s::AbstractACSet, args...) = +orientation(::Type{Val{2}}, s::ACSet, args...) = s[args..., :tri_orientation] -set_orientation!(::Type{Val{2}}, s::AbstractACSet, t, orientation) = +set_orientation!(::Type{Val{2}}, s::ACSet, t, orientation) = (s[t, :tri_orientation] = orientation) -function ∂_nz(::Type{Val{2}}, s::AbstractACSet, t::Int) +function ∂_nz(::Type{Val{2}}, s::ACSet, t::Int) edges = triangle_edges(s,t) (edges, sign(2,s,t) * sign(1,s,edges) .* @SVector([1,-1,1])) end -function d_nz(::Type{Val{1}}, s::AbstractACSet, e::Int) +function d_nz(::Type{Val{1}}, s::ACSet, e::Int) sgn = sign(1, s, e) t₀, t₁, t₂ = coface(2,0,s,e), coface(2,1,s,e), coface(2,2,s,e) (lazy(vcat, t₀, t₁, t₂), @@ -265,18 +267,18 @@ end #---------------------------- @present EmbeddedDeltaSchema2D <: OrientedDeltaSchema2D begin - Point::Data + Point::AttrType point::Attr(V, Point) end """ A two-dimensional, embedded, oriented delta set. """ -const EmbeddedDeltaSet2D = ACSetType(EmbeddedDeltaSchema2D, - index=[:src, :tgt, :∂e0, :∂e1, :∂e2]) +@acset_type EmbeddedDeltaSet2D(EmbeddedDeltaSchema2D, + index=[:src,:tgt,:∂e0,:∂e1,:∂e2]) <: AbstractDeltaSet2D volume(::Type{Val{n}}, s::EmbeddedDeltaSet2D, x) where n = volume(Val{n}, s, x, CayleyMengerDet()) -volume(::Type{Val{2}}, s::AbstractACSet, t::Int, ::CayleyMengerDet) = +volume(::Type{Val{2}}, s::ACSet, t::Int, ::CayleyMengerDet) = volume(point(s, triangle_vertices(s,t))) # General operators @@ -318,11 +320,11 @@ const TriForm = SimplexForm{2} """ Simplices of given dimension in a simplicial set. """ -@inline simplices(n::Int, s::AbstractACSet) = 1:nsimplices(Val{n}, s) +@inline simplices(n::Int, s::ACSet) = 1:nsimplices(Val{n}, s) """ Number of simplices of given dimension in a simplicial set. """ -@inline nsimplices(n::Int, s::AbstractACSet) = nsimplices(Val{n}, s) +@inline nsimplices(n::Int, s::ACSet) = nsimplices(Val{n}, s) """ Face map and boundary operator on simplicial sets. @@ -342,21 +344,21 @@ The boundary operator on `n`-faces and `n`-chains is implemented by the call Note that the face map returns *simplices*, while the boundary operator returns *chains* (vectors in the free vector space spanned by oriented simplices). """ -@inline ∂(i::Int, s::AbstractACSet, x::Simplex{n}) where n = +@inline ∂(i::Int, s::ACSet, x::Simplex{n}) where n = Simplex{n-1}(face(Val{(n,i)}, s, x.data)) -@inline ∂(n::Int, i::Int, s::AbstractACSet, args...) = +@inline ∂(n::Int, i::Int, s::ACSet, args...) = face(Val{(n,i)}, s, args...) -@inline coface(i::Int, s::AbstractACSet, x::Simplex{n}) where n = +@inline coface(i::Int, s::ACSet, x::Simplex{n}) where n = Simplex{n+1}(coface(Val{(n+1,i)}, s, x.data)) -@inline coface(n::Int, i::Int, s::AbstractACSet, args...) = +@inline coface(n::Int, i::Int, s::ACSet, args...) = coface(Val{(n,i)}, s, args...) -∂(s::AbstractACSet, x::SimplexChain{n}) where n = +∂(s::ACSet, x::SimplexChain{n}) where n = SimplexChain{n-1}(∂(Val{n}, s, x.data)) -@inline ∂(n::Int, s::AbstractACSet, args...) = ∂(Val{n}, s, args...) +@inline ∂(n::Int, s::ACSet, args...) = ∂(Val{n}, s, args...) -function ∂(::Type{Val{n}}, s::AbstractACSet, args...) where n +function ∂(::Type{Val{n}}, s::ACSet, args...) where n operator_nz(Int, nsimplices(n-1,s), nsimplices(n,s), args...) do x ∂_nz(Val{n}, s, x) end @@ -368,11 +370,11 @@ const boundary = ∂ """ The discrete exterior derivative, aka the coboundary operator. """ -d(s::AbstractACSet, x::SimplexForm{n}) where n = +d(s::ACSet, x::SimplexForm{n}) where n = SimplexForm{n+1}(d(Val{n}, s, x.data)) -@inline d(n::Int, s::AbstractACSet, args...) = d(Val{n}, s, args...) +@inline d(n::Int, s::ACSet, args...) = d(Val{n}, s, args...) -function d(::Type{Val{n}}, s::AbstractACSet, args...) where n +function d(::Type{Val{n}}, s::ACSet, args...) where n operator_nz(Int, nsimplices(n+1,s), nsimplices(n,s), args...) do x d_nz(Val{n}, s, x) end @@ -388,13 +390,13 @@ const exterior_derivative = d """ Orientation of simplex. """ -orientation(s::AbstractACSet, x::Simplex{n}) where n = +orientation(s::ACSet, x::Simplex{n}) where n = orientation(Val{n}, s, x.data) -@inline orientation(n::Int, s::AbstractACSet, args...) = +@inline orientation(n::Int, s::ACSet, args...) = orientation(Val{n}, s, args...) -@inline Base.sign(n::Int, s::AbstractACSet, args...) = sign(Val{n}, s, args...) -Base.sign(::Type{Val{n}}, s::AbstractACSet, args...) where n = +@inline Base.sign(n::Int, s::ACSet, args...) = sign(Val{n}, s, args...) +Base.sign(::Type{Val{n}}, s::ACSet, args...) where n = numeric_sign.(orientation(Val{n}, s, args...)) numeric_sign(x) = sign(x) @@ -402,14 +404,14 @@ numeric_sign(x::Bool) = x ? +1 : -1 """ Set orientation of simplex. """ -@inline set_orientation!(n::Int, s::AbstractACSet, args...) = +@inline set_orientation!(n::Int, s::ACSet, args...) = set_orientation!(Val{n}, s, args...) """ ``n``-dimensional volume of ``n``-simplex in an embedded simplicial set. """ -volume(s::AbstractACSet, x::Simplex{n}, args...) where n = +volume(s::ACSet, x::Simplex{n}, args...) where n = volume(Val{n}, s, x.data, args...) -@inline volume(n::Int, s::AbstractACSet, args...) = volume(Val{n}, s, args...) +@inline volume(n::Int, s::ACSet, args...) = volume(Val{n}, s, args...) """ Convenience function for linear operator based on structural nonzero values. """ @@ -434,7 +436,7 @@ function [`orient_component!`](@ref). orient!(s::AbstractDeltaSet1D) = orient!(s, E) orient!(s::AbstractDeltaSet2D) = orient!(s, Tri) -function orient!(s::AbstractACSet, ::Type{Simplex{n}}) where n +function orient!(s::ACSet, ::Type{Simplex{n}}) where n # Compute connected components as coequalizer of face maps. ndom, ncodom = nsimplices(n, s), nsimplices(n-1, s) face_maps = SVector{n+1}([ FinFunction(x -> ∂(n,i,s,x), ndom, ncodom) @@ -471,7 +473,7 @@ orient_component!(s::AbstractDeltaSet1D, e::Int, args...) = orient_component!(s::AbstractDeltaSet2D, t::Int, args...) = orient_component!(s, Tri(t), args...) -function orient_component!(s::AbstractACSet, x::Simplex{n}, +function orient_component!(s::ACSet, x::Simplex{n}, x_orientation::Orientation) where {n, Orientation} orientations = repeat(Union{Orientation,Nothing}[nothing], nsimplices(n, s)) diff --git a/test/SimplicialSets.jl b/test/SimplicialSets.jl index 36591c91..e10ad6cc 100644 --- a/test/SimplicialSets.jl +++ b/test/SimplicialSets.jl @@ -8,7 +8,7 @@ using CombinatorialSpaces.SimplicialSets """ Check that the semi-simplicial identities hold in dimension `n`. """ -function is_semi_simplicial(s::AbstractACSet, n::Int) +function is_semi_simplicial(s::ACSet, n::Int) all(∂(n-1, i, s, ∂(n, j, s)) == ∂(n-1, j-1, s, ∂(n, i, s)) for i in 0:n for j in (i+1):n) end