Skip to content

Commit a3452fc

Browse files
committed
diag in C-Set categories, currying, products of FinCats
1 parent feafb7b commit a3452fc

File tree

6 files changed

+444
-56
lines changed

6 files changed

+444
-56
lines changed

src/categorical_algebra/CSets.jl

Lines changed: 154 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,12 @@ export ACSetTransformation, CSetTransformation,
88
isomorphism, isomorphisms, is_isomorphic,
99
generate_json_acset, parse_json_acset, read_json_acset, write_json_acset,
1010
generate_json_acset_schema, parse_json_acset_schema,
11-
read_json_acset_schema, write_json_acset_schema, acset_schema_json_schema
11+
read_json_acset_schema, write_json_acset_schema, acset_schema_json_schema,
12+
uncurry, curry, ACSetCat
1213

1314
using Base.Iterators: flatten
1415
using Base.Meta: quot
15-
using DataStructures: OrderedDict
16+
using DataStructures: OrderedDict, DefaultDict
1617
using StructEquality
1718
import JSON
1819
using Reexport
@@ -34,7 +35,7 @@ import ..FinCats: FinDomFunctor, components, is_natural, FinCatGraph, FinCatPres
3435
using ...Graphs
3536
using ..FinCats: normalize, Path
3637
import ..FinSets: FinSet, FinFunction, FinDomFunction, force, predicate, is_monic, is_epic
37-
import ..FinCats: FinDomFunctor, components, is_natural
38+
import ..FinCats: FinDomFunctor, components, is_natural, FinTransformationMap, FinDomFunctorMap
3839

3940
# Sets interop
4041
##############
@@ -137,17 +138,24 @@ end
137138
const ACSetDomCat = FinCats.FinCatPresentation{
138139
Symbol, Union{FreeSchema.Ob,FreeSchema.AttrType},
139140
Union{FreeSchema.Hom,FreeSchema.Attr,FreeSchema.AttrType}}
141+
const FinSetCat = TypeCat{SetOb,FinDomFunction{Int}}
140142

141-
""" Wrapper type to interpret attributed C-set as a functor.
142-
"""
143143
@struct_hash_equal struct ACSetFunctor{ACS<:ACSet} <:
144-
Functor{ACSetDomCat,TypeCat{SetOb,FinDomFunction{Int}}}
144+
Functor{ACSetDomCat,FinSetCat}
145145
acset::ACS
146+
eqs::Vector{Pair}
147+
end
148+
FinDomFunctor(X::ACSet; eqs=Pair[]) = ACSetFunctor(X, eqs)
149+
150+
function dom(F::ACSetFunctor)
151+
p = Presentation(F.acset)
152+
for (l,r) in F.eqs
153+
add_equation!(p, l, r)
154+
end
155+
FinCat(p)
146156
end
147-
FinDomFunctor(X::ACSet) = ACSetFunctor(X)
148157

149-
dom(F::ACSetFunctor) = FinCat(Presentation(F.acset))
150-
codom(F::ACSetFunctor) = TypeCat{SetOb,FinDomFunction{Int}}()
158+
codom(F::ACSetFunctor) = FinSetCat()
151159

152160
Categories.do_ob_map(F::ACSetFunctor, x) = SetOb(F.acset, functor_key(x))
153161
Categories.do_hom_map(F::ACSetFunctor, f) = SetFunction(F.acset, functor_key(f))
@@ -168,13 +176,19 @@ function (::Type{ACS})(F::FinDomFunctor) where ACS <: ACSet
168176
return X
169177
end
170178

179+
function (C::Type{ACS})(F::FinTransformationMap) where ACS <: ACSet
180+
Cd, CCd = C(dom(F)), C(codom(F))
181+
return CSetTransformation(Cd, CCd; components(F)...)
182+
end
183+
184+
171185
""" Copy parts from a set-valued `FinDomFunctor` to an `ACSet`.
172186
"""
173187
function ACSetInterface.copy_parts!(X::ACSet, F::FinDomFunctor)
174188
pres = presentation(dom(F))
175189
added = Dict(Iterators.map(generators(pres, :Ob)) do c
176190
c = nameof(c)
177-
c => add_parts!(X, c, length(ob_map(F, c)::FinSet{Int}))
191+
c => add_parts!(X, c, length(ob_map(F, Symbol(c))::FinSet{Int}))
178192
end)
179193
for f in generators(pres, :Hom)
180194
dom_parts, codom_parts = added[nameof(dom(f))], added[nameof(codom(f))]
@@ -237,6 +251,11 @@ end
237251
components::ACSetTransformation) = α.components
238252
force::ACSetTransformation) = map_components(force, α)
239253

