Skip to content

Commit

Permalink
factoring morphisms into composites in C-Set as well as slice cats.
Browse files Browse the repository at this point in the history
update for HomSearch split
  • Loading branch information
Kris Brown committed Sep 5, 2023
1 parent 05cfe2a commit f150aa8
Show file tree
Hide file tree
Showing 5 changed files with 151 additions and 2 deletions.
4 changes: 3 additions & 1 deletion src/categorical_algebra/CSets.jl
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@ import ...Theories: ob, hom, dom, codom, compose, ⋅, id,
using ..FreeDiagrams, ..Limits, ..Subobjects, ..Sets, ..FinSets, ..FinCats
using ..FinSets: VarFunction, LooseVarFunction, IdentityFunction, VarSet
import ..Limits: limit, colimit, universal
import ...Theories: compose, , id, meet, , join, , top, ⊤, bottom, ⊥
using ..FreeDiagrams, ..Limits, ..Subobjects, ..FinSets, ..FinCats
import ..Limits: limit, colimit, universal, factorize
import ..Subobjects: Subobject, implies, , subtract, \, negate, ¬, non, ~
import ..Sets: SetOb, SetFunction, TypeSet
using ..Sets
Expand Down Expand Up @@ -666,7 +669,6 @@ end
@cartesian_monoidal_instance ACSet ACSetTransformation
@cocartesian_monoidal_instance ACSet ACSetTransformation


# Limits and colimits
#####################

Expand Down
54 changes: 54 additions & 0 deletions src/categorical_algebra/HomSearch.jl
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ using ...Theories, ..CSets, ..FinSets, ..FreeDiagrams, ..Subobjects
using ...Graphs.BasicGraphs
using ..CSets: map_components
using ACSets.DenseACSets: attrtype_type, delete_subobj!
import ..Limits: factorize

using Random
using CompTime
Expand Down Expand Up @@ -471,6 +472,59 @@ function escape_assignment_lhs(expr)
end



# Factorization
###############

""" factorize(s::Span; initial=Dict(), single=true, kw...)
Factor a morphism f: A->C by finding a morphism h: B → C such that f=g⋅h.
B
g ↗ ↘ h = ?
A ⟶ C
f
This function assumes that the general form of factorizing involves creating an
"initial" dict for homomorphism search. In some categories this may not be the
case, which would mean factorize_constraints should actually return a dictionary
that gets passed as kwargs to homomorphism search.
"""
function factorize(s::Span; initial=Dict(), single::Bool=true, kw...)
f, g = s
init = factorize_constraints(f,g; initial=initial)
if isnothing(init) return single ? nothing : typeof(f)[] end
search = single ? homomorphism : homomorphisms
search(codom(g), codom(f); initial=NamedTuple(init), kw...)
end

"""
Use the data of f:A->C and g:A->B to initialize search for Hom(B,C)
if f(a) = c, then g(a) must equal c.
"""
function factorize_constraints(f::ACSetTransformation,
g::ACSetTransformation;
initial=Dict())
dom(f) == dom(g) || error("f and g are not a span: $jf \n$jg")
S = acset_schema(dom(f))
res = Dict{Symbol, Dict{Int,Int}}()
for o in ob(S)
init = haskey(initial, o) ? initial[o] : Dict{Int,Int}()
for (a, g_a) in enumerate(collect(g[o]))
f_a = f[o](a)
if haskey(init, g_a)
if init[g_a] != f_a
return nothing

Check warning on line 517 in src/categorical_algebra/HomSearch.jl

View check run for this annotation

Codecov / codecov/patch

src/categorical_algebra/HomSearch.jl#L516-L517

Added lines #L516 - L517 were not covered by tests
end
else
init[g_a] = f_a
end
end
res[o] = init
end
return res
end

# Maximum Common C-Set
######################

Expand Down
53 changes: 52 additions & 1 deletion src/categorical_algebra/Slices.jl
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ using ...Theories: ThCategory
import ...Theories: dom, codom, compose, id
import ..Limits: limit, colimit, universal
import ..FinSets: force

import ..CSets: is_natural, components
import ..HomSearch: factorize_constraints, homomorphism, homomorphisms, factorize
"""
The data of the object of a slice category (say, some category C sliced over an
object X in Ob(C)) is the data of a homomorphism in Hom(A,X) for some ob A.
Expand Down Expand Up @@ -86,6 +87,9 @@ function slice_diagram(f::FreeDiagram)::FreeDiagram
FreeDiagram(obs,homs)
end

factorize_constraints(f::SliceHom,g::SliceHom; initial=Dict()) =
factorize_constraints(f.f,g.f; initial=initial)

"""
Convert a limit problem in the slice category to a limit problem of the
underlying category.
Expand Down Expand Up @@ -132,4 +136,51 @@ function universal(lim::SliceLimit, sp::Multispan)
return SliceHom(apx, apx2, u)
end

