From 2cac4793133cbcecab3cf8c6f5934a1bbd8d6272 Mon Sep 17 00:00:00 2001 From: Evan Patterson Date: Sun, 18 Oct 2020 20:50:47 -0700 Subject: [PATCH 1/4] ENH: Composition of subparts in `subpart` accessor of C-sets. --- src/categorical_algebra/CSetDataStructures.jl | 20 +++++++++++++++---- .../categorical_algebra/CSetDataStructures.jl | 5 +++++ 2 files changed, 21 insertions(+), 4 deletions(-) diff --git a/src/categorical_algebra/CSetDataStructures.jl b/src/categorical_algebra/CSetDataStructures.jl index 8cff9354e..467a7e701 100644 --- a/src/categorical_algebra/CSetDataStructures.jl +++ b/src/categorical_algebra/CSetDataStructures.jl @@ -12,9 +12,8 @@ using Compat: isnothing, only using PrettyTables: pretty_table using StructArrays -using ...Theories: Schema, FreeSchema, dom, codom, - CatDesc, CatDescType, AttrDesc, AttrDescType, SchemaType, - ob_num, hom_num, data_num, attr_num, dom_num, codom_num +using ...Theories: Schema, FreeSchema, dom, codom, codom_num, + CatDesc, CatDescType, AttrDesc, AttrDescType, SchemaType using ...Present # Data types @@ -324,11 +323,24 @@ end """ Get subpart of part in C-set. -Both single and vectorized access are supported. +Both single and vectorized access are supported. Chaining, or composition, of +parts is also supported. For example, given a vertex-attributed graph `g`, + +``` +subpart(g, e, [:src, :vattr]) +``` + +returns the vertex attribute of the source vertex of the edge `e`. """ subpart(acs::ACSet, part, name::Symbol) = subpart(acs,name)[part] subpart(acs::ACSet, name::Symbol) = _subpart(acs,Val(name)) +function subpart(acs::ACSet, part, names::AbstractVector{Symbol}) + foldl(names, init=part) do part, name + subpart(acs, part, name) + end +end + @generated function _subpart(acs::ACSet{CD,AD,Ts}, ::Val{name}) where {CD,AD,Ts,name} if name ∈ CD.hom diff --git a/test/categorical_algebra/CSetDataStructures.jl b/test/categorical_algebra/CSetDataStructures.jl index aa1dcbb74..f9d6a8d62 100644 --- a/test/categorical_algebra/CSetDataStructures.jl +++ b/test/categorical_algebra/CSetDataStructures.jl @@ -145,6 +145,11 @@ set_subpart!(d, [4,5], :parent, 5) @test subpart(d, 4, :height) == 10 @test subpart(d, :, :height) == [0,0,0,10,20] +# Chained accessors. +@test subpart(d, 3, [:parent, :parent]) == 5 +@test subpart(d, 3, [:parent, :height]) == 10 + +# Copying parts. d2 = Dendrogram{Int}() copy_parts!(d2, d, X=[4,5]) @test nparts(d2, :X) == 2 From d125e5d43c49997133bb9b048dd1ecc26ff86089 Mon Sep 17 00:00:00 2001 From: Evan Patterson Date: Sun, 18 Oct 2020 21:16:30 -0700 Subject: [PATCH 2/4] ENH: Composition of superparts in `incident` accessor of C-sets. --- src/categorical_algebra/CSetDataStructures.jl | 11 ++++++++++- test/categorical_algebra/CSetDataStructures.jl | 2 ++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/src/categorical_algebra/CSetDataStructures.jl b/src/categorical_algebra/CSetDataStructures.jl index 467a7e701..abab0e38d 100644 --- a/src/categorical_algebra/CSetDataStructures.jl +++ b/src/categorical_algebra/CSetDataStructures.jl @@ -355,7 +355,8 @@ end """ Get superparts incident to part in C-set. If the subpart is indexed, this takes constant time; otherwise, it takes linear -time. Both single and vectorized access are supported. +time. As with [`subpart`](@ref), both single and vectorized access, as well as +chained access, are supported. Note that when the subpart is indexed, this function returns a view of the underlying index, which should not be mutated. To ensure that a fresh copy is @@ -365,6 +366,14 @@ returned, regardless of whether indexing is enabled, set the keyword argument incident(acs::ACSet, part, name::Symbol; copy::Bool=false) = _incident(acs, part, Val(name); copy=copy) +function incident(acs::ACSet, part, names::AbstractVector{Symbol}; + copy::Bool=false) + # Don't need to pass `copy` because copy will be made regardless. + foldr(names, init=part) do name, part + reduce(vcat, incident(acs, part, name), init=Int[]) + end +end + @generated function _incident(acs::ACSet{CD,AD,Ts,Idxed}, part, ::Val{name}; copy::Bool=false) where {CD,AD,Ts,Idxed,name} if name ∈ CD.hom diff --git a/test/categorical_algebra/CSetDataStructures.jl b/test/categorical_algebra/CSetDataStructures.jl index f9d6a8d62..3759bdee2 100644 --- a/test/categorical_algebra/CSetDataStructures.jl +++ b/test/categorical_algebra/CSetDataStructures.jl @@ -148,6 +148,8 @@ set_subpart!(d, [4,5], :parent, 5) # Chained accessors. @test subpart(d, 3, [:parent, :parent]) == 5 @test subpart(d, 3, [:parent, :height]) == 10 +@test incident(d, 5, [:parent, :parent]) == [1,2,3,4,5] +@test incident(d, 10, [:parent, :height]) == [1,2,3] # Copying parts. d2 = Dendrogram{Int}() From 50d9b78c64f6ca65e84c624e3a7a5babc5ef1ce9 Mon Sep 17 00:00:00 2001 From: Evan Patterson Date: Sun, 18 Oct 2020 21:41:07 -0700 Subject: [PATCH 3/4] ENH: Allow GAT expressions in `subpart` and `incident`. --- src/categorical_algebra/CSetDataStructures.jl | 8 ++++++++ test/categorical_algebra/CSetDataStructures.jl | 9 ++++++++- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/src/categorical_algebra/CSetDataStructures.jl b/src/categorical_algebra/CSetDataStructures.jl index abab0e38d..f29ef15f2 100644 --- a/src/categorical_algebra/CSetDataStructures.jl +++ b/src/categorical_algebra/CSetDataStructures.jl @@ -12,6 +12,7 @@ using Compat: isnothing, only using PrettyTables: pretty_table using StructArrays +using ...Syntax: GATExpr, args using ...Theories: Schema, FreeSchema, dom, codom, codom_num, CatDesc, CatDescType, AttrDesc, AttrDescType, SchemaType using ...Present @@ -340,6 +341,11 @@ function subpart(acs::ACSet, part, names::AbstractVector{Symbol}) subpart(acs, part, name) end end +subpart(acs::ACSet, part, expr::GATExpr) = subpart(acs, part, subpart_name(expr)) + +subpart_name(expr::GATExpr{:generator}) = first(expr)::Symbol +subpart_name(expr::GATExpr{:id}) = Symbol[] +subpart_name(expr::GATExpr{:compose}) = mapreduce(subpart_name, vcat, args(expr)) @generated function _subpart(acs::ACSet{CD,AD,Ts}, ::Val{name}) where {CD,AD,Ts,name} @@ -373,6 +379,8 @@ function incident(acs::ACSet, part, names::AbstractVector{Symbol}; reduce(vcat, incident(acs, part, name), init=Int[]) end end +incident(acs::ACSet, part, expr::GATExpr; kw...) = + incident(acs, part, subpart_name(expr); kw...) @generated function _incident(acs::ACSet{CD,AD,Ts,Idxed}, part, ::Val{name}; copy::Bool=false) where {CD,AD,Ts,Idxed,name} diff --git a/test/categorical_algebra/CSetDataStructures.jl b/test/categorical_algebra/CSetDataStructures.jl index 3759bdee2..68e19dc25 100644 --- a/test/categorical_algebra/CSetDataStructures.jl +++ b/test/categorical_algebra/CSetDataStructures.jl @@ -1,7 +1,8 @@ module TestCSetDataStructures using Test -using Catlab: @present +using Catlab: @present, generator +using Catlab.Theories: compose, id using Catlab.CSetDataStructures # Discrete dynamical systems @@ -151,6 +152,12 @@ set_subpart!(d, [4,5], :parent, 5) @test incident(d, 5, [:parent, :parent]) == [1,2,3,4,5] @test incident(d, 10, [:parent, :height]) == [1,2,3] +X, parent, height = generator.(Ref(TheoryDendrogram), [:X, :parent, :height]) +@test subpart(d, 3, parent) == 4 +@test subpart(d, 3, compose(parent, height)) == 10 +@test subpart(d, 3, id(X)) == 3 +@test incident(d, 10, compose(parent, height)) == [1,2,3] + # Copying parts. d2 = Dendrogram{Int}() copy_parts!(d2, d, X=[4,5]) From 6bb97a75ed1350d363fcec6a12c8b8b268b4ca4d Mon Sep 17 00:00:00 2001 From: Evan Patterson Date: Mon, 19 Oct 2020 14:19:54 -0700 Subject: [PATCH 4/4] DOC: Order of morphism names in chained call of `incident`. --- src/categorical_algebra/CSetDataStructures.jl | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/categorical_algebra/CSetDataStructures.jl b/src/categorical_algebra/CSetDataStructures.jl index f29ef15f2..17aeb5473 100644 --- a/src/categorical_algebra/CSetDataStructures.jl +++ b/src/categorical_algebra/CSetDataStructures.jl @@ -362,7 +362,14 @@ end If the subpart is indexed, this takes constant time; otherwise, it takes linear time. As with [`subpart`](@ref), both single and vectorized access, as well as -chained access, are supported. +chained access, are supported. Note that sequences of morphisms are supplied in +the usual left-to-right order, so that + +``` +incident(g, x, [:src, :vattr]) +``` + +returns the list of all edges whose source vertex has vertex attribute `x`. Note that when the subpart is indexed, this function returns a view of the underlying index, which should not be mutated. To ensure that a fresh copy is