254+
FinTransformationMap(f::ACSetTransformation; eqs=Pair[]) =
255+
FinTransformationMap(components(f),
256+
FinDomFunctor(dom(f); eqs=eqs),
257+
FinDomFunctor(codom(f); eqs=eqs))
258+
240259
""" Transformation between C-sets.
241260
242261
Recall that a C-set homomorphism is a natural transformation: a transformation
@@ -779,12 +798,12 @@ particular length (e.g. 1 means a generator must map onto another generator, not
779798
a composite).
780799
"""
781800
function homomorphisms(gX::FinCatGraph, gY::FinCatGraph; n_max::Int=3,
782-
monic=false, iso=false,init_obs=nothing,
801+
monic_obs=false, epic_obs=false, init_obs=nothing,
783802
init_homs=nothing, hom_lens=nothing)
784803

785-
y_pths = Dict(map(collect(enumerate_paths_cyclic(gY.graph; n_max=n_max))) do (k,v)
804+
y_pths = map(collect(enumerate_paths_cyclic(gY.graph; n_max=n_max))) do (k,v)
786805
k => unique(h->normalize(gY, Path(h, k[1], k[2])), v)
787-
end)
806+
end |> Dict
788807

789808
yGrph = Graph(nv(gY.graph))
790809

@@ -800,38 +819,26 @@ function homomorphisms(gX::FinCatGraph, gY::FinCatGraph; n_max::Int=3,
800819
res = []
801820
kwargs = Dict{Symbol,Any}(:initial=>(V=Dict([
802821
i=>v for (i, v) in enumerate(init_obs) if !isnothing(v)]),))
803-
if iso kwargs[:iso] = [:V]
804-
elseif monic kwargs[:monic] = [:V]
805-
end
822+
if monic_obs kwargs[:monic] = [:V] end
823+
if epic_obs error("depends on is_surjective PR") end
806824
for h in homomorphisms(gX.graph, yGrph; kwargs...)
807825
om = collect(h[:V])
808-
809826
pths = map(zip(collect(h[:E]), init_homs, hom_lens)) do (e, ih, hl)
810827
p = y_pths[(src(yGrph,e),tgt(yGrph,e))]
811828
# Apply init_homs and hom_lens constraints to possible paths
812829
if !isnothing(hl)
813-
filter!(z->length(z)==hl, p)
830+
p = filter(z->length(z)==hl, p)
814831
end
815832
if !isnothing(ih)
816-
maybe_e = findfirst(x->(x isa Vector ? x : edges(x)) == e, p)
817-
if isnothing(maybe_e)
818-
p = []
819-
else
820-
p = [p[maybe_e]]
821-
end
833+
p = filter(x->is_hom_equal(gY,x,ih), p)
822834
end
823835
return p
824836
end
825-
837+
# This should be done in a backtracking style
826838
for combo in Iterators.product(pths...) # pick a path for each edge in X
827839
hm = map(enumerate(combo)) do (ei,z)
828840
isempty(z) ? id(gY, om[src(gX.graph,ei)]) : z
829841
end
830-
if (monic || iso) && ((length(hm) != length(unique(hm))) || any(isempty,combo))
831-
continue
832-
elseif iso
833-
error("how to check hom map is surjective?")
834-
end
835842
F = FinFunctor((V=om, E=hm), gX, gY)
836843
if is_functorial(F; check_equations=true)
837844
push!(res, F)
@@ -1196,6 +1203,123 @@ end
11961203
end...))
11971204
end
11981205

