From 22aed7339bd6568a02102a631c11d33dff30b3f4 Mon Sep 17 00:00:00 2001 From: Evan Patterson Date: Tue, 29 Sep 2020 18:12:46 -0700 Subject: [PATCH 1/5] ENH: Add accessor `tables` to C-set data structure. --- src/categorical_algebra/CSetDataStructures.jl | 12 ++++++++++-- src/categorical_algebra/CSets.jl | 2 +- test/categorical_algebra/CSetDataStructures.jl | 1 + 3 files changed, 12 insertions(+), 3 deletions(-) diff --git a/src/categorical_algebra/CSetDataStructures.jl b/src/categorical_algebra/CSetDataStructures.jl index 3409c42ef..4f3a5da96 100644 --- a/src/categorical_algebra/CSetDataStructures.jl +++ b/src/categorical_algebra/CSetDataStructures.jl @@ -3,8 +3,9 @@ module CSetDataStructures export AbstractACSet, ACSet, AbstractCSet, CSet, Schema, FreeSchema, AbstractACSetType, ACSetType, AbstractCSetType, CSetType, - nparts, has_part, subpart, has_subpart, incident, add_part!, add_parts!, - copy_parts!, set_subpart!, set_subparts!, disjoint_union + tables, nparts, has_part, subpart, has_subpart, incident, + add_part!, add_parts!, copy_parts!, set_subpart!, set_subparts!, + disjoint_union using Compat: isnothing, only using StructArrays @@ -221,6 +222,13 @@ end # Imperative interface ###################### +""" Tables defining a C-set. + +A named tuple with a table for each part type. To ensure consistency, do not +directly mutate these tables, especially when indexing is enabled! +""" +tables(acs::ACSet) = acs.tables + """ Number of parts of given type in a C-set. """ nparts(acs::ACSet, type) = length(acs.tables[type]) diff --git a/src/categorical_algebra/CSets.jl b/src/categorical_algebra/CSets.jl index ca9205d5b..0a6cd4b04 100644 --- a/src/categorical_algebra/CSets.jl +++ b/src/categorical_algebra/CSets.jl @@ -109,7 +109,7 @@ force(α::ACSetTransformation) = end end -finsets(X::ACSet) = map(table -> FinSet(length(table)), X.tables) +finsets(X::ACSet) = map(table -> FinSet(length(table)), tables(X)) # Limits and colimits ##################### diff --git a/test/categorical_algebra/CSetDataStructures.jl b/test/categorical_algebra/CSetDataStructures.jl index 454777858..43bfb7f6b 100644 --- a/test/categorical_algebra/CSetDataStructures.jl +++ b/test/categorical_algebra/CSetDataStructures.jl @@ -18,6 +18,7 @@ const DDS = CSetType(TheoryDDS, index=[:Φ]) @test DDS <: CSet dds = DDS() +@test keys(tables(dds)) == (:X,) @test keys(dds.indices) == (:Φ,) @test nparts(dds, :X) == 0 @test add_part!(dds, :X) == 1 From eefc8bff72e6df26a8ed0510b1c08fddbc85986c Mon Sep 17 00:00:00 2001 From: Evan Patterson Date: Tue, 29 Sep 2020 21:51:41 -0700 Subject: [PATCH 2/5] ENH: Distinguish attributed and non-attributed C-sets when printing. --- src/categorical_algebra/CSetDataStructures.jl | 12 +++++++----- test/categorical_algebra/CSetDataStructures.jl | 2 ++ 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/src/categorical_algebra/CSetDataStructures.jl b/src/categorical_algebra/CSetDataStructures.jl index 4f3a5da96..5933feb42 100644 --- a/src/categorical_algebra/CSetDataStructures.jl +++ b/src/categorical_algebra/CSetDataStructures.jl @@ -194,8 +194,9 @@ function Base.copy(acs::T) where T <: ACSet T(map(copy, acs.tables), map(copy, acs.indices)) end -function Base.show(io::IO, acs::AbstractACSet{CD,AD,Ts}) where {CD,AD,Ts} - println(io, "ACSet(") +function Base.show(io::IO, acs::T) where {CD,AD,Ts,T<:AbstractACSet{CD,AD,Ts}} + print(io, T <: AbstractCSet ? "CSet" : "ACSet") + println(io, "(") join(io, vcat( [ " $ob = 1:$(nparts(acs,ob))" for ob in CD.ob ], [ " $data = $(Ts.parameters[i])" for (i,data) in enumerate(AD.data) ], @@ -207,9 +208,10 @@ function Base.show(io::IO, acs::AbstractACSet{CD,AD,Ts}) where {CD,AD,Ts} print(io, ")") end -function Base.show(io::IO, ::MIME"text/plain", acs::ACSet) - println(io, "ACSet:") - for (name, table) in pairs(acs.tables) +function Base.show(io::IO, ::MIME"text/plain", acs::T) where {T<:AbstractACSet} + print(io, T <: AbstractCSet ? "CSet" : "ACSet") + println(io, ":") + for (name, table) in pairs(tables(acs)) print(io, " $name table with $(length(table)) elements") if !(eltype(table) <: EmptyTuple) print(io, ":\n ") diff --git a/test/categorical_algebra/CSetDataStructures.jl b/test/categorical_algebra/CSetDataStructures.jl index 43bfb7f6b..a382e6fb7 100644 --- a/test/categorical_algebra/CSetDataStructures.jl +++ b/test/categorical_algebra/CSetDataStructures.jl @@ -48,6 +48,7 @@ set_subpart!(dds, 1, :Φ, 1) # Pretty printing. s = sprint(show, dds) +@test startswith(s, "CSet") @test occursin("X = 1:3", s) @test occursin("Φ : X → X = ", s) @@ -110,6 +111,7 @@ du = disjoint_union(d, d2) # Pretty printing of data attributes. s = sprint(show, d) +@test startswith(s, "ACSet") @test occursin("R = Int64", s) @test occursin("height : X → R = ", s) From 6195eecc99f6416c5b8b2c801399f2a73ebfef47 Mon Sep 17 00:00:00 2001 From: Evan Patterson Date: Wed, 30 Sep 2020 10:47:50 -0700 Subject: [PATCH 3/5] ENH: Pretty print tables of C-set in plain text. Uses PrettyTables.jl. --- Project.toml | 2 ++ src/categorical_algebra/CSetDataStructures.jl | 14 +++++++++----- test/categorical_algebra/CSetDataStructures.jl | 5 +++-- 3 files changed, 14 insertions(+), 7 deletions(-) diff --git a/Project.toml b/Project.toml index e8a657b81..2b4ee5f76 100644 --- a/Project.toml +++ b/Project.toml @@ -20,6 +20,7 @@ MLStyle = "d8e11817-5142-5d16-987a-aa16d5891078" MetaGraphs = "626554b9-1ddb-594c-aa3c-2596fe9399a5" Parameters = "d96e819e-fc66-5662-9728-84c9c7592b0a" Pkg = "44cfe95a-1eb2-52ea-b672-e2afdf69b78f" +PrettyTables = "08abe8d2-0d0c-5749-adfa-8a2ac140af0d" Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" Reexport = "189a3867-3050-52da-a836-e630ba90ab69" Requires = "ae029012-a4dd-5104-9daa-d747884805df" @@ -41,6 +42,7 @@ LightXML = "0.8, 0.9" MLStyle = "0.4" MetaGraphs = "^0.6" Parameters = "0.11, 0.12" +PrettyTables = "0.9" Reexport = "0.2" Requires = "^1" StaticArrays = "0.12" diff --git a/src/categorical_algebra/CSetDataStructures.jl b/src/categorical_algebra/CSetDataStructures.jl index 5933feb42..dec553894 100644 --- a/src/categorical_algebra/CSetDataStructures.jl +++ b/src/categorical_algebra/CSetDataStructures.jl @@ -8,6 +8,8 @@ export AbstractACSet, ACSet, AbstractCSet, CSet, Schema, FreeSchema, disjoint_union using Compat: isnothing, only + +using PrettyTables: pretty_table using StructArrays using ...Theories: Schema, FreeSchema, dom, codom, @@ -210,14 +212,16 @@ end function Base.show(io::IO, ::MIME"text/plain", acs::T) where {T<:AbstractACSet} print(io, T <: AbstractCSet ? "CSet" : "ACSet") - println(io, ":") + print(io, " with types: ") + join(io, keys(tables(acs)), ", ") + println(io) for (name, table) in pairs(tables(acs)) - print(io, " $name table with $(length(table)) elements") + println(io, "• $name table with $(length(table)) elements") if !(eltype(table) <: EmptyTuple) - print(io, ":\n ") - join(io, map(string, table), "\n ") + # TODO: Set option `row_number_column_title=name` when next version of + # PrettyTables is released. + pretty_table(io, table, nosubheader=true, show_row_number=true) end - println(io) end end diff --git a/test/categorical_algebra/CSetDataStructures.jl b/test/categorical_algebra/CSetDataStructures.jl index a382e6fb7..afd8d7620 100644 --- a/test/categorical_algebra/CSetDataStructures.jl +++ b/test/categorical_algebra/CSetDataStructures.jl @@ -53,8 +53,8 @@ s = sprint(show, dds) @test occursin("Φ : X → X = ", s) s = sprint(show, MIME"text/plain"(), dds) +@test startswith(s, "CSet") @test occursin("X table with 3 elements", s) -@test occursin("(Φ = 1,)", s) # Error handling. @test_throws AssertionError add_part!(dds, :X, Φ=5) @@ -115,8 +115,9 @@ s = sprint(show, d) @test occursin("R = Int64", s) @test occursin("height : X → R = ", s) +show(stdout, MIME"text/plain"(), d) s = sprint(show, MIME"text/plain"(), d) -@test occursin("(parent = 4, height = 0)", s) +@test startswith(s, "ACSet") # Allow type inheritance for data attributes. d = Dendrogram{Number}() From 22c33195f0dddc11483187f32af07311fdcd2c7f Mon Sep 17 00:00:00 2001 From: Evan Patterson Date: Wed, 30 Sep 2020 14:34:49 -0700 Subject: [PATCH 4/5] ENH: Pretty print tables of C-set in HTML. Uses PrettyTables.jl. --- src/categorical_algebra/CSetDataStructures.jl | 24 +++++++++++++++++++ .../categorical_algebra/CSetDataStructures.jl | 6 ++++- 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/src/categorical_algebra/CSetDataStructures.jl b/src/categorical_algebra/CSetDataStructures.jl index dec553894..8178b39fb 100644 --- a/src/categorical_algebra/CSetDataStructures.jl +++ b/src/categorical_algebra/CSetDataStructures.jl @@ -225,6 +225,30 @@ function Base.show(io::IO, ::MIME"text/plain", acs::T) where {T<:AbstractACSet} end end +function Base.show(io::IO, ::MIME"text/html", acs::T) where {T<:AbstractACSet} + println(io, "
") + print(io, "") + print(io, T <: AbstractCSet ? "CSet" : "ACSet") + print(io, " with types: ") + join(io, keys(tables(acs)), ", ") + println(io, "") + println(io, "
    ") + for (name, table) in pairs(tables(acs)) + println(io, "
  • ") + print(io, "") + print(io, "$name table with $(length(table)) elements") + println(io, "") + if !(eltype(table) <: EmptyTuple) + # TODO: Set option `row_number_column_title`. See above. + pretty_table(io, table, backend=:html, standalone=false, + nosubheader=true, show_row_number=true) + end + println(io, "
  • ") + end + println(io, "
