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

Making the code more julian #18

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
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
2 changes: 2 additions & 0 deletions Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ authors = ["benjaminmerlinbumpus <[email protected]>"]
version = "0.2.0"

[deps]
ACSets = "227ef7b5-1206-438b-ac65-934d6da304b8"
AMD = "14f7f29c-3bd6-536c-9a0b-7339e30b5a3e"
AbstractTrees = "1520ce14-60c1-5f80-bbc7-55ef81b5835c"
Catlab = "134e5e36-593f-5add-ad60-77f754baafbe"
Expand All @@ -13,6 +14,7 @@ LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e"
MLStyle = "d8e11817-5142-5d16-987a-aa16d5891078"
Metis = "2679e427-3c69-5b7f-982b-ece356f1e94b"
PartialFunctions = "570af359-4316-4cb7-8c74-252c00c2016b"
Reexport = "189a3867-3050-52da-a836-e630ba90ab69"
SparseArrays = "2f01184e-e22b-5df5-ae63-d93ebab69eaf"

[compat]
Expand Down
105 changes: 105 additions & 0 deletions docs/literate/coloring.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
using ACSets, ACSets.ADTs
using Catlab
# using StructuredDecompositions

# specify a problem
struct Coloring <: AbstractFunctor
n::Int
f::Function
function Coloring(n::Int)
new(n, g -> homomorphisms(g, K(n)))
end
end

# coloring is a representable functor Graph(-, K(n))
(c::Coloring)(x::Graph) = FinSet(c.f(x))
(c::Coloring)(f::ACSetTransformation) = FinFunction(λ -> f ∘ λ, c(codom(f)), c(dom(f)))
# notice the contravariance in action

# specify a decomposition

macro graph(head, body)
v = 0;
parsebody = @λ begin
Expr(:block, args...) => parsebody.(args)
Expr(:call, :E, s, t) => begin
v = maximum([v, s, t])
Expr(:call, :E, s, t)
end
:: LineNumberNode => nothing
s => s
end
edges = parsebody(body)
# result = quote
# construct(Graph, acsetspec(:Graph,
quote
$(Expr(:tuple, [Expr(:call, :V) for i in v])...)
$(edges...)
end
# ))
# end
end

G1 = construct(Graph, acsetspec(:(Graph),
quote
V(); V(); V(); V(); V();
E(src=1,tgt=2)
E(src=2,tgt=3)
E(src=3,tgt=4)
E(src=3,tgt=5)
E(src=4,tgt=5)
end))

macro see(head, body)
dump(body)
end

# Bag 1
G1 = @acset Graph begin
V=5; E=5
src=[1,2,3,3,4]
tgt=[2,3,4,5,5]
end
# A 12
G12 = @acset Graph begin V=1; end
# Bag 2
G2 = @acset Graph begin
V=7
E=12
src=[1,2,3,4,5,6,1,7,7,7,7,2]
tgt=[2,3,4,5,6,1,5,1,6,5,3,4]
end
# A 23
G23 = @acset Graph begin
V=3
E=2
src=[1,2]
tgt=[2,3]
end
# Bag 3
G3 = @acset Graph begin
V=7
E=6
src=[1,2,3,5,4,4]
tgt=[3,3,4,4,6,7]
end
# A 31
G31 = @acset Graph begin V=2; end

shape = @acset Graph begin
V=3; E=3
src=[1,2,3]
tgt=[2,3,1]
end

Γ=FinDomFunctor(
Dict(1=>G1,2=>G2,3=>G3,4=>G12,5=>G23,6=>G31),
Dict(1=>ACSetTransformation(G12, G1, V=[1]),
2=>ACSetTransformation(G12, G2, V=[6]),
3=>ACSetTransformation(G23, G2, V=[1,6,5]), # error
4=>ACSetTransformation(G23, G3, V=[6,4,5]), # error
5=>ACSetTransformation(G31, G3, V=[1,2]),
6=>ACSetTransformation(G31, G3, V=[3,4])
),
∫(shape));

115 changes: 64 additions & 51 deletions src/DecidingSheaves.jl
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,11 @@ using ..FunctorUtils
using Catlab
using Catlab.CategoricalAlgebra

struct DecompError <: Exception end

Base.showerror(io, e::DecompError) = print(io, "Expecting Codecomposition but received decomposition")

