Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Basic show methods for categories, functors, and transformations #542

Merged
merged 5 commits into from
Oct 30, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion src/categorical_algebra/CSetDataStructures.jl
Original file line number Diff line number Diff line change
Expand Up @@ -604,8 +604,9 @@ function Base.show(io::IO, acs::T) where {S,T<:StructACSet{S}}
s = SchemaDesc(S)
if get(io, :compact, false)
print(io, nameof(T))
print(io, ": ")
print(io, " {")
join(io, ("$ob = $(nparts(acs,ob))" for ob in s.obs), ", ")
print(io, "}")
else
print(io, T)
println(io, ":")
Expand Down
16 changes: 16 additions & 0 deletions src/categorical_algebra/CSets.jl
Original file line number Diff line number Diff line change
Expand Up @@ -253,6 +253,14 @@ type_components(α::TightACSetTransformation{S}) where S =
map_components(f, α::TightACSetTransformation) =
TightACSetTransformation(map(f, components(α)), dom(α), codom(α))

function Base.show(io::IO, α::TightACSetTransformation)
print(io, "ACSetTransformation(")
show(io, components(α))
print(io, ", ")
Categories.show_domains(io, α)
print(io, ")")
end

""" Loose transformation between attributed C-sets.

See [`ACSetTranformation`](@ref) for the distinction between tight and loose.
Expand Down Expand Up @@ -308,6 +316,14 @@ function Base.getindex(α::LooseACSetTransformation, c::Symbol)
end
end

function Base.show(io::IO, α::LooseACSetTransformation)
print(io, "ACSetTransformation(")
show(io, merge(components(α), type_components(α)))
print(io, ", ")
Categories.show_domains(io, α)
print(io, ")")
end

function is_natural(α::ACSetTransformation{S}) where {S}
X, Y = dom(α), codom(α)
for (f, c, d) in flatten((zip(hom(S), dom(S), codom(S)),
Expand Down
23 changes: 23 additions & 0 deletions src/categorical_algebra/Categories.jl
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,9 @@ TypeCat(Ob::Type, Hom::Type) = TypeCat{Ob,Hom}()
#ob(::TypeCat{Ob,Hom}, x) where {Ob,Hom} = convert(Ob, x)
#hom(::TypeCat{Ob,Hom}, f) where {Ob,Hom} = convert(Hom, f)

Base.show(io::IO, ::TypeCat{Ob,Hom}) where {Ob,Hom} =
print(io, "TypeCat($Ob, $Hom)")

# Functors
##########

Expand Down Expand Up @@ -119,6 +122,26 @@ codom(F::IdentityFunctor) = F.dom
do_ob_map(F::IdentityFunctor, x) = ob(F.dom, x)
do_hom_map(F::IdentityFunctor, f) = hom(F.dom, f)

function Base.show(io::IO, F::IdentityFunctor)
print(io, "id(")
show_domains(io, F, codomain=false)
print(io, ")")
end

show_type_constructor(io::IO, ::Type{<:Functor}) = print(io, "Functor")

function show_domains(io::IO, f; codomain::Bool=true, recurse::Bool=true)
if get(io, :hide_domains, false)
print(io, "…")
else
show(IOContext(io, :compact=>true, :hide_domains=>!recurse), dom(f))
if codomain
print(io, ", ")
show(IOContext(io, :compact=>true, :hide_domains=>!recurse), codom(f))
end
end
end

# Instances
#----------

Expand Down
75 changes: 56 additions & 19 deletions src/categorical_algebra/FinCats.jl
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,14 @@ graph(C::FinCatGraph) = C.graph
ob_generators(C::FinCatGraph) = vertices(graph(C))
hom_generators(C::FinCatGraph) = edges(graph(C))

function Base.show(io::IO, C::FinCatGraph)
print(io, "FinCat(")
show(io, graph(C))
print(io, ", [")
join(io, equations(C), ", ")
print(io, "])")
end

# Paths in graphs
#----------------

Expand Down Expand Up @@ -114,6 +122,12 @@ function Base.vcat(p1::Path, p2::Path)
Path(vcat(edges(p1), edges(p2)), src(p1), tgt(p2))
end

function Base.show(io::IO, path::Path)
print(io, "Path(")
show(io, edges(path))
print(io, ": $(src(path)) → $(tgt(path)))")
end

""" Abstract type for category whose morphisms are paths in a graph.