") + println(io, "
") +end + # Imperative interface ###################### diff --git a/test/categorical_algebra/CSetDataStructures.jl b/test/categorical_algebra/CSetDataStructures.jl index afd8d7620..fb7213635 100644 --- a/test/categorical_algebra/CSetDataStructures.jl +++ b/test/categorical_algebra/CSetDataStructures.jl @@ -56,6 +56,11 @@ s = sprint(show, MIME"text/plain"(), dds) @test startswith(s, "CSet") @test occursin("X table with 3 elements", s) +s = sprint(show, MIME"text/html"(), dds) +@test startswith(s, "
") +@test occursin("", s) +@test endswith(rstrip(s), "") + # Error handling. @test_throws AssertionError add_part!(dds, :X, Φ=5) @test subpart(dds, :Φ) == [1,1,1,0] @@ -115,7 +120,6 @@ s = sprint(show, d) @test occursin("R = Int64", s) @test occursin("height : X → R = ", s) -show(stdout, MIME"text/plain"(), d) s = sprint(show, MIME"text/plain"(), d) @test startswith(s, "ACSet") From edb94dbedc433a468878df4a784c6df62e0fe9a7 Mon Sep 17 00:00:00 2001 From: Evan Patterson Date: Wed, 30 Sep 2020 14:57:19 -0700 Subject: [PATCH 5/5] COSMETIC: More compact pretty printing of C-set tables. --- src/categorical_algebra/CSetDataStructures.jl | 29 +++++++------------ .../categorical_algebra/CSetDataStructures.jl | 2 +- 2 files changed, 12 insertions(+), 19 deletions(-) diff --git a/src/categorical_algebra/CSetDataStructures.jl b/src/categorical_algebra/CSetDataStructures.jl index 8178b39fb..26f6b1d11 100644 --- a/src/categorical_algebra/CSetDataStructures.jl +++ b/src/categorical_algebra/CSetDataStructures.jl @@ -212,15 +212,15 @@ end function Base.show(io::IO, ::MIME"text/plain", acs::T) where {T<:AbstractACSet} print(io, T <: AbstractCSet ? "CSet" : "ACSet") - print(io, " with types: ") - join(io, keys(tables(acs)), ", ") + print(io, " with elements ") + join(io, ["$ob = 1:$(nparts(acs,ob))" for ob in keys(tables(acs))], ", ") println(io) - for (name, table) in pairs(tables(acs)) - println(io, "• $name table with $(length(table)) elements") + for (ob, table) in pairs(tables(acs)) if !(eltype(table) <: EmptyTuple) # TODO: Set option `row_number_column_title=name` when next version of - # PrettyTables is released. - pretty_table(io, table, nosubheader=true, show_row_number=true) + # PrettyTables is released, instead of making new table. + table = StructArray((; ob => 1:nparts(acs,ob), fieldarrays(table)...)) + pretty_table(io, table, nosubheader=true) end end end @@ -229,23 +229,16 @@ function Base.show(io::IO, ::MIME"text/html", acs::T) where {T<:AbstractACSet} println(io, "
") print(io, "") print(io, T <: AbstractCSet ? "CSet" : "ACSet") - print(io, " with types: ") - join(io, keys(tables(acs)), ", ") + print(io, " with elements ") + join(io, ["$ob = 1:$(nparts(acs,ob))" for ob in keys(tables(acs))], ", ") println(io, "") - println(io, "
    ") - for (name, table) in pairs(tables(acs)) - println(io, "
  • ") - print(io, "") - print(io, "$name table with $(length(table)) elements") - println(io, "") + for (ob, table) in pairs(tables(acs)) if !(eltype(table) <: EmptyTuple) # TODO: Set option `row_number_column_title`. See above. - pretty_table(io, table, backend=:html, standalone=false, - nosubheader=true, show_row_number=true) + table = StructArray((; ob => 1:nparts(acs,ob), fieldarrays(table)...)) + pretty_table(io, table, backend=:html, standalone=false, nosubheader=true) end - println(io, "
  • ") end - println(io, "
") println(io, "
") end diff --git a/test/categorical_algebra/CSetDataStructures.jl b/test/categorical_algebra/CSetDataStructures.jl index fb7213635..30c1f75fa 100644 --- a/test/categorical_algebra/CSetDataStructures.jl +++ b/test/categorical_algebra/CSetDataStructures.jl @@ -54,7 +54,7 @@ s = sprint(show, dds) s = sprint(show, MIME"text/plain"(), dds) @test startswith(s, "CSet") -@test occursin("X table with 3 elements", s) +@test occursin("X = 1:3", s) s = sprint(show, MIME"text/html"(), dds) @test startswith(s, "
")