1206+
1207+
# Tensor-hom adjunction (currying of diagrams in C-Set)
1208+
#######################################################
1209+
const ACSetCat{S} = TypeCat{S, ACSetTransformation}
1210+
1211+
""" uncurry(d::FinFunctor{D, ACSetCat{S}}) where {D,S}
1212+
Undoing currying on objects of a functor category. C->D->Set ==> (CxD)->Set
1213+
"""
1214+
function uncurry(d::FinFunctor{D, ACSetCat{S}}) where {D,S}
1215+
shapelim = product(FinCatPresentation[dom(d), FinCat(Presentation(S))])
1216+
shape_ind, part_ind = legs(shapelim)
1217+
asl = apex(shapelim)
1218+
omap = Dict(map(ob_generators(asl)) do o
1219+
x = ob_map(shape_ind, o)
1220+
y = ob_map(part_ind, o)
1221+
o => FinSet(ob_map(d, x), Symbol(y))
1222+
end)
1223+
1224+
hmap = Dict(map(hom_generators(asl)) do o
1225+
x = hom_map(shape_ind, o)
1226+
y = hom_map(part_ind, o)
1227+
if first(typeof(x).parameters) == :id
1228+
o => FinFunction(ob_map(d, only(x.args)), Symbol(y))
1229+
elseif first(typeof(y).parameters) == :id
1230+
o => hom_map(d, x)[Symbol(only(y.args))]
1231+
else
1232+
error("x $x $(typeof(x)) y $y $(typeof(y))")
1233+
end
1234+
end)
1235+
1236+
FinDomFunctor(omap,hmap,asl,FinSetCat())
1237+
end
1238+
1239+
"""
1240+
Currying a FinFunctor into Set: (CxD)->Set ==> C->D->Set
1241+
1242+
An example FinDomFunctor (in the original curried format) is required.
1243+
"""
1244+
function curry(d::FinDomFunctor{D1, FinSetCat},
1245+
old_d::FinDomFunctor{D2, ACSetCat{S}}) where {D1,D2,S}
1246+
# Recover schema for d as a product, not just the apex
1247+
shapelim = product([dom(old_d), FinCat(Presentation(S))])
1248+
asl = apex(shapelim)
1249+
shape_ind, part_ind = legs(shapelim)
1250+
1251+
cset_type = typeof(first(old_d.ob_map)[2])
1252+
omap = Dict(map(ob_generators(dom(old_d))) do o
1253+
x = Base.invokelatest(cset_type)
1254+
for o_ in ob_generators(asl)
1255+
if ob_map(shape_ind, o_) == o
1256+
add_parts!(x, Symbol(ob_map(part_ind, o_)), length(ob_map(d, o_)))
1257+
end
1258+
end
1259+
for h in hom_generators(asl)
1260+
h_ = hom_map(shape_ind, h)
1261+
if h_ == id(o)
1262+
set_subpart!(x, Symbol(hom_map(part_ind, h)), collect(hom_map(d, h)))
1263+
end
1264+
end
1265+
o => x
1266+
end)
1267+
hmap = Dict(map(hom_generators(dom(old_d))) do h
1268+
comps = Dict()
1269+
for h_ in hom_generators(asl)
1270+
if hom_map(shape_ind, h_) == h
1271+
comps[Symbol(only(hom_map(part_ind, h_).args))] = hom_map(d, h_)
1272+
end
1273+
end
1274+
dom_, codom_ = [omap[get(h)] for get in [dom, codom]]
1275+
h => ACSetTransformation(dom_,codom_; comps...)
1276+
end)
1277+
FinDomFunctor(omap,hmap,dom(old_d),ACSetCat{S}())
1278+
end
1279+
1280+
""" uncurry(d::FinFunctor{D, ACSetCat{S}}) where {D,S}
1281+
Uncurrying on morphisms of a functor category with an ACSetCat as codom
1282+
"""
1283+
function uncurry::FinTransformationMap{D, ACSetCat{S}}) where {D,S}
1284+
cur_d, cur_cd = uncurry.([dom(ϕ), codom(ϕ)])
1285+
shapelim = product([dom(dom(ϕ)), FinCat(Presentation(S))])
1286+
shape_ind, part_ind = legs(shapelim)
1287+
comps = Dict(map(ob_generators(apex(shapelim))) do o
1288+
oshape, opart = Symbol(shape_ind(o)), Symbol(part_ind(o))
1289+
Symbol(o) => components(ϕ)[oshape][opart]
1290+
end)
1291+
FinTransformationMap(comps,cur_d,cur_cd)
1292+
end
1293+
1294+
""" curry(d::FinTransformationMap, old_d::FinTransformationMap{D, ACSetCat{S}}) where {D, S}
1295+
Currying on morphisms of a functor category with an ACSetCat as codom
1296+
An example FinDomFunctor (in the original curried format) is required.
1297+
"""
1298+
function curry(d::FinTransformationMap,
1299+
old_d::FinDomFunctor{D, ACSetCat{S}}
1300+
) where {D, S}
1301+
# Recover schema for d as a product, not just the apex
1302+
shapelim = product([dom(old_d), FinCat(Presentation(S))])
1303+
shape_ind, part_ind = legs(shapelim)
1304+
1305+
αcomps = Dict(o => DefaultDict{Symbol,Vector{Int}}(()->Int[])
1306+
for o in Symbol.(ob_generators(dom(old_d))))
1307+
for o in (ob_generators(apex(shapelim)))
1308+
dic = αcomps[Symbol(ob_map(shape_ind, o))]
1309+
dic[Symbol(ob_map(part_ind, o))] = collect(components(d)[Symbol(o)])
1310+
end
1311+
1312+
uc_d, uc_cd = [curry(get(d), old_d) for get in [dom, codom]]
1313+
1314+
α = Dict(map(collect(αcomps)) do (o, comps)
1315+
o => ACSetTransformation(ob_map(uc_d, o),
1316+
ob_map(uc_cd, o); comps...)
1317+
end)
1318+
1319+
1320+
FinTransformationMap(α, uc_d, uc_cd)
1321+
end
1322+
11991323
# ACSet serialization
12001324
#####################
12011325

src/categorical_algebra/Diagrams.jl

Lines changed: 39 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,12 @@ import ...Theories: dom, codom, id, compose, ⋅, ∘, munit
1010
using ...Theories: ThCategory, composeH
1111
import ..Categories: ob_map, hom_map, op, co
1212
using ..FinCats, ..FreeDiagrams
13-
using ..FinCats: mapvals
13+
using ..FinCats: mapvals, FinDomFunctorMap, FinTransformationMap
1414
import ..FinCats: force, collect_ob, collect_hom
1515
import ..Limits: limit, colimit, universal
16+
using ..CSets: curry, uncurry, ACSetTransformation
1617
import ..CSets: homomorphisms, is_natural
18+
using ...CSetDataStructures: AnonACSetType
1719
# Data types
1820
############
1921

@@ -230,28 +232,53 @@ function compose(f::DiagramHom{T}, F::Functor; kw...) where T
230232
compose(f.precomposed_diagram, F; kw...))
231233
end
232234

235+
const ACSetCat{S} = TypeCat{S, ACSetTransformation}
236+
237+
"""
238+
Search for natural transformations between Functors F,G: C->(D-Set) by
239+
translating the problem into natural transformations in CxD->Set.
240+
"""
241+
function homomorphisms(x::FinDomFunctorMap{D,ACSetCat{S}},
242+
y::FinDomFunctorMap{D,ACSetCat{S}}; kwargs...) where {D,S}
243+
cx, cy = uncurry.([x,y])
244+
dt = AnonACSetType(presentation(dom(cx)))
245+
[curry(FinTransformationMap(h), x) for h in homomorphisms(dt(cx), dt(cy); kwargs...)]
246+
end
247+
248+
function homomorphism(x::FinDomFunctorMap{D,ACSetCat{S}},
249+
y::FinDomFunctorMap{D,ACSetCat{S}}; kwargs...) where {D,S}
250+
cx, cy = uncurry.([x,y])
251+
dt = AnonACSetType(presentation(dom(cx)))
252+
h = homomorphism(dt(cx), dt(cy); kwargs...)
253+
return isnothing(h) ? nothing : curry(FinTransformationMap(h), x)
254+
end
255+
256+
233257
"""
234258
Diagram morphisms by first finding shape maps and then, for each,
235259
finding a diagram map.
236260
"""
237-
function homomorphisms(X::Diagram{T}, Y::Diagram{T}; n_max::Int=3, monic=false,
238-
iso=false,init_obs=nothing,init_homs=nothing,
239-
hom_lens=nothing) where T
240-
fs = homomorphisms(shape(X),shape(Y))
261+
function homomorphisms(X::Diagram{T}, Y::Diagram{T}; n_max::Int=3,
262+
monic_obs=false, epic_obs=false,
263+
init_obs=nothing,init_homs=nothing,
264+
hom_lens=nothing, diag_kws=(;)) where T
265+
fs = homomorphisms(shape(X),shape(Y); init_obs=init_obs, monic_obs=monic_obs,
266+
epic_obs=epic_obs, init_homs=init_homs, n_max=n_max,
267+
hom_lens=hom_lens)
241268

242269
res = []
243-
for f in fs
244-
codom(f) == shape(Y) || error("SHOULD COMPOSE")
270+
for shapemap in fs
245271
if T == id
246-
hargs = [diagram(X), f diagram(Y)]
272+
hargs = [diagram(X), shapemap diagram(Y)]
247273
elseif T == op
248-
hargs = [f diagram(Y),diagram(X)]
274+
hargs = [shapemap diagram(Y), diagram(X)]
249275
else
250276
error("$T not supported")
251277
end
252-
nts = homomorphisms(hargs...)
253-
for nt in nts
254-
push!(res, DiagramHom{T}(f, nt.components, X, Y))
278+
tt = typeof(hargs[1]).parameters[2]
279+
natural_transformations = homomorphisms(hargs...; diag_kws...)
280+
for nt in natural_transformations
281+
push!(res, DiagramHom{T}(shapemap, nt.components, X, Y))
255282
end
256283
end
257284
return res

0 commit comments

Comments
 (0)