### DOC: Consistent indentation in vignette about labeled graphs.

 `@ -31,12 +31,12 @@ end` ``` ``` `# We need to tell Catlab how to convert our `LGraph` type into the normal `Graph` type by taking just the edges and vertices. This could be computed with Functorial Data Migration, but that is left for another sketch.` `to_graph(g::LGraph) = begin` ` h = Graphs.Graph(nparts(g,:V))` ` for e in edges(g)` ` add_edge!(h, g[e, :src], g[e,:tgt])` ` end` ` return h` ` h = Graphs.Graph(nparts(g,:V))` ` for e in edges(g)` ` add_edge!(h, g[e, :src], g[e,:tgt])` ` end` ` return h` `end` ``` ``` `# Graphviz doesn't automatically know how we want to draw the labels, so we have to explicitly provide code that converts them to colors on the vertices. Note that we aren't calling these colored graphs, because that would imply some connectivity constraints on which vertices are allowed to be colored with the same colors. These labels are arbitrary, but we use color to visually encode them.` `GraphvizGraphs.to_graphviz(g::LGraph; kw...) =` `@ -57,37 +57,31 @@ draw(G::LGraph) = to_graphviz(G, node_labels=true, edge_labels=true)` ``` ``` `# Now we can start making some `LGraph` instances.` `G = @acset LGraph begin` ` V = 4` ` E = 4` ` L = 4` ` src = [1,1,2,3]` ` tgt = [2,3,4,4]` ` label = [1,2,3,4]` ` V = 4` ` E = 4` ` L = 4` ` src = [1,1,2,3]` ` tgt = [2,3,4,4]` ` label = [1,2,3,4]` `end` ``` ``` `draw(G)` ``` ``` `# The graph `G` has a 1-1 map between vertices and labels. That isn't necessary. ` `H = @acset LGraph begin` ` V = 4` ` E = 4` ` L = 3` ` src = [1,1,2,3]` ` tgt = [2,3,4,4]` ` label = [1,2,2,3]` ` V = 4` ` E = 4` ` L = 3` ` src = [1,1,2,3]` ` tgt = [2,3,4,4]` ` label = [1,2,2,3]` `end` ``` ``` `draw(H)` ``` ``` ``` ``` `# We can look at some homomorphisms from G to H by their action on the labels or on the vertices.` `homsᵥ(G,H) = map(homomorphisms(G, H)) do α` ` components(α).V` `end` ``` ``` `homsₗ(G,H) = map(homomorphisms(G, H)) do α` ` components(α).L` `end` `homsᵥ(G,H) = map(α -> α[:V], homomorphisms(G, H))` `homsₗ(G,H) = map(α -> α[:L], homomorphisms(G, H))` ``` ``` `# αₗ: G→ H` `homsₗ(G,H)` `@ -100,23 +94,23 @@ homsᵥ(H,G)` ``` ``` `# We can build some bigger examples like A.` `A = @acset LGraph begin` ` V = 6` ` E = 7` ` L = 3` ` src = [1,1,2,3,2,5,4]` ` tgt = [2,3,4,4,5,6,6]` ` label = [1,2,2,3,2,3]` ` V = 6` ` E = 7` ` L = 3` ` src = [1,1,2,3,2,5,4]` ` tgt = [2,3,4,4,5,6,6]` ` label = [1,2,2,3,2,3]` `end` `draw(A)` ``` ``` `# and B.` `B = @acset LGraph begin` ` V = 6` ` E = 7` ` L = 4` ` src = [1,1,2,3,2,5,4]` ` tgt = [2,3,4,4,5,6,6]` ` label = [1,2,4,3,2,3]` ` V = 6` ` E = 7` ` L = 4` ` src = [1,1,2,3,2,5,4]` ` tgt = [2,3,4,4,5,6,6]` ` label = [1,2,4,3,2,3]` `end` `draw(B)` ``` ``` `@ -142,42 +136,44 @@ draw(apex(product(G,G)))` ``` ``` `# The graph above looks weirdly disconnected and probably wasn't what you expected to see as the product. When we compose with products, we often want to add the reflexive edges in order to get the expected notion of product.` `add_loops!(G::LGraph) = begin` ` for v in parts(G,:V)` ` add_edge!(G, v,v)` ` end` ` return G` ` for v in parts(G,:V)` ` add_edge!(G, v,v)` ` end` ` return G` `end ` `add_loops(G::LGraph) = add_loops!(copy(G))` ``` ``` `Gᵣ = add_loops(G)` `P = apex(product(Gᵣ, G))` `draw(apex(product(Gᵣ, G)))` ``` ``` `# We can look at the shape of commuting triangle, which is our favorite 3-vertex graph.` `T = @acset LGraph begin` ` V = 3` ` E = 3` ` L = 3` ` src = [1,1,2]` ` tgt = [2,3,3]` ` label = [1,2,3]` ` V = 3` ` E = 3` ` L = 3` ` src = [1,1,2]` ` tgt = [2,3,3]` ` label = [1,2,3]` `end` `Tᵣ = add_loops(T)` `draw(Tᵣ)` ``` ``` `E = @acset LGraph begin` ` V = 2` ` E = 1` ` L = 2` ` src = [1]` ` tgt = [2]` ` label = [1,2]` ` V = 2` ` E = 1` ` L = 2` ` src = [1]` ` tgt = [2]` ` label = [1,2]` `end` `Eᵣ = add_loops(E)` `draw(Eᵣ)` ``` ``` `# We can draw the product of the edge graph and the triangle graph to get the shape of a triangular prism. You can view this product as extruding `Tᵣ` along `Eᵣ`. Catlab provides a `ReflexiveGraph` as a type that handles these self-loops more intelligently than we are here. Graphviz struggles with the layout here because the product graph will include edges that are a step in both directions. This [blog post](https://www.algebraicjulia.org/blog/post/2021/04/cset-graphs-3/) does a good job explaining products in differnt kinds of graph categories.` `draw(apex(product(Tᵣ,Eᵣ)))` `components(legs(product(Tᵣ, Eᵣ))[1]).V |> collect` `legs(product(Tᵣ, Eᵣ))[1][:V] |> collect` ``` ``` `# Another limit is the pullback. If you have a cospan, which is a diagram of the shape `X ⟶ A ⟵ Y`, you can pull back one arrow along the other by solving a system of equations. ` `PB₂₂ = pullback(homomorphisms(Tᵣ,Eᵣ)[2],homomorphisms(Tᵣ,Eᵣ)[2]);` `draw(apex(PB₂₂))` `@ -194,10 +190,10 @@ homomorphisms(apex(PB₂₂), apex(product(Tᵣ,Tᵣ)), monic=true) |> length` ``` ``` `# In order to illustrate this we will be gluing triangles together to make a mesh. We start by defining the point `X`, which is the shape of the boundary along which we will glue and the morphism `ℓ₁`, which is the place in `T` that we consider as the boundary.` `X = @acset LGraph begin` ` E = 0` ` V = 1` ` L = 3` ` label=[2]` ` E = 0` ` V = 1` ` L = 3` ` label=[2]` `end` `ℓ₁ = ACSetTransformation(X,T, V=[2],L=1:3)` `draw(X)` `@ -209,9 +205,9 @@ draw(apex(P))` ``` ``` `# Now we want to repeat the gluing process to get a bigger mesh. So we are going to need a bigger interface.` `I = @acset LGraph begin` ` V = 2` ` L = 3` ` label = [1,1]` ` V = 2` ` L = 3` ` label = [1,1]` `end` `draw(I)` ``` ``` `@ -221,4 +217,4 @@ is_natural(ll)` `lr = ACSetTransformation(I, apex(P), V=[1,4], L =[1,3,2])` `is_natural(lr)` `P₂ = pushout(ll, lr);` `draw(apex(P₂))` `draw(apex(P₂))`