Skip to content

Commit

Permalink
ENH: Colimits of finite sets whose elements are meaningfully named.
Browse files Browse the repository at this point in the history
  • Loading branch information
epatters committed Nov 30, 2021
1 parent be45c93 commit cf6370f
Show file tree
Hide file tree
Showing 2 changed files with 47 additions and 20 deletions.
63 changes: 45 additions & 18 deletions src/categorical_algebra/FinSets.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1123,42 +1123,69 @@ end
#--------------------

""" Compute colimit of finite sets whose elements are meaningfully named.
This situation seems to be mathematically uninteresting but is practically
important. The colimit is computed by reduction to the skeleton of **FinSet**
(`FinSet{Int}`) and the names are assigned afterwards, following some reasonable
conventions and add tags where necessary to avoid name clashes.
"""
struct NamedColimit <: ColimitAlgorithm end

function colimit(::Type{<:Tuple{<:FinSet{S,T},<:FinFunction}}, d) where
{S, T<:Union{Symbol,AbstractString}}
function colimit(::Type{<:Tuple{<:FinSet{<:Any,T},<:FinFunction}}, d) where
{T <: Union{Symbol,AbstractString}}
colimit(d, NamedColimit())
end

function colimit(span::Multispan{<:FinSet{S,T}}, ::NamedColimit) where {S,T}
X = skeletize(apex(span), index=false)
feet_skel = map(skeletize, feet(span))
legs_skel = map((f, Y) -> skeletize(f, X, Y), legs(span), feet_skel)
span_skel = Multispan(dom(X), legs_skel)
colim_skel = colimit(span_skel)
function colimit(d::FixedShapeFreeDiagram{<:FinSet{<:Any,T},Hom},
alg::NamedColimit) where {T,Hom}
# Reducing to the case of bipartite free diagrams is a bit lazy, but at least
# using `SpecializeColimit` below should avoid some gross inefficiencies.
colimit(BipartiteFreeDiagram{FinSet{<:Any,T},Hom}(d), alg)
end
function colimit(d::BipartiteFreeDiagram{<:FinSet{<:Any,T}}, ::NamedColimit) where T
# Compute colimit of diagram in the skeleton of FinSet (`FinSet{Int}`).
# Note: no performance would be gained by using `DisjointSets{T}` from
# DataStructures.jl because it is just a wrapper around `IntDisjointSets` that
# internally builds the very same indices that we use below.
sets₁_skel = map(set -> skeletize(set, index=false), ob₁(d))
sets₂_skel = map(set -> skeletize(set, index=true), ob₂(d))
funcs = map(edges(d)) do e
skeletize(hom(d,e), sets₁_skel[src(d,e)], sets₂_skel[tgt(d,e)])
end
d_skel = BipartiteFreeDiagram{FinSetInt,eltype(funcs)}()
add_vertices₁!(d_skel, nv₁(d), ob₁=dom.(sets₁_skel))
add_vertices₂!(d_skel, nv₂(d), ob₂=dom.(sets₂_skel))
add_edges!(d_skel, src(d), tgt(d), hom=funcs)
colim_skel = colimit(d_skel, SpecializeColimit())

# Assign elements/names to the colimit set.
elems = Vector{T}(undef, length(apex(colim_skel)))
for (ι, Y) in zip(colim_skel, feet_skel)
for (ι, Y) in zip(colim_skel, sets₂_skel)
for i in dom(Y)
elems[ι(i)] = Y(i)
end
end
ι = compose(first(span_skel), first(colim_skel))
for i in dom(X)
elems[ι(i)] = X(i)
# The vector should already be filled, but to reduce arbitrariness we prefer
# names from the layer 1 sets whenever possible. For example, when computing a
# pushout, we prefer names from the apex of cospan to names from the feet.
for (u, X) in zip(vertices₁(d_skel), sets₁_skel)
e = first(incident(d_skel, u, :src))
f, ι = hom(d_skel, e), legs(colim_skel)[tgt(d_skel, e)]
for i in dom(X)
elems[ι(f(i))] = X(i)
end
end
# Eliminate clashes in provisional list of names.
unique_by_tagging!(elems)

Z = FinSet(elems)
ιs = map(colim_skel, feet_skel) do ι, Y
FinFunction(Dict(Y(i) => elems[ι(i)] for i in dom(Y)), Z)
ιs = map(colim_skel, sets₂_skel) do ι, Y
FinFunction(Dict(Y(i) => elems[ι(i)] for i in dom(Y)), FinSet(elems))
end
Colimit(span, Multicospan(Z, ιs))
Colimit(d, Multicospan(FinSet(elems), ιs))
end

function skeletize(set::FinSet; index::Bool=true)
# FIXME: Should support `unique_index`.
function skeletize(set::FinSet; index::Bool=false)
# FIXME: We should support `unique_index` and it should be used here.
FinDomFunction(collect(set), set, index=index)
end
function skeletize(f::FinFunction, X, Y)
Expand Down
4 changes: 2 additions & 2 deletions src/categorical_algebra/FreeDiagrams.jl
Original file line number Diff line number Diff line change
Expand Up @@ -458,7 +458,7 @@ function BipartiteFreeDiagram{Ob,Hom}(F::Functor{<:FinCat{Int}};
end
return d
end
BipartiteFreeDiagram(F::Functor{<:FinCat{Int},<:TypeCat{Ob,Hom}}; kw...) where {Ob,Hom} =
BipartiteFreeDiagram(F::Functor{<:FinCat{Int},<:Cat{Ob,Hom}}; kw...) where {Ob,Hom} =
BipartiteFreeDiagram{Ob,Hom}(F; kw...)

# Free diagrams
Expand Down Expand Up @@ -551,7 +551,7 @@ function FreeDiagram{Ob,Hom}(F::Functor{<:FinCat{Int}}) where {Ob,Hom}
diagram[:hom] = collect_hom(F)
diagram
end
FreeDiagram(F::Functor{<:FinCat{Int},<:TypeCat{Ob,Hom}}) where {Ob,Hom} =
FreeDiagram(F::Functor{<:FinCat{Int},<:Cat{Ob,Hom}}) where {Ob,Hom} =
FreeDiagram{Ob,Hom}(F)

(::Type{BFD})(diagram::FreeDiagram; kw...) where BFD <: BipartiteFreeDiagram =
Expand Down

0 comments on commit cf6370f

Please sign in to comment.