Skip to content

Commit

Permalink
Merge pull request #542 from epatters/print-fincats
Browse files Browse the repository at this point in the history
Basic `show` methods for categories, functors, and transformations
  • Loading branch information
epatters committed Oct 30, 2021
2 parents 0f03cde + 7726be3 commit 8b25944
Show file tree
Hide file tree
Showing 11 changed files with 183 additions and 60 deletions.
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

0 comments on commit 8b25944

Please sign in to comment.