is_natural(x::SliceHom) = is_natural(x.f)
components(x::SliceHom) = components(x.f)
Base.getindex::SliceHom, c) = x.f[c]

Check warning on line 141 in src/categorical_algebra/Slices.jl

View check run for this annotation

Codecov / codecov/patch

src/categorical_algebra/Slices.jl#L139-L141

Added lines #L139 - L141 were not covered by tests

"""
This could be made more efficient as a constraint *during* homomorphism finding.
This would require implementing a new constraint to homomorphism search that
restricts the codomain for each part of A, i.e. ∀ a ∈ A: h(a) ∈ g⁻¹(f(a)).
"""
function homomorphisms(X::Slice,Y::Slice; kw...)
map(filter(h->force(X.slice)==force(compose(h,Y.slice)),
homomorphisms(dom(X), dom(Y); kw...)) ) do h
SliceHom(X, Y, h)
end |> collect
end

"""
Because the constraint isn't incorporated into the search process, we cannot
stop early.
"""
function homomorphism(X::Slice,Y::Slice; kw...)
hs = homomorphisms(X,Y; kw...)
return isempty(hs) ? nothing : first(hs)
end

"""
Factorizing a cospan is equivalent to looking for a slice morphism. f->g
B
h = ? ↗ ↘ g
A ⟶ C
f
"""
function factorize(s::Cospan; initial=Dict(), single::Bool=true, kw...)
f, g = Slice.(s)
search = single ? homomorphism : homomorphisms
res = search(f, g; initial=NamedTuple(initial), kw...)
if isnothing(res)
return nothing

Check warning on line 178 in src/categorical_algebra/Slices.jl

View check run for this annotation

Codecov / codecov/patch

src/categorical_algebra/Slices.jl#L178

Added line #L178 was not covered by tests
else
return [x.f for x in res]
end
end



end # module
14 changes: 14 additions & 0 deletions test/categorical_algebra/HomSearch.jl
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,20 @@ end
@test_throws ErrorException @acset_transformation g h begin V = [4,3,2,1]; E = [1,2,3,4] end


# Factorizing morphisms
#----------------------

p2, p3 = path_graph(Graph, 2), path_graph(Graph, 3)
loop = apex(terminal(Graph))
f = ACSetTransformation(Graph(2), p3; V=[2,1])
g1 = ACSetTransformation(Graph(2), p2; V=[1,2])
g2 = ACSetTransformation(Graph(2), p2; V=[2,1])
@test isnothing(factorize(Span(f, g1)))
@test length(factorize(Span(f, g2); single=false)) == 1
f2 = homomorphism(Graph(2), loop)
@test isnothing(factorize(Span(f2, id(Graph(2))); monic=true))
@test factorize(Span(f2, id(Graph(2)))) == f2

# Enumeration of subobjects
###########################

Expand Down
28 changes: 28 additions & 0 deletions test/categorical_algebra/Slices.jl
Original file line number Diff line number Diff line change
Expand Up @@ -59,4 +59,32 @@ slice_dia = FreeDiagram{Slice,SliceHom}(Multispan(A, [f, g]))
clim = colimit(slice_dia)
@test is_isomorphic(dom(apex(clim)), d)


# Factorizing morphisms (morally same tests as in CSets)
#-------------------------------------------------------
p2G, p3G = [path_graph(Graph, x) for x in [3,5]]
p2, p3 = [Slice(homomorphism(p, two)) for p in [p2G,p3G]] # ⊚→□→⊚ and ⊚→□→⊚□→⊚
loop = Slice(id(two)) # ⊚ ↔ □
g2G = Slice(ACSetTransformation(Graph(2), two; V=[1,1])) # ⊚ ⊚
f = SliceHom(g2G, p3, ACSetTransformation(Graph(2), p3G; V=[3,1]))
g1 = SliceHom(g2G, p2, CSetTransformation(Graph(2), p2G; V=[1,3]))
g2 = SliceHom(g2G, p2, CSetTransformation(Graph(2), p2G; V=[3,1]))
@test isnothing(factorize(Span(f, g1)))
@test length(factorize(Span(f, g2); single=false)) == 1
f2 = homomorphism(g2G, loop)
@test isnothing(factorize(Span(f2, id(g2G)); monic=true))
@test factorize(Span(f2, id(g2G))) == f2

# Factorize C-set morphisms where the second one is known
#--------------------------------------------------------

A = path_graph(Graph, 2)
B = @acset Graph begin V=4; E=3; src=[1,1,3]; tgt=[2,4,4] end
C = @acset Graph begin V=2; E=2; src=1; tgt=2 end

f = ACSetTransformation(A, C; V=[1,2], E=[1])
g = ACSetTransformation(B, C; V=[1,2,1,2], E=[1,2,1])

@test length(factorize(Cospan(f,g); single=false)) == 2

end # module

0 comments on commit f150aa8

Please sign in to comment.