(Or equivalence classes of paths in a graph, but we compute with
Expand Down Expand Up @@ -152,6 +166,12 @@ FinCatGraph(g::HasGraph) = FreeCatGraph(g)

is_free(::FreeCatGraph) = true

function Base.show(io::IO, C::FreeCatGraph)
print(io, "FinCat(")
show(io, graph(C))
print(io, ")")
end

# Category on graph with equations
#---------------------------------

Expand Down Expand Up @@ -228,6 +248,12 @@ hom(C::FinCatPresentation{Schema}, f::GATExpr) =
gat_typeof(f) ∈ (:Hom, :Attr) ? f :
error("Expression $f is not a morphism or attribute")

function Base.show(io::IO, C::FinCatPresentation)
print(io, "FinCat(")
show(io, presentation(C))
print(io, ")")
end

# Functors
##########

Expand Down Expand Up @@ -256,6 +282,9 @@ end
(F::FinDomFunctor)(expr::ObExpr) = ob_map(F, expr)
(F::FinDomFunctor)(expr::HomExpr) = hom_map(F, expr)

Categories.show_type_constructor(io::IO, ::Type{<:FinDomFunctor}) =
print(io, "FinDomFunctor")

""" Is the purported functor on a presented category functorial?

This function checks that functor preserves domains and codomains. When
Expand Down Expand Up @@ -291,6 +320,9 @@ FinFunctor(ob_map, hom_map, dom::FinCat, codom::FinCat) =
FinFunctor(ob_map, hom_map, dom::Presentation, codom::Presentation) =
FinDomFunctor(ob_map, hom_map, FinCat(dom), FinCat(codom))

Categories.show_type_constructor(io::IO, ::Type{<:FinFunctor}) =
print(io, "FinFunctor")

# Mapping-based functors
#-----------------------

Expand Down Expand Up @@ -328,25 +360,23 @@ functor_key(C::FinCat, expr::GATExpr) = head(expr) == :generator ?
Categories.do_ob_map(F::FinDomFunctorMap, x) = F.ob_map[x]
Categories.do_hom_map(F::FinDomFunctorMap, f) = F.hom_map[f]

collect_ob(F::FinDomFunctorMap) = values(F.ob_map)
collect_hom(F::FinDomFunctorMap) = values(F.hom_map)

function Categories.do_compose(F::FinDomFunctorMap, G::FinDomFunctorMap)
FinDomFunctorMap(mapvals(x -> ob_map(G, x), F.ob_map),
mapvals(f -> hom_map(G, f), F.hom_map), dom(F), codom(G))
end

""" Functor object and morphism maps given as vectors.
"""
const FinDomFunctorVector{Dom<:FinCat,Codom<:Cat,
ObMap<:AbstractVector,HomMap<:AbstractVector} =
FinDomFunctorMap{Dom,Codom,ObMap,HomMap}

collect_ob(F::FinDomFunctorVector) = F.ob_map
collect_hom(F::FinDomFunctorVector) = F.hom_map

""" Functor with object and morphism maps given as dictionaries.
"""
const FinDomFunctorDict{Dom<:FinCat,Codom<:Cat,
ObMap<:AbstractDict,HomMap<:AbstractDict} =
FinDomFunctorMap{Dom,Codom,ObMap,HomMap}
function Base.show(io::IO, F::T) where T <: FinDomFunctorMap
Categories.show_type_constructor(io, T); print(io, "(")
show(io, F.ob_map)
print(io, ", ")
show(io, F.hom_map)
print(io, ", ")
Categories.show_domains(io, F)
print(io, ")")
end

# Natural transformations
#########################
Expand Down Expand Up @@ -431,11 +461,8 @@ transformation_key(C::FinCat, x) = x
transformation_key(C::FinCat, expr::GATExpr) = head(expr) == :generator ?
first(expr) : error("Natural transformation must be defined on generators")

component(α::FinTransformationMap{C,D,F,G,Comp}, c::Integer) where
{C,D,F,G,Comp<:AbstractVector} = α.components[c]
component(α::FinTransformationMap{C,D,F,G,Comp}, c::Key) where
{Key,C,D,F,G,Comp<:AbstractDict{Key}} = α.components[c]
component(α::FinTransformationMap, expr::GATExpr) =
component(α::FinTransformationMap, x) = α.components[x]
component(α::FinTransformationMap, expr::GATExpr{:generator}) =
component(α, first(expr))

function Categories.do_compose(α::FinTransformationMap, β::FinTransformation)
Expand All @@ -458,6 +485,16 @@ function Categories.do_composeH(α::FinTransformationMap, H::Functor)
compose(F, H), compose(G, H))
end

function Base.show(io::IO, α::FinTransformationMap)
print(io, "FinTransformation(")
show(io, components(α))
print(io, ", ")
Categories.show_domains(io, α, recurse=false)
print(io, ", ")
Categories.show_domains(io, dom(α))
print(io, ")")
end

# Dict utilities
################

Expand Down
45 changes: 36 additions & 9 deletions src/categorical_algebra/FinSets.jl
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,11 @@ Base.iterate(set::FinSetCollection, args...) = iterate(set.collection, args...)
Base.length(set::FinSetCollection) = length(set.collection)
Base.in(set::FinSetCollection, elem) = in(elem, set.collection)

Base.show(io::IO, set::FinSetCollection) = print(io, "FinSet($(set.collection)")
function Base.show(io::IO, set::FinSetCollection)
print(io, "FinSet(")
show(io, set.collection)
print(io, ")")
end

""" Finite set whose elements are rows of a table.

Expand All @@ -86,7 +90,11 @@ FinSet(nt::NamedTuple) = TabularSet(nt)
Base.iterate(set::TabularSet, args...) = iterate(Tables.rows(set.table), args...)
Base.length(set::TabularSet) = Tables.rowcount(set.table)

Base.show(io::IO, set::TabularSet) = print(io, "TabularSet($(set.table))")
function Base.show(io::IO, set::TabularSet)
print(io, "TabularSet(")
show(io, set.table)
print(io, ")")
end

function Base.show(io::IO, ::MIME"text/plain", set::TabularSet{T}) where T
print(io, "$(length(set))-element TabularSet{$T}")
Expand All @@ -96,6 +104,14 @@ function Base.show(io::IO, ::MIME"text/plain", set::TabularSet{T}) where T
end
end

function Base.show(io::IO, ::MIME"text/html", set::TabularSet)
println(io, "<div class=\"tabular-set\">")
println(io, "$(length(set))-element TabularSet")
PrettyTables.pretty_table(io, set.table, backend=Val(:html), standalone=false,
nosubheader=true)
println(io, "</div>")
end

# Discrete categories
#--------------------

Expand Down Expand Up @@ -128,6 +144,9 @@ FinDomFunctor(ob_map, ::Nothing, dom::DiscreteCat, codom::Cat) =

hom_map(F::FinDomFunctor{<:DiscreteCat}, x) = id(codom(F), ob_map(F, x))

Base.show(io::IO, C::DiscreteCat{Int,FinSetInt}) =
print(io, "FinCat($(length(C.set)))")

# Finite functions
##################

Expand Down Expand Up @@ -158,7 +177,8 @@ function FinFunction(f::AbstractVector{Int}, args...; index=false)
end
end

Sets.show_type(io::IO, ::Type{<:FinFunction}) = print(io, "FinFunction")
Sets.show_type_constructor(io::IO, ::Type{<:FinFunction}) =
print(io, "FinFunction")

""" Function out of a finite set.

Expand All @@ -180,7 +200,8 @@ function FinDomFunction(f::AbstractVector, args...; index=false)
end
end

Sets.show_type(io::IO, ::Type{<:FinDomFunction}) = print(io, "FinDomFunction")
Sets.show_type_constructor(io::IO, ::Type{<:FinDomFunction}) =
print(io, "FinDomFunction")

""" Function in **Set** represented by a vector.

Expand All @@ -206,8 +227,11 @@ dom(f::FinDomFunctionVector) = FinSet(length(f.func))

(f::FinDomFunctionVector)(x) = f.func[x]

Base.show(io::IO, f::FinDomFunctionVector) =
print(io, "FinDomFunction($(f.func), $(dom(f)), $(codom(f)))")
function Base.show(io::IO, f::FinDomFunctionVector)
print(io, "FinDomFunction($(f.func), ")
Sets.show_domains(io, f)
print(io, ")")
end

""" Force evaluation of lazy function or relation.
"""
Expand All @@ -232,7 +256,7 @@ Sets.do_compose(f::FinFunctionVector, g::FinDomFunctionVector) =
@cocartesian_monoidal_instance FinSet FinFunction

Ob(C::FinCat{Int}) = FinSet(length(ob_generators(C)))
Ob(F::FinCats.FinDomFunctorVector) = FinDomFunction(F.ob_map, Ob(codom(F)))
Ob(F::Functor{<:FinCat{Int}}) = FinDomFunction(collect_ob(F), Ob(codom(F)))

# Indexed functions
#------------------
Expand Down Expand Up @@ -268,8 +292,11 @@ Base.:(==)(f::Union{FinDomFunctionVector,IndexedFinDomFunction},
# Ignore index when comparing for equality.
f.func == g.func && codom(f) == codom(g)

Base.show(io::IO, f::IndexedFinDomFunction) =
print(io, "FinDomFunction($(f.func), $(dom(f)), $(codom(f)), index=true)")
function Base.show(io::IO, f::IndexedFinDomFunction)
print(io, "FinDomFunction($(f.func), ")
Sets.show_domains(io, f)
print(io, ", index=true)")
end

dom(f::IndexedFinDomFunction) = FinSet(length(f.func))
force(f::IndexedFinDomFunction) = f
Expand Down
14 changes: 9 additions & 5 deletions src/categorical_algebra/Sets.jl
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ using FunctionWrappers: FunctionWrapper
using ...GAT, ..Categories, ..FreeDiagrams, ..Limits
using ...Theories: Category
import ...Theories: Ob, dom, codom, id, compose, ⋅, ∘
import ..Categories: show_type_constructor, show_domains
import ..Limits: limit, universal

# Data types
Expand Down Expand Up @@ -52,7 +53,7 @@ abstract type SetFunction{Dom <: SetOb, Codom <: SetOb} end
SetFunction(f::Function, args...) = SetFunctionCallable(f, args...)
SetFunction(::typeof(identity), args...) = SetFunctionIdentity(args...)

show_type(io::IO, ::Type{<:SetFunction}) = print(io, "SetFunction")
show_type_constructor(io::IO, ::Type{<:SetFunction}) = print(io, "SetFunction")

""" Function in **Set** defined by a callable Julia object.
"""
Expand All @@ -75,8 +76,10 @@ end

function Base.show(io::IO, f::F) where F <: SetFunctionCallable
func = f.func.obj[] # Deference FunctionWrapper
show_type(io, F)
print(io, "($(nameof(func)), $(f.dom), $(f.codom))")
show_type_constructor(io, F)
print(io, "($(nameof(func)), ")
show_domains(io, f)
print(io, ")")
end

""" Identity function in **Set**.
Expand All @@ -95,8 +98,9 @@ codom(f::SetFunctionIdentity) = f.dom
(f::SetFunctionIdentity)(x) = x

function Base.show(io::IO, f::F) where F <: SetFunctionIdentity
show_type(io, F)
print(io, "(identity, $(f.dom))")
print(io, "id(")
show_domains(io, f, codomain=false)
print(io, ")")
end

""" Function in **Set** taking a constant value.
Expand Down
Loading