# TODO FinSet(Int) assumed
"""
Filtering algorithm.
Note: we are assuming that we only know how to work with FinSet(Int) !
Expand All @@ -22,66 +27,74 @@ OUTPUT: a structured decomposition obtained by replacing the span de in d
by the span obtained by projecting the pullback of de (i.e. taking images)
"""
function adhesion_filter(tup::Tuple, d::StructuredDecomposition)
if d.decomp_type == Decomposition
error("expecting ", CoDecomposition, " given ", Decomposition)
end
# d_csp is the cospan dx₁ -> de <- dx₂ corresp to some edge e = x₁x₂ in shape(d)
(csp, d_csp) = tup #unpack the tuple
# the pullback cone dx₁ <-l₁-- p --l₂ --> dx₂ with legs l₁ and l₂
p_cone = pullback(d_csp)
p_legs = legs(p_cone)
#for each leg lᵢ : p → xᵢ of the pullback cone,
#compute its image ιᵢ : im lᵢ → dxᵢ
imgs = map( f -> legs(image(f))[1], p_legs)
#now get the new desired cospan;
#i.e. im l₁ --ι₁--> dx₁ --l₁--> de <--l₂--dx₂ <--ι₂-- im l₂
new_d_csp = map(t -> compose(t...), zip(imgs, d_csp))
#get the domain of d
d_dom = dom(d.diagram)
#now make the new decomposition, call it δ
#start with the object map δ₀
function ob_replace(x)
if x == dom(d_dom, csp[1])
dom(new_d_csp[1])
elseif x == dom(d_dom, csp[2])
dom(new_d_csp[2])
else
ob_map(d,x)
d.decomp_type == Decomposition && throw(DecompError)
# d_cospan is the cospan dx₁ -> de <- dx₂ corresp to some edge e = x₁x₂ in shape(d)
(cospan, d_cospan) = tup #unpack the tuple
# the pullback cone dx₁ <-l₁-- p --l₂ --> dx₂ with legs l₁ and l₂
p_legs = (legs∘pullback)(d_cospan)
# for each leg lᵢ : p → xᵢ of the pullback cone,
# compute its image ιᵢ : im lᵢ → dxᵢ
imgs = (first∘legs∘image).(p_legs)
# now get the new desired cospan;
# i.e. im l₁ --ι₁--> dx₁ --l₁--> de <--l₂-- dx₂ <--ι₂-- im l₂
new_d_cospan = map(t -> compose(t...), zip(imgs, d_cospan))
# get the domain of d
d_dom = dom(d.diagram)

# TODO is there ever a time when "out" has length > 1
function ob_replace(x)
out = dom.(new_d_cospan[x .== dom.(Ref(d_dom), cospan)])
!isempty(out) ? first(out) : ob_map(d, x)
end

function mor_replace(f)
out = new_d_cospan[f .== cospan]
!isempty(out) ? first(out) : hom_map(d, f)
end
end
δ₀ = Dict( x => ob_replace(x) for x ∈ ob_generators(d_dom) )
#now do the same thing with the morphism map
function mor_replace(f)
if f == csp[1]
return new_d_csp[1]
elseif f == csp[2]
return new_d_csp[2]
else
return hom_map(d,f)
end
end
δ₁ = Dict( f => mor_replace(f) for f ∈ hom_generators(d_dom) )
StrDecomp(d.decomp_shape, FinDomFunctor(δ₀, δ₁, d.domain), d.decomp_type)

# now make the new decomposition, call it δ
# start with the object map δ₀
δ₀ = Dict( x => ob_replace(x) for x ∈ ob_generators(d_dom) )
# now do the same thing with the morphism map
δ₁ = Dict( f => mor_replace(f) for f ∈ hom_generators(d_dom) )

StrDecomp(d.decomp_shape, FinDomFunctor(δ₀, δ₁, d.domain), d.decomp_type)
end

#for some reason PartialFunctions is giving me an error here
#and we have to explicitly Curry adhesion_filter..
# for some reason PartialFunctions is giving me an error here
# and we have to explicitly Curry adhesion_filter..
adhesion_filter(tup::Tuple) = d -> adhesion_filter(tup, d)

"""Solve the decision problem encoded by a sheaf.
export adhesion_filter

""" decide_sheaf_tree_shape(f,
d::StructuredDecomposition,
solution_space_decomp::StructuredDecomposition)

Solve the decision problem encoded by a sheaf.
The algorithm is as follows:
compute on each bag (optionally, if the decomposition of the solution space
is already known, then it can be passed as an argument),
compute composites on edges,
project back down to bags
answer (providing a witness)
1. compute on each bag. Optionally, if the decomposition of the solution space
is already known, then it can be passed as an argument.
2. compute composites on edges
3. project back down to bags
4. answer (providing a witness)
"no" if there is an empty bag;
"yes" otherwise.

"""
function decide_sheaf_tree_shape(f, d::StructuredDecomposition, solution_space_decomp::StructuredDecomposition = 𝐃(f, d, CoDecomposition))
witness = foldl(∘, map(adhesion_filter, adhesionSpans(solution_space_decomp, true)))(solution_space_decomp)
(foldr(&, map( !isempty, bags(witness))), witness)
function decide_sheaf_tree_shape(f,
d::StructuredDecomposition,
solution_space_decomp::StructuredDecomposition = 𝐃(f, d, CoDecomposition))

# witness = foldl(∘, map(adhesion_filter, adhesionSpans(solution_space_decomp, true)))(solution_space_decomp)

@info "Structured Space Decomposition: $solution_space_decomp"
@info "Adhesion Spans: $(adhesionSpans(solution_space_decomp, true))"
witness =
∘((adhesion_filter.(adhesionSpans(solution_space_decomp, true)))...)(solution_space_decomp)

(all(!isempty, bags(witness)), witness)
end


end
end
Loading
Loading