{ "cells": [ { "cell_type": "markdown", "id": "8c4b0397", "metadata": {}, "source": [ "# Computational Category Theoretic Rewriting \n", "### Kris Brown, Evan Patterson, Tyler Hanks, and James Fairbanks\n", "This notebook accompanies the above paper, showing the code behind the scenes for each of the main figures.\n", "# WARNING\n", "This was written prior to the development of [AlgebraicRewriting.jl](https://github.com/AlgebraicJulia/AlgebraicRewriting.jl) which is the recommended way of performing rewriting within [AlgebraicJulia](https://www.algebraicjulia.org/).\n" ] }, { "cell_type": "code", "execution_count": 1, "id": "df50d84b", "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "\u001b[32m\u001b[1m Activating\u001b[22m\u001b[39m project at `~/code/Computational-Category-Theoretic-Rewriting`\n" ] } ], "source": [ "using Pkg; Pkg.activate(\"/Users/ksb/code/Computational-Category-Theoretic-Rewriting\")\n", "#using Revise, Catlab.CategoricalAlgebra, Catlab.Graphs, Catlab.Present, Catlab.Graphics, Catlab.Theories\n", "#import Catlab\n", "#import Catlab.CategoricalAlgebra.CatElements\n", "#using Catlab.CategoricalAlgebra.FinCats: FinCatGraphEq\n", "#using CombinatorialSpaces\n", "#using CombinatorialSpaces.SimplicialSets: get_edge!\n", "#import AlgebraicPetri\n" ] }, { "cell_type": "code", "execution_count": 2, "id": "5c112b63", "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "┌ Info: Precompiling CombinatorialSpaces [b1c52339-7909-45ad-8b6a-6e388f7c67f2]\n", "└ @ Base loading.jl:1423\n", "┌ Info: Precompiling AlgebraicPetri [4f99eebe-17bf-4e98-b6a1-2c4f205a959b]\n", "└ @ Base loading.jl:1423\n" ] } ], "source": [ "using Base.Iterators\n", "using CairoMakie, GeometryBasics\n", "using CombinatorialSpaces\n", "import AlgebraicPetri\n", "using CombinatorialSpaces.SimplicialSets: get_edge!\n", "using Catlab.CategoricalAlgebra, Catlab.Graphs, Catlab.Present, Catlab.Graphics, Catlab.Theories\n", "using Catlab.CategoricalAlgebra.FinCats: FinCatGraphEq\n", "import Catlab \n", "pres = Catlab.CategoricalAlgebra.CatElements.presentation; # abbreviate long name" ] }, { "cell_type": "markdown", "id": "39592b20", "metadata": {}, "source": [ "## Figure 1" ] }, { "cell_type": "code", "execution_count": 3, "id": "145b2896", "metadata": {}, "outputs": [ { "data": { "image/svg+xml": [ "\n", "\n", "\n", "\n", "\n", "\n", "G\n", "\n", "\n", "\n", "n1\n", "\n", "1\n", "\n", "\n", "\n", "n2\n", "\n", "2\n", "\n", "\n", "\n", "n1->n2\n", "\n", "\n", "\n", "\n", "\n", "n3\n", "\n", "3\n", "\n", "\n", "\n", "n2->n3\n", "\n", "\n", "\n", "\n", "\n", "n2->n3\n", "\n", "\n", "\n", "\n", "\n" ], "text/plain": [ "Catlab.Graphics.Graphviz.Graph(\"G\", true, \"dot\", Catlab.Graphics.Graphviz.Statement[Catlab.Graphics.Graphviz.Node(\"n1\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"1\")), Catlab.Graphics.Graphviz.Node(\"n2\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"2\")), Catlab.Graphics.Graphviz.Node(\"n3\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"3\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n1\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n2\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}()), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n2\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n3\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}()), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n2\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n3\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}())], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:rankdir => \"LR\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:height => \"0.05\", :margin => \"0\", :shape => \"circle\", :width => \"0.05\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:arrowsize => \"0.5\"))" ] }, "execution_count": 3, "metadata": {}, "output_type": "execute_result" } ], "source": [ "G = @acset Graph begin \n", " V=3; E=3; \n", " src=[1,2,2]; \n", " tgt=[2,3,3] \n", "end\n", "to_graphviz(G; node_labels=true)" ] }, { "cell_type": "markdown", "id": "e3f6f05d", "metadata": {}, "source": [ "## Figure 2\n", "The declaration of a new $\\mathcal{C}$-set schema and an example instance of that schema." ] }, { "cell_type": "code", "execution_count": 4, "id": "0df883a6", "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "SSet with elements V = 1:4, E = 1:5, T = 1:2\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
Esrctgt
114
212
313
424
534
\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
Td1d2d3
1124
2135
\n", "
\n" ], "text/plain": [ "SSet with elements V = 1:4, E = 1:5, T = 1:2\n", "┌───┬─────┬─────┐\n", "│\u001b[1m E \u001b[0m│\u001b[1m src \u001b[0m│\u001b[1m tgt \u001b[0m│\n", "├───┼─────┼─────┤\n", "│ 1 │ 1 │ 4 │\n", "│ 2 │ 1 │ 2 │\n", "│ 3 │ 1 │ 3 │\n", "│ 4 │ 2 │ 4 │\n", "│ 5 │ 3 │ 4 │\n", "└───┴─────┴─────┘\n", "┌───┬────┬────┬────┐\n", "│\u001b[1m T \u001b[0m│\u001b[1m d1 \u001b[0m│\u001b[1m d2 \u001b[0m│\u001b[1m d3 \u001b[0m│\n", "├───┼────┼────┼────┤\n", "│ 1 │ 1 │ 2 │ 4 │\n", "│ 2 │ 1 │ 3 │ 5 │\n", "└───┴────┴────┴────┘\n" ] }, "execution_count": 4, "metadata": {}, "output_type": "execute_result" } ], "source": [ "@present ThSemisimplicialSet(FreeSchema) begin\n", " (V,E,T) :: Ob\n", " (d1,d2,d3)::Hom(T,E)\n", " (src,tgt) :: Hom(E,V)\n", " compose(d1, src) == compose(d2, src)\n", " compose(d1, tgt) == compose(d3, tgt)\n", " compose(d2, tgt) == compose(d3, src)\n", "end\n", "@acset_type SSet(ThSemisimplicialSet)\n", "\n", "quadrangle = @acset SSet begin \n", " T=2; E=5; V=4\n", " d1=[1,1]\n", " d2=[2,3]\n", " d3=[4,5]\n", " src=[1,1,1,2,3]\n", " tgt=[4,2,3,4,4]\n", "end " ] }, { "cell_type": "markdown", "id": "03365ec8", "metadata": {}, "source": [ "Thanks to Andrew Baas, we can visualize SSets with the following function:" ] }, { "cell_type": "code", "execution_count": 5, "id": "df31a019", "metadata": {}, "outputs": [ { "data": { "image/png": "iVBORw0KGgoAAAANSUhEUgAAAyAAAAJYCAIAAAAVFBUnAAAABmJLR0QA/wD/AP+gvaeTAAAfZklEQVR4nO3dX2id9f3A8efMBCmmNiRS/xT7S8loKSVoSJAOqWsLVi8kN7saIqgbwq5U7IUXXnSMedPhym7GvJChxbsJLchk1a5gbypJ8V9bKi1J52q3GktDIsU09vwuzoxpmj/nPOf7/H+98MIcn5zz+CeeN5/PN0mtXq9HAACE85OsbwAAoGwEFgBAYAILACAwgQUAEJjAAgAITGABAAQmsAAAAhNYAACBCSwAgMAEFgBAYAILACAwgQUAEJjAAgAITGABAATWkfUNLOHAgQMff/xxX19f1jcCABBNTEw8+OCDL7zwQvOfkscJ1scffzwxMZHoS9y4cWN6ejrRlwAy991333333XdZ3wWQrOnp6Rs3biT6EhMTEx9//HFLn5LHCVZfX19fX9++ffuSe4m5ubnLly/fd999yb0EkLmpqakoitatW5f1jQAJ+uqrr9avX9/RkWDSxGiSPE6wAAAKTWABAAQmsAAAAhNYAACBCSwAgMAEFgBAYAILACAwgQUAEJjAAgAITGABAASWx1+VQ5OGh4cbfzI6OprtnQAACwms4pnvKgAgnwRWYegqACgKgVUA0goAikVg5ZeuAoCCEli5o6sAoOjiBNaNGzf++c9/Hjx48G9/+9v09PT4+HhfX98K11++fPmll1569913Z2dnH3744ddee23btm0x77e82ukqTQZADL4JPTlxfg7WiRMnXn311R07duzdu3fVi69fv75nz55z586dPHnywoULvb29O3fuvHTpUozXLavh4WGFBABlEmeC9bOf/eyDDz6IoujAgQOrXvz2229/8sknp0+fbky5Xn/99Q0bNuzfv/+1116L8dJlIqoAoKwS/0nuhw8f7u/v37p1a+PDrq6u3bt3Hzp0KOnXza3hH2R9IwBAUhIPrFOnTm3evHnhI1u2bBkfH7927VrSL503ugoAKiLx7yK8cuXK4ODgwke6u7vr9frVq1fXrFmT9KvngagCgKpJPLDq9frKj/zhD3/Yv3//wkceeOCBgYGBixcvJndXc3Nz/9fXV4sW31tYQ0PSCoD8qtWyvoMw7puYuNDRkWDSTE9Pr127tqVPSTywenp6pqamFj4yNTVVq9W6u7sbH/7mN7956qmn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weTkZNy7BSrHuhAoojiB9fbbb3/yySdvvPFGX19fb2/v66+/Pjs7u3///uA3BxA5+Q4UUJzAOnz4cH9//9atWxsfdnV17d69+9ChQ0FvDOAmRllAgcQJrFOnTm3evHnhI1u2bBkfH7927dpyn7Jr167Ozs577733mWeeuXjxYowXBdBYQFHECawrV66sW7du4SPd3d31ev3q1au3Xnz77be/8sorx48fv3Llyptvvnn8+PHt27d//fXXMe8XqDbrQqAQOmJ8Tr1eX/WReTt27NixY0fjzx999NF33nnngQceOHDgwO9///vGg/v27fvtb3+78FN+/vOfDw4O/utf/4pxb0AVjI6NDQ8NhXq2oaHhsbHRUM8G5Eeolpiamlo0WlpVnMDq6emZmppa9MK1Wq27u3vVzx0YGLj//vtPnDgx/8i+ffv27du38JrGhxs3boxxb0BFaCxgVaFaotW6iuKtCLdt2/bFF18sfOTs2bObNm1as2ZNjGcDiMe6EMitOIE1MjJy/vz5M2fOND6cmZk5evToyMhIM5/7+eeff/nllw899FCM1wW4lZPvQA7FCawnn3xyYGDg2WefnZiY+Oabb5577rnOzs69e/c2/up7771Xq9UOHjzY+PDXv/71wYMHL1y4MDMz88EHH/ziF7+47777XnjhhWB/B0DlaSwgb+IEVmdn55EjR/r7+wcHBzdu3Dg5OXns2LENGzYsefHLL7/84Ycf7tq1q6en5+mnn37kkUc++uij9evXt3fbADexLgRyJc4h9yiK7r777vkZ1SKPP/74wm8q/OlPf/qXv/wl3qsAtMTJdyAnYv6yZ4B8Cj7KCvVUQKUILKCErAuBbAksoJycfAcyJLCA0nLyHciKwAJKzigLSJ/AAspPYwEpE1hAJVgXAmkSWECFGGUB6RBYQLVoLCAFAguoHOtCIGkCC6gooywgOQILqC6NBSREYAGVZl0IJEFgARhlAYEJLIAoSmCUFeqpgCISWAA/si4EghBYADexLgTaJ7AAFnPyHWiTwAJYmlEWEJvAAliWxgLiEVgAK7EuBGIQWACrM8oCWiKwAJqisYDmCSyAZlkXAk0SWACtMcoCViWwAFqmsYCVCSyAOKwLgRUILID4jLKAJQksgLYEH2WFeiogQwILIADrQmAhgQUQhnUhME9gAQTj5DvQILAAAjPKAgQWQHga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", "text/plain": [ "Figure()" ] }, "execution_count": 5, "metadata": {}, "output_type": "execute_result" } ], "source": [ "function plot_sset(ss::SSet, points::Vector, \n", " tri_colors::Union{Nothing,Vector}=nothing) \n", " dflt = collect(take(cycle([:blue,:red,:green, :purple, :pink, :yellow, :grey, :orange, :brown, :cyan]), nparts(ss, :T)))\n", " tri_colors = isnothing(tri_colors) ? dflt : tri_colors\n", " # Validate inputs\n", " lengthscale=0.8\n", " dim = length(points[1])\n", " length(points) == nparts(ss,:V) || error(\"# of points\")\n", " if dim == 2 \n", " points = [(p1,p2,0.) for (p1,p2) in points]\n", " elseif dim != 3\n", " error(\"dim $dim\")\n", " end\n", " tri_colors = tri_colors[1:nparts(ss, :T)]\n", "\n", " # Convert SSet to EmbeddedDeltaSet2D\n", " s = EmbeddedDeltaSet2D{Bool, Point{3, Float64}}()\n", "\n", " edge_colors = [:black for _ in nparts(ss, :E)]\n", " add_vertices!(s, length(points), point=points)\n", " for (src, tgt) in zip(ss[:src], ss[:tgt])\n", " get_edge!(s, src, tgt)\n", " end\n", " \n", " for t in parts(ss,:T)\n", " glue_sorted_triangle!(s, ss[t,[:d1,:src]],\n", " ss[t,[:d3,:src]],\n", " ss[t, [:d1,:tgt]])\n", " end\n", "\n", " # Split mesh into component triangles\n", " m = GeometryBasics.Mesh(s)\n", " x = faces(m)\n", " m_points = m.position[vcat([[t[1],t[2],t[3]] for t in x]...)]\n", " m_faces = TriangleFace{Int}[[((t-1) * 3) .+ (1,2,3) for t in 1:length(x)]...]\n", " new_m = GeometryBasics.Mesh(Point{3, Float64}[m_points...], m_faces)\n", " if ntriangles(s) == 0\n", " fig, ax, ob = arrows((s[s[:∂v0], :point] * (0.5 + lengthscale / 2) \n", " .+ s[s[:∂v1], :point] * (0.5 - lengthscale / 2)) , \n", " (s[s[:∂v1], :point] .- s[s[:∂v0], :point]), \n", " lengthscale=lengthscale, arrowsize=0.05, shininess=0.0,\n", " color=edge_colors, diffuse=[0.0,0.0,0.0])\n", " else\n", " fig, ax, ob = mesh(new_m, color=vcat([[v,v,v] for v in tri_colors]...))\n", " arrows!((s[s[:∂v0], :point] * (0.5 + lengthscale / 2) \n", " .+ s[s[:∂v1], :point] * (0.5 - lengthscale / 2)) , \n", " (s[s[:∂v1], :point] .- s[s[:∂v0], :point]), \n", " lengthscale=lengthscale, arrowsize=0.05, shininess=0.0,\n", " color=edge_colors, diffuse=[0.0,0.0,0.0])\n", " end\n", " if dim == 2\n", " # hidespines!(ax); hidedecorations!(ax)\n", " ax.aspect = AxisAspect(1.0) # Remove this line if 3D embedding\n", " end \n", " fig\n", "end\n", "\n", "quad_coords = [(0,1,0), (1,1,0), (0,0,0),(1,0,0)]\n", "plot_sset(quadrangle, quad_coords)\n", "\n" ] }, { "cell_type": "markdown", "id": "53f0e2f2", "metadata": {}, "source": [ "## Figure 3a \n", "Catlab has functionality to reversibly translate between a $\\mathcal{C}$-set and its category-of-elements representation (which is a $\\mathcal{C}$-typed-graph)." ] }, { "cell_type": "code", "execution_count": 6, "id": "8c33ddec", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "NODE TYPES: [:V, :V, :V, :V, :E, :E, :E, :E, :E, :T, :T]\n" ] }, { "data": { "image/svg+xml": [ "\n", "\n", "\n", "\n", "\n", "\n", "G\n", "\n", "\n", "\n", "n1\n", "\n", "1\n", "\n", "\n", "\n", "n2\n", "\n", "2\n", "\n", "\n", "\n", "n3\n", "\n", "3\n", "\n", "\n", "\n", "n4\n", "\n", "4\n", "\n", "\n", "\n", "n5\n", "\n", "5\n", "\n", "\n", "\n", "n5->n1\n", "\n", "\n", "\n", "\n", "\n", "n5->n4\n", "\n", "\n", "\n", "\n", "\n", "n6\n", "\n", "6\n", "\n", "\n", "\n", "n6->n1\n", "\n", "\n", "\n", "\n", "\n", "n6->n2\n", "\n", "\n", "\n", "\n", "\n", "n7\n", "\n", "7\n", "\n", "\n", "\n", "n7->n1\n", "\n", "\n", "\n", "\n", "\n", "n7->n3\n", "\n", "\n", "\n", "\n", "\n", "n8\n", "\n", "8\n", "\n", "\n", "\n", "n8->n2\n", "\n", "\n", "\n", "\n", "\n", "n8->n4\n", "\n", "\n", "\n", "\n", "\n", "n9\n", "\n", "9\n", "\n", "\n", "\n", "n9->n3\n", "\n", "\n", "\n", "\n", "\n", "n9->n4\n", "\n", "\n", "\n", "\n", "\n", "n10\n", "\n", "10\n", "\n", "\n", "\n", "n10->n5\n", "\n", "\n", "\n", "\n", "\n", "n10->n6\n", "\n", "\n", "\n", "\n", "\n", "n10->n8\n", "\n", "\n", "\n", "\n", "\n", "n11\n", "\n", "11\n", "\n", "\n", "\n", "n11->n5\n", "\n", "\n", "\n", "\n", "\n", "n11->n7\n", "\n", "\n", "\n", "\n", "\n", "n11->n9\n", "\n", "\n", "\n", "\n", "\n" ], "text/plain": [ "Catlab.Graphics.Graphviz.Graph(\"G\", true, \"dot\", Catlab.Graphics.Graphviz.Statement[Catlab.Graphics.Graphviz.Node(\"n1\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"1\")), Catlab.Graphics.Graphviz.Node(\"n2\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"2\")), Catlab.Graphics.Graphviz.Node(\"n3\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"3\")), Catlab.Graphics.Graphviz.Node(\"n4\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"4\")), Catlab.Graphics.Graphviz.Node(\"n5\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"5\")), Catlab.Graphics.Graphviz.Node(\"n6\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"6\")), Catlab.Graphics.Graphviz.Node(\"n7\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"7\")), Catlab.Graphics.Graphviz.Node(\"n8\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"8\")), Catlab.Graphics.Graphviz.Node(\"n9\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"9\")), Catlab.Graphics.Graphviz.Node(\"n10\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"10\")) … Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n5\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n1\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}()), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n6\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n1\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}()), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n7\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n1\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}()), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n8\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n2\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}()), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n9\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n3\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}()), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n5\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n4\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}()), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n6\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n2\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}()), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n7\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n3\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}()), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n8\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n4\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}()), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n9\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n4\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}())], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:rankdir => \"LR\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:height => \"0.05\", :margin => \"0\", :shape => \"circle\", :width => \"0.05\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:arrowsize => \"0.5\"))" ] }, "execution_count": 6, "metadata": {}, "output_type": "execute_result" } ], "source": [ "e = elements(quadrangle)\n", "println(\"NODE TYPES: \", e[[:πₑ, :nameo]])\n", "to_graphviz(FreeDiagram(pres(e)[1]), node_labels=true)" ] }, { "cell_type": "markdown", "id": "a872b32b", "metadata": {}, "source": [ "## Figure 4\n", "We show a sequence of building schema `N+1` by choosing a designated instance of schema `N` and treating it as a type system." ] }, { "cell_type": "code", "execution_count": 7, "id": "8b9b7d32", "metadata": {}, "outputs": [], "source": [ "G2 = @acset Graph begin V=2; E=2; src=[1,2]; tgt=[2,1] end \n", "ThPetri = pres(elements(G2))[1]\n", "@acset_type Petri(ThPetri)\n", "Interact = @acset Petri begin \n", " V_1=2; V_2=3; E_1=4; E_2=4\n", " src_E_1 = [1,1,2,2]\n", " tgt_E_1 = [1,2,2,3]\n", " src_E_2 = [1,2,2,3]\n", " tgt_E_2 = [1,1,2,2]\n", "end\n", "ThHV = pres(elements(Interact))[1]\n", "@acset_type HV(ThHV) ; \n", "# etc. TODO visualize the acsets+schemas" ] }, { "cell_type": "markdown", "id": "f85227f7", "metadata": {}, "source": [ "## Figure 5\n", "The benchmark code is also found in this repository, in the `src` folder." ] }, { "cell_type": "markdown", "id": "57bdba3c", "metadata": {}, "source": [ "## Figure 6\n", "A single quadralateral edge flip with DPO rewriting. We first set up the objects involved in the rules and the object we will rewrite:" ] }, { "cell_type": "code", "execution_count": 8, "id": "b4599817", "metadata": {}, "outputs": [ { "data": { "image/png": "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JrAAAIIJLACAYAILACCYwAIACCawAACCCSwAgGACCwAgmMACAAgmsAAAggksAIBgAgsAIJjAAgAIJrAAAIIJLACAYAILACCYwAIACCawAACCCSwAgGACCwAgmMACAAgmsAAAggksAIBgAgsAIJjAAgAIJrAAAIIJLACAYAILACCYwAIACCawAACCCSwAgGACCwAgmMACAAgmsAAAggksAIBgAgsAIJjAAgAIJrAAAIIJLACAYAILACCYwAIACCawAACCCSwAgGACCwAgmMACAAgmsAAAggksAIBgAgsAIJjAAgAIJrAAAIIJLACAYAILACCYwAIACCawAACCCSwAgGACCwAgmMACAAgmsAAAggksAIBgAgsAIJjAAgAIJrAAAIIJLACAYAILACCYwAIACCawAACCCSwAgGACCwAgmMACAAgmsAAAggksAIBgAgsAIJjAAgAIJrAAAIIJLACAYAILACCYwAIACCawAACCCSwAgGACCwAgmMACAAgmsAAAggksAIBgAgsAIJjAAgAIJrAAAIIJLACAYAILACCYwAIACCawAACCCSwAgGACCwAgmMACAAgmsAAAggksAIBgAgsAIJjAAgAIJrAAAIIJLACAYAILACCYwAIACCawAACCCSwAgGACCwAgmMACAAgmsAAAggksAIBgAgsAIJjAAgAIJrAAAIIJLACAYAILACCYwAIACCawAACCCSwAgGACCwAgmMACAAgmsAAAggksAIBgAgsAIJjAAgAIJrAAAIIJLACAYAILACCYwAIACCawAACCCSwAgGACCwAgmMACAAgmsAAAggksAIBgAgsAIJjAAgAIJrAAAIIJLACAYAILACCYwAIACCawAACCCSwAgGACCwAgmMACAAgmsAAAggksAIBgAgsAIJjAAgAIJrAAAIIJLACAYAILACCYwAIACCawAACCCSwAgGACCwAgmMACAAgmsAAAggksAIBgAgsAIJjAAgAIJrAAAIIJLACAYAILACCYwAIACCawAACCCSwAgGACCwAgmMACAAgmsAAAggksAIBgAgsAIJjAAgAIJrAAAIIJLACAYAkDa3h4eM+ePXV1ddXV1a+//np/f/+TRp4+fTr/Y88//3zS2QIAlIEkgTU1NdXV1XX9+vWLFy/euHGjvr5++/btt27despdvvzyy+IDIyMjSWcLAFAGkgTW8ePHL1++/OGHHzY3N9fX1x89enRycvLQoUPhkwMAKEdJAuvkyZOtra2bNm2avVldXb1z584TJ06ETgwAoFwlCaz+/v4NGzbM3bJx48bBwcF79+496S47duwoFAovvPDC3r17b968mWCnAADlIklgjY6O1tTUzN1SW1tbLBbv3r3708GrVq16//33z58/Pzo6+tFHH50/f37btm23b99OOF8AgMyrSnCfYrH4zC0PdXZ2dnZ2zv77tdde++STTzZv3nzkyJE//vGPsxt7enp+//vfz73LL3/5y46Ojv/85z8J5haihLsGAo2Pj+dyubGxsVJPBCiNqAV9bGzskVNLz5QksOrq6h55whobG8vn87W1tc+8b3t7+4svvnjhwoWHW3p6enp6euaOmb3Z1NSUYG4hSrhrINDsM9VCnxaBihG1oCd4GknyEmFbW9vXX389d8u1a9daWlpWr16d4LcBAFSYJIHV3d09MDBw9erV2ZsTExNnz57t7u6ez32/+uqrb7755qWXXkqwXwCAspAksHbv3t3e3r5v376hoaE7d+7s37+/UCgcPHhw9qenTp3K5/PHjh2bvfnb3/722LFjN27cmJiYOHPmzK9+9av169e/8847Yf8DAICMSRJYhUKht7e3tbW1o6OjqalpZGTk3LlzjY2Njx383nvvffbZZzt27Kirq3vrrbdeffXVzz//vKGhYXHTBgDIriQXuedyuXXr1j08R/WIXbt2zX1T4c9//vO//e1vyfYCAFCOEn7ZMwAATyKwAACCCSwAgGACCwAgmMACAAgmsAAAggksAIBgAgsAIJjAAgAIJrAAAIIJLACAYAILACCYwAIACCawAACCCSwAgGACCwAgmMACAAgmsAAAggksAIBgAgsAIJjAAgAIJrAAAIIJLACAYAILACCYwAIACCawAACCCSwAgGACCwAgmMACAAgmsAAAggksAIBgAgsAIJjAAgAIJrAAAIIJLACAYAILACCYwAIACCawAACCCSwAgGACCwAgmMACAAgmsAAAggksAIBgAgsAIJjAAgAIJrAAAIIJLACAYAILACCYwAIACCawAACCCSwAgGACCwAgmMACAAgmsAAAggksAIBgAgsAIJjAAgAIJrAAAIIJLACAYAILACCYwAIACCawAACCCSwAgGACCwAgmMACAAgmsAAAggksAIBgAgsAIJjAAgAIJrAAAIIJLACAYAILACCYwAIACCawAACCCSwAgGACCwAgmMACAAgmsAAAggksAIBgAgsAIJjAAgAIJrAAAIIJLACAYAILACCYwAIACCawAACCCSwAgGACCwAgmMACAAgmsAAAggksAIBgAgsAIJjAAgAIJrAAAIIJLACAYAILACCYwAIACCawAACCCSwAgGACCwAgmMACAAgmsAAAggksAIBgAgsAIJjAAgAIJrAAAIIJLACAYAILACCYwAIACCawAACCCSwAgGACCwAgmMACAAgmsAAAggksAIBgAgsAIJjAAgAIJrAAAIIJLACAYAILACCYwAIACCawAACCCSwAgGACCwAgmMACAAgmsAAAggksAIBgAgsAIJjAAgAIJrAAAIIJLACAYAILACCYwAIACCawAACCCSwAgGACCwAgmMACAAgmsAAAggksAIBgAgsAIJjAAgAIJrAAAIIJLACAYAILACCYwAIACCawAACCCSwAgGACCwAgmMACAAgmsAAAggksAIBgAgsAIJjAAgAIJrAAAIIJLACAYAILACCYwAIACCawAACCCSwAgGACCwAgmMACAAgmsAAAggksAIBgAgsAIJjAAgAIJrAAAIIJLACAYAILACCYwAIACCawAACCCSwAgGACCwAgmMACAAgmsAAAggksAIBgAgsAIJjAAgAIJrAAAIIJLACAYAILACCYwAIACCawAACCCSwAgGACCwAgmMACAAgmsAAAggksAIBgAgsAIJjAAgAIJrAAAIIJLACAYFWlnkDq+vr6frpxenp6eHh4/fr1Sz8fACCBxy7ouVzu22+/bWhoqKrKVtI4gwUAEExgAQAEE1gAAMEEFgBAMIEFABBMYAEABBNYAADBBBYAQDCBBQAQTGABAAQTWAAAwQQWAEAwgQUAEExgAQAEE1gAAMEEFgBAMIEFABBMYAEABBNYAADBBBYAQDCBBQAQTGABAAQTWAAAwQQWAEAwgQUAEExgAQAEE1gAAMEEFgBAMIEFABBMYAEABBNYAADBBBYAQDCBBQAQTGABAAQTWAAAwapKPQES2rp168N/9/X1lXAmAMAjBFb5mZtWAEAGCayyoasAoFwIrKzTVQBQdgRWRukqAChfAitzpBUAlLuEgTU8PPzuu+9++umnk5OTr7zyyuHDh9va2kIGL1uL6SpNBkAC3oSeniSfgzU1NdXV1XX9+vWLFy/euHGjvr5++/btt27dWvzgZWjrA6WeCAAQJklgHT9+/PLlyx9++GFzc3N9ff3Ro0cnJycPHTq0+MHLiq4CgEqVJLBOnjzZ2tq6adOm2ZvV1dU7d+48ceLE4gcvB05ZAUDFSxJY/f39GzZsmLtl48aNg4OD9+7dW+TgCqarAGD5SHKR++joaEdHx9wttbW1xWLx7t27q1evXujg77//fmJiYu6AqampqqqqH374IcHc5umHB9LbxUMvv/zyEuwFABZqadbBtM0u6Pl8Pr1dFIvFhf7+JIFVLBafuWX+g//6178+cknW5s2b29vb//e//yWY2zxNT0/fuXNnxYp0v+v6zTffTPX3A8BipLrULpnbt2/PzMxUVaX4yVMTExNr165d0F2SzKaurm5sbGzulrGxsXw+X1tbm2DwwYMHDx48OHdAT09PLpdrbGxMMLd5mp6eLhQK69evT28XuQdvf/WyIADZlOpSu2Ty+XxDQ0OqgbXQusolC6y2trYvvvhi7pZr1661tLT89PXBhQ6uSA8/ZURpAcAykeQ1su7u7oGBgatXr87enJiYOHv2bHd39+IHV7a+vj4f6QYAy0GSwNq9e3d7e/u+ffuGhobu3Lmzf//+QqHw8GW+U6dO5fP5Y8eOzWfwMtT3QKknAgCkJUlgFQqF3t7e1tbWjo6OpqamkZGRc+fOPel13AUNXlaUFgBUqoRXhK1bt+7hOapH7Nq165H3CT5lMDnXwgNAxUnxknsWZDHXwjsNBo81+xbmmpqaUk8EWHYEVuZ41yEAlDuBlV1KCwDKVLofZU4I18IDQHlxBqtsOKEFAOVCYJUfpQUAGSewypjXDQEgm1yDBQAQTGABAAQTWAAAwQQWAEAwgQUAEExgAQAEE1gAAMEEFgBAMIEFABBMYAEABMviV+UMDQ0NDQ319PSkt4uZmZnvv/9+7dq16e0CKLn79+/ncrlVq1aVeiJAisbHx9esWbNiRYrnjM6dO9fc3Lygu2TxDNaWLVsW+t9YqMnJyStXrqS6C6Dkbt26devWrVLPAkjXlStXJicnU91Fc3Pzli1bFnSXfLFYTGk2WTYwMNDV1TUwMFDqiQApmj0RnurpcKDkWltb//Wvf7W2tpZ6Ij+SxTNYAABlTWABAAQTWAAAwQQWAECwLH5MwxKoq6t7++23Sz0LIF3bt28v9RSA1L399tt1dXWlnsWjlum7CAEA0uMlQgCAYAILACCYwAIACCawAACCVXJgDQ8P79mzp66urrq6+vXXX+/v748aDGTH/B+8p0+fzv/Y888/v5RTBRKYmZk5c+bM3r17n3vuuXw+PzQ09PTxGVnQKzawpqamurq6rl+/fvHixRs3btTX12/fvv1JX/u6oMFAdiR48H755ZfFB0ZGRpZsqkAyFy5c+OCDDzo7Ow8ePPjMwRla0IsV6u9//3sul7ty5crszfHx8eeee+7AgQOLHwxkx4IevL29vbkfBxZQRv785z/ncrnBwcGnjMnOgl6xZ7BOnjzZ2tq6adOm2ZvV1dU7d+48ceLE4gcD2eHBC8yVneeEig2s/v7+DRs2zN2ycePGwcHBe/fuLXIwkB0JHrw7duwoFAovvPDC3r17b968mf4cgaWTnQW9YgNrdHS0pqZm7pba2tpisXj37t1FDgayY0EP3lWrVr3//vvnz58fHR396KOPzp8/v23bttu3by/VZIHUZWdBr9jAKv7kK4B+uiXZYCA7FvTg7ezs/MMf/rBx48a1a9e+9tprn3zyyc2bN48cOZLyHIGlk50FvWIDq66ubmxsbO6WsbGxfD5fW1u7yMFAdizmwdve3v7iiy9euHAhtdkBSy07C3rFBlZbW9vXX389d8u1a9daWlpWr169yMFAdnjwAnNl5zmhYgOru7t7YGDg6tWrszcnJibOnj3b3d29+MFAdizmwfvVV1998803L730UpoTBJZUhhb0pf9kiKUxOTnZ3t6+bdu2wcHBkZGRX//61/X19f/9739nf/rPf/4zl8t9/PHH8xkMZNaCHum/+c1vPv7446GhofHx8dOnT2/YsKGxsfG7774r3fSBBXjs52BldkGv2DNYhUKht7e3tbW1o6OjqalpZGTk3LlzjY2Nix8MZMeCHrzvvffeZ599tmPHjrq6urfeeuvVV1/9/PPPGxoalnjOwIJMT0/PfrfVgQMHcrlcS0tLPp9/4403Hjs4Owt6vujtcgAAoSr2DBYAQKkILACAYAILACCYwAIACCawAACCCSwAgGACCwAgmMACAAgmsAAAggksAIBgAgsAIJjAAgAIJrAAAIIJLACAYAILACCYwAIACCawAACCCSwAgGD/BzbTGSGBUsdzAAAAAElFTkSuQmCC", "text/plain": [ "Figure()" ] }, "execution_count": 8, "metadata": {}, "output_type": "execute_result" } ], "source": [ "L = quadrangle # We defined quadrilateral above.\n", "I = @acset SSet begin\n", " E=4; V=4\n", " src=[1,1,2,3]\n", " tgt=[2,3,4,4]\n", "end\n", "plot_sset(I, quad_coords) \n" ] }, { "cell_type": "code", "execution_count": 9, "id": "614e2da7", "metadata": {}, "outputs": [ { "data": { "image/png": "iVBORw0KGgoAAAANSUhEUgAAAyAAAAJYCAIAAAAVFBUnAAAABmJLR0QA/wD/AP+gvaeTAAAfJklEQVR4nO3dX2id9eHH8efMBim2NqRS/xRLSkZLKaEGi3RIXVuwyg/NzUAYIqjbT9iV/3oh/IR1jHnT0ZXdjHkxhhYvfjChFZms2hXs76LSFf81pbOl6Vytq7E0JBJsY/O7ODOLaZqc85znz/f5Pq8XXjTHJz2PbvG8+XxP0sbU1FQCAEB2vlf2DQAAxEZgAQBkTGABAGRMYAEAZExgAQBkTGABAGRMYAEAZExgAQBkTGABAGRMYAEAZExgAQBkTGABAGRMYAEAZExgAQBkbFHZNzCHPXv2vP/++729vWXfCABAMjw8fNdddz3zzDOtf0qIC9b7778/PDyc61NcvXp1bGws16cASvf1119//fXXZd8FkK+xsbGrV6/m+hTDw8Pvv/9+W58S4oLV29vb29u7c+fO/J5icnLywoULd9xxR35PAZRudHQ0SZJly5aVfSNAjj777LMVK1YsWpRj0qRokhAXLACAShNYAAAZE1gAABkTWAAAGRNYAAAZE1gAABkTWAAAGRNYAAAZE1gAABkTWAAAGQvxj8qhRRs3bmz+4ujRo+XeCQAwk8CqnumuAgDCJLAqQ1cBQFUIrAqQVgBQLQIrXLoKACpKYAVHVwFA1aUJrKtXr/71r3/du3fvn/70p7GxsTNnzvT29s5z/YULF55//vk333zz8uXL99577+7du9evX5/yfuPVSVdpMgBS8E3o+Unzc7COHDny0ksvbd68eceOHQtefOXKle3bt586derYsWNnz55dvnz5li1bzp8/n+J5Y7Vx40aFBAAxSbNg/eAHP3jnnXeSJNmzZ8+CF7/22msffPDB0NBQc+V6+eWXV65cuWvXrt27d6d46piIKgCIVe4/yX3//v19fX3r1q1rfrhkyZJt27bt27cv7+cN1sZvlX0jAEBecg+s48ePr1mzZuYja9euPXPmzMTERN5PHRpdBQA1kft3EV68eHFgYGDmI93d3VNTU5cuXVq8eHHezx4CUQUAdZN7YE1NTc3/yK9//etdu3bNfGTDhg39/f3nzp3L764mJyf/77/+K7/fv2l3PQoSgIp6LYpv6v9k6JHHhx9ftCjHpBkbG1u6dGlbn5J7YPX09IyOjs58ZHR0tNFodHd3Nz/82c9+9thjj8284Le//e2iRYtuu+22/O5qcnIyv9982nMTE4nMAoDcfDL0SJIkt912W66BtWTJknY/JffAWr9+/YcffjjzkZMnT65evXr6fPCmm2666aabZl7Q1dWVJMkNN9yQ311du6vlR2YBQOaaadV0ww035JoNjUaj3U/J/U3ug4ODp0+fPnHiRPPD8fHxgwcPDg4O5v28oXluYqL5V9k3AgCVN7OuwpR9YL311luNRmPv3r3NDx999NH+/v4nn3xyeHj4yy+/fOqpp7q6ulr5CaWxUloAkNonQ4+EX1dJusCanJxsNBqNRuPZZ59NkmT16tWNRuOhhx6a8+Kurq4DBw709fUNDAysWrVqZGTk0KFDK1eu7OiuoyCzAKAtlUirpjTvwVq0aNE872F68MEHZ/3dW2+9dXrQYpbpxvImLQCYR4XqKingTe60qJPSsoQBELFqpVVT7m9yp12ODgFgWhXrKrFgBcvRIQA1V9G0ahJYoVNaANRQpesqEVgVorQAqImq11XiPVhV5E1aAEQsgrpKLFjVpbEAiEwcadVkwQIAyhdTXSUWLACgXJGlVZMFCwAoTZR1lQgsAKAssdZV4ogQAChexGnVZMECAAoVfV0lAgsAKFId6ipxRAgAFKMmadVkwQIAclerukoEFgCQt7rVVeKIEADITw3TqqmmC9amTZt2L15c9l0AQMyKqas37n5j06ZNBTxRW2oaWE0aCwByUlhdFfAsKdQxsDZu3Dj9a40FANn6ZOiR4utq5ot7CGoXWKH9DwAAMSnxTVdBvcR7k3uye/Hi5yYmyr4LAKi2gtMq2MPBpnotWNdrWweFANCJQOoqnBGrRoEVzr90AIhJUD+LIZCXe0eE/+agEADaMn3+83Cxzxv44WBTXQKrlZ7VWAAwjxDeUdNKXW3cuPHo0aMF3Mw8ahFYgayFAFA5C0bVw38reMBqSemNVYvAap0RCwBCWKrmVInDwab4A6vd+UpjAVBD6aKqyPmq3boqd8SKPLAcDgLA9QS7VGWlxMaKPLDSMWIBEKsMoyrk+ap0MQdWJ/OVxgIgGlVfqjqpq7JGrGgDq/PDQY0FQHVVPaqmdb5dldJYcf4kd2+9AoBchfnTGa6n+DCIM7CyEk3+A1A3cRzCVO6tV9MiDKxsK1VjAVBR+TVWMfNVtnVV8IgVW2A5HASAac9NTMQxZWWiyEiILbDyYMQCoNKybawqzlfFiyqw8itTjQVARe1evLhyr2L51VVhI1Y8geVwEABmyTytqvXNg3MqJhjiCay8VS7/Aai5ir5yVf1wsCmSwCqmRiv6/1QAaiiP16wC5qti6qqAbIjkJ7nP8xNaU/xL9A0XAFRXpeeAeRouRXuV9Sc9J9EsWABAUvG6ionAAoBI5FpXEby9vUiRHBECQJ0ZrkJjwQKAaiugrsxX7RJYAFBV2f4QURWVIYEFAJWU7XDVrKuH//bwtZklvFIQWABQPdkOV7MSSlF1zpvcAaBK8hiurvf4G3e/IbbSsWABQGUUU1etX8D1WLAAoBq8n71CBBYAhK7g4YrOCSwACJrhqooEFgAEynBVXd7kDgAhUleVZsECgOA4Fqw6gQUAATFcxcERIQCEQl1Fw4IFAEFwLBgTgQUAJTNcxccRIQCUSV1FyYIFAOWQVhGzYAFACdRV3AQWABRNXUXPESEAFEda1YQFCwAKoq7qQ2ABQBHUVa04IgSAfEmrGrJgAUCO1FU9CSwAyIu6qi1HhACQPWlVcxYsAMiYusKCBQBZyrCupFV1CSwAyIbhimmOCAEgA+qKmSxYANARacW1LFgAkJ66Yk4CCwBSUldcjyNCAGibtGJ+FiwAaI+6YkECCwDaoK5ohSNCAGiJtKJ1FiwAWJi6oi0CCwAWoK5olyNCALguaUU6FiwAmJu6IjULFgDMIcO6klY1JLAA4DsMV3TOESEA/Ie6IhMWLABIEmlFpixYAKCuyJjAAqDu1BWZc0QIQH1JK3JiwQKgptQV+RFYANSRuiJXjggBqBdpRQEsWADUiLqiGAILgLpQVxTGESEA8ZNWFMyCBUDk1BXFs2ABELMM60pa0TqBBUCcDFeUyBEhABFSV5TLggVAVKQVIbBgARAPdUUgBBYAkVBXhMMRIQCVJ60IjQULgGpTVwRIYAFQYeqKMDkiBKCSpBUhs2ABUD3qisAJLAAqRl0RPkeEAFSGtKIqLFgAVIO6okIsWABUQIZ1Ja0ogMACIGiGK6rIESEA4VJXVJQFC4AQSSsqzYIFQHDUFVUnsAAIi7oiAo4IAQiFtCIaFiwAgqCuiInAAqB86orIOCIEoEzSiihZsAAojboiVgILgHKoKyLmiBCAokkromfBAqBQ6oo6sGABUJwM60paETKBBUARDFfUiiNCAHKnrqgbCxYAOZJW1JMFC4C8qCtqS2ABkAt1RZ05IgQgY9IKLFgAZEldQSKwAMiQuoImR4QAZEBawUwWLAA6pa5gFoEFQEfUFVzLESEAKUkruB4LFgBpqCuYh8ACoG3qCubniBCANkgraIUFC4BWqStokQULgJZkWFfSiugJLAAWYLiCdjkiBGA+6gpSsGABMDdpBalZsACYg7qCTggsAGZTV9AhR4QA/Ie0gkxYsAD4N3UFWRFYACSJuoJMOSIEqDtpBZmzYAHUmrqCPAgsgPpSV5ATR4QAdSStIFcWLIDaUVeQNwsWQL1kWFfSCq5HYAHUheEKCuOIEKAW1BUUyYIFEDlpBcWzYAHETF1BKQQWQLTUFZTFESFAhKQVlMuCBRAbdQWlE1gAUVFXEAJHhACRkFYQDgsWQAzUFQRFYAFUnrqC0DgiBKgwaQVhsmABVJW6gmBZsAAqKcO6klaQOYEFUDGGKwifI0KAKlFXUAkWLIBqkFZQIRYsgApQV1AtAgsgdOoKKscRIUC4pBVUlAULIFDqCqpLYAGESF1BpTkiBAiLtIIIWLAAAqKuIA4CCyAU6gqi4YgQoHzSCiJjwQIombqC+FiwAMqUYV1JKwiHwAIoh+EKIuaIEKAE6griZsECKJS0gjqwYAEUR11BTQgsgIKoK6gPR4QAuZNWUDcWLIB8qSuoIYEFkCN1BfXkiBAgF9IK6syCBZA9dQU1J7AAMqauAEeEAJmRVkCTBQsgG+oKmGbBAshAhnUlrSACAgugI4Yr4FqOCAHSU1fAnCxYAGlIK2AeFiyAtqkrYH4CC6A96gpYkCNCgFZJK6BFFiyAlqgroHUCC2Bh6gpoiyNCgPlIKyAFCxbAdakrIB2BBTA3dQWk5ogQYDZpBXTIggXwHeoK6JwFC+A/MqwraQV1JrAAksRwBWTKESGAugIyZsECak1aAXmwYAH1pa6AnAgsoKbUFZAfR4RA7UgrIG8WLKBe1BVQAIEF1Ii6AorhiBCoBWkFFMmCBcRPXQEFE1hA5NQVUDxHhEC0pBVQFgsWECd1BZTIggVEKMO6klZACikXrAsXLjz22GM9PT1Llix54IEHjh8/fr0r33777cZ33XLLLWnvFmABuxcvVldA6dIE1pUrV7Zv337q1Kljx46dPXt2+fLlW7ZsOX/+/Dyf8tFHH019a2RkJO3dAszHsSAQiDRHhK+99toHH3wwNDTU29ubJMnLL7+8cuXKXbt27d69O+O7A2iNtAKCkmbB2r9/f19f37p165ofLlmyZNu2bfv27cv0xgBapa6A0KQJrOPHj69Zs2bmI2vXrj1z5szExMT1PmXr1q1dXV233377E088ce7cuRRPCjAndQUEKE1gXbx4cdmyZTMf6e7unpqaunTp0rUX33jjjS+++OLhw4cvXrz4yiuvHD58eNOmTV988UXK+wX4VubvZ1dXQFbSvAdrampqwUembd68efPmzc1f33///a+//vqGDRv27Nnzq1/9qvngzp07f/GLX8z8lB/+8IcDAwP/+Mc/UtwbUBOGK2BBWbXE6OjorGlpQWkCq6enZ3R0dNYTNxqN7u7uBT+3v7//zjvvPHLkyPQjO3fu3Llz58xrmh+uWrUqxb0BdaCugFZk1RLt1lWSLrDWr1//4Ycfznzk5MmTq1evXpzpf/IAriWtgEpI8x6swcHB06dPnzhxovnh+Pj4wYMHBwcHW/ncjz/++NNPP73nnntSPC9Qc+oKqIo0gfXoo4/29/c/+eSTw8PDX3755VNPPdXV1bVjx47m333rrbcajcbevXubH/70pz/du3fv2bNnx8fH33nnnR/96Ed33HHHM888k9k/AVAP6gqokDSB1dXVdeDAgb6+voGBgVWrVo2MjBw6dGjlypVzXvzCCy+8++67W7du7enpefzxx++777733ntvxYoVnd02UCO+WxConJR/2POtt946vVHN8uCDD878psLvf//7v//979M9C4DhCqiilIEFUAB/bDNQUQILCJHhCqi0NO/BAsiVugKqzoIFBERaAXGwYAGhUFdANAQWEAR1BcTEESFQMmkFxMeCBZRJXQFRElhAadQVECtHhEAJpBUQNwsWUDR1BURPYAGFUldAHTgiBAoirYD6sGABRVBXQK1YsIDcZVhX0gqoBIEF5MhwBdSTI0IgL+oKqC0LFpA9aQXUnAULyJi6AhBYQJbUFUDiiBDIirQCmGbBAjKgrgBmElhAp9QVwCyOCIH0pBXAnCxYQErqCuB6BBaQhroCmIcjQqA90gpgQRYsoA3qCqAVFiygVRnWlbQC4iawgIUZrgDa4ogQWIC6AmiXBQu4LmkFkI4FC5ibugJITWABc1BXAJ1wRAh8h7QC6JwFC/gPdQWQCYEF/Ju6AsiKI0JAWgFk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", "text/plain": [ "Figure()" ] }, "execution_count": 9, "metadata": {}, "output_type": "execute_result" } ], "source": [ "R = @acset SSet begin\n", " T=2; E=5; V=4\n", " d1=[2,3]\n", " d2=[1,5]\n", " d3=[5,4]\n", " src=[1,1,2,3,2]\n", " tgt=[2,3,4,4,3]\n", "end\n", "plot_sset(R, quad_coords, [:brown, :purple])" ] }, { "cell_type": "code", "execution_count": 10, "id": "7066b0f9", "metadata": {}, "outputs": [ { "data": { "image/png": "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GRprcHCw1RpM//7qCkL09ddfL1hQ4F/tefr06auvvrqjD8lyNUuXLh0bG5v+lrGxsXa7vWTJkgzvvH379u3bt09/h6lT/eXLl2e4tpQmJib+9/D/3nLLLR191K9avxoYGCjokoB5DQ0NdfT+333xufZXHXyKVsttDjm7/ClMLr766qvlN9xQaGB1WletbM9grV279vPPP9P1+XEAAAcESURBVJ/+ls8++2zlypWX7oOdvnP9dfr1HcjF0NBQaXdfmZ8LaKosgbV169aDBw8eOHBg6penT59+9913t27d2v07B8FXXihZJTedOx3oRpbAevjhh9etW7dt27bR0dFvvvnm8ccf7+npSWa+t956q91u79ixI807B8pXXihNhbebOx3ILEtg9fT07N69u6+vb/369StWrDh+/PiePXsu98hUR+8cECMClKDyu6zyCwAClfGJsBtvvDE5o5rhgQcemPF9gnO8c+iGhoY8DwtFqE/ZTF2JOx3oSIGP3Edi7i++9flNgrNnz545c+b666+v+kL4zhzJUsMbZ+4/TdXwgqN17NixRYsWXXXVVVVfCLHLMhFyKV9eIRd1Ht/rfG1A3Qis3PjKC10K4iYK4iKBygmsPPkDLmQW0L0T0KUCVRFY+fPFFzoS4p9MQrxmoEwCqxC+8kJKQd8sQV88UCjfRVgUX3lhbs24R5rxbwHkzgkWAEDOBBYAQM4EFgBAzgQWAEDOBBYAQM4EFgBAzgQWAEDOBBYAQM4EFgBAzgQWAEDO6vijckZHR0dHRwcHB4v7FBcuXDhz5szVV19d3KegbsbHx8fHx6+66qqqL4TyfPvtt61W68orr6z6QijP2bNne3p6enp6qr4QynPq1KlFixb9z/8UeGa0Z8+e3t7ejj6kjidYd9xxR6f/Gp06f/78p59+WuinoG7GxsZGRkaqvgpKdeTIkSNHjlR9FZRqZGRkbGys6qugVJ9++un58+cL/RS9vb133HFHRx/SnpycLOhq6uzgwYObN28+ePBg1RdCeV5//fWXX3759ddfr/pCKM/UQXihx+HUzUMPPfSzn/3soYceqvpCKE9fX9/f/va3vr6+qi/kInU8wQIACJrAAgDImcACAMiZwAIAyNkVcT7+2W63Fy5c+MMf/rDqC6E87Xb7+uuvv+2226q+EErV29tb9HclUyvtdvu222677rrrqr4QytNutzds2LBw4cKqL+QikX4XIQBAcUyEAAA5E1gAADkTWAAAORNYAAA5a35gXbhw4Z133nnssceuueaadrs9Ojo69/sfPXr0kUceWbp06eLFi++///79+/eXcpnkrKPX8e23325fzLcgBaSj19oN3gzpX0d3dwME+vt48wNr7969zz777MaNG7dv3z7vO4+Pj2/evPmLL77Yt2/foUOHli1bds899/hhscHJ9jp+/PHHk//n+PHj5VwqXerotXaDN0OG19HdHbRQfx+fjMbvf//7Vqs1MjIyx/v8+c9/brVan3766dQvT506dc011zz55JNlXB/56fR13L17d+viL8GEoqPX2g3eDB29ju7uJgnr9/Hmn2B15I033ujr61uzZs3ULxcvXnzvvffu3Lmz2quiU17HeHT0WvsPoxm8jsyhPv95CKyL7N+/f9WqVdPfsnr16pGRkXPnzlV1SWSQ7XXctGlTT0/PzTff/Nhjjx0+fLjgayQfHb3WbvBmyPA6urvjUZ/bXGBd5MSJE9dee+30tyxZsmRycvLkyZNVXRIZdPo6Xnnllc8888z7779/4sSJl19++f3339+wYcOxY8dKuVi60tFr7QZvho5eR3d3bOpzmwusi0xe8oODLn0L9dfp67hx48bf/OY3q1evvvrqq++7777XXnvt8OHDL7zwQpHXSD46eq3d4M3Q0evo7o5NfW7zRgXWP/7xj+nfi5vhn7B06dKxsbHpbxkbG2u320uWLMnpGsnfpa97l6/junXrbr311r179xZyueSqo9faDd4M3byO7u7Gq89t3qjA2rBhw/QH+DP8E9auXfv5559Pf8tnn322cuXKuv2Mbqa79HX3Osajo9fafxjN4HVkDvX5z6NRgdW9rVu3Hjx48MCBA1O/PH369Lvvvrt169Zqr4pOdfk6fvLJJ19++eWdd95Z2AWSm45eazd4M3TzOrq7G69Gt3mRfwdEvcz692f89a9/bbVar7zyytQvz58/v27dug0bNoyMjBw/fvynP/3psmXL/v3vf1dwuXRh7tdxxos+OTn585///JVXXhkdHT116tTbb7+9atWq5cuX/+c//6no8ulAR6+1G7wZOnrR3d1NEtbv480/wZqYmJh6NOfJJ59stVorV65st9sPPvjgrO/c09Oze/fuvr6+9evXr1ix4vjx43v27Fm+fHm5l0y3On0dn3766ffee2/Tpk1Lly599NFH77777g8++OCGG24o85rJpqPX2g3eDB29ju7uBgj09/H2pG+iAQDIVfNPsAAASiawAAByJrAAAHImsAAAciawAAByJrAAAHImsAAAciawAAByJrAAAHImsAAAciawAAByJrAAAHImsAAAciawAAByJrAAAHImsAAAciawAAByJrAAAHL2/wGOn67t1YomegAAAABJRU5ErkJggg==", "text/plain": [ "Figure()" ] }, "execution_count": 10, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# construct G via pushout: glue two quads by a common edge\n", "edge = @acset SSet begin E=1; V=2; src=[1]; tgt=[2] end \n", "edge_left = homomorphism(edge, L; initial=Dict([:V=>[1,3]]))\n", "edge_right = homomorphism(edge, L; initial=Dict([:V=>[2,4]]))\n", "G = apex(pushout(edge_left, edge_right)) \n", "six_coords = vcat(quad_coords,[(-1.,1.,0.),(-1.,0.,0.),])\n", "plot_sset(G, six_coords)" ] }, { "cell_type": "markdown", "id": "684cabd1", "metadata": {}, "source": [ "Partially specify homomorphisms and let automated search handle the rest to generate the morphisms used in DPO." ] }, { "cell_type": "code", "execution_count": 11, "id": "2309384d", "metadata": {}, "outputs": [ { "data": { "image/png": "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l9q+EJrT7/dvuummO+64o+0LoVGjo6N1f1cyUen3+3fcccfnPve5ti+E5vT7/T179qxdu7btC/mMjn4XIQBAfUyEAACBCSwAgMAEFgBAYAILACCw/APr8uXLL7300kMPPXTDDTf0+/3p6enB73/mzJkHH3xw48aN69ev//rXv378+PFGLpPASr2OL774Yv+zfAtSQkq91m7wPBR/Hd3dGUj09/H8A+vVV1/94Q9/uHfv3oMHD676zrOzs/v27Xv33Xdfe+21kydPbtq06Z577vHDYpNT7XX8wx/+MP//zp4928ylMqRSr7UbPA8VXkd3d9JS/X18vjP+/d//vdfrTU1NDXifn/3sZ71e780331z45fnz52+44YZHH320iesjnLKv45EjR3qf/RJMKkq91m7wPJR6Hd3dOUnr9/H8T7BKef7558fGxm6//faFX65fv/6+++577rnn2r0qyvI6dkep19p/GHnwOjJAPP95CKzPOH78+LZt25a+Zfv27VNTUx9//HFbl0QF1V7He++9d2Rk5POf//xDDz106tSpmq+RMEq91m7wPFR4Hd3d3RHPbS6wPuPcuXM33njj0rds2LBhfn7+ww8/bOuSqKDs63jttdd+73vfe+WVV86dO/fMM8+88sore/bsef/99xu5WIZS6rV2g+eh1Ovo7u6aeG5zgfUZ81f84KAr30L8yr6Oe/fu/bd/+7ft27dff/31X/va137xi1+cOnXqySefrPMaCaPUa+0Gz0Op19Hd3TXx3OZZBdZ///d/L/1e3Ar/hI0bN87MzCx9y8zMTL/f37BhQ6BrJLwrX/chX8edO3d+4QtfePXVV2u5XIIq9Vq7wfMwzOvo7s5ePLd5VoG1Z8+epQ/wV/gn7Nix45133ln6lrfffnvr1q2x/Yxulrrydfc6dkep19p/GHnwOjJAPP95ZBVYwztw4MCJEyfeeuuthV9euHDh5ZdfPnDgQLtXRVlDvo5//OMf//SnP33xi1+s7QIJptRr7QbPwzCvo7s7exHd5nX+HRBxWfHvz/iv//qvXq/385//fOGXly5d2rlz5549e6amps6ePfuP//iPmzZt+t///d8WLpchDH4dl73o8/Pz//zP//zzn/98enr6/PnzL7744rZt2zZv3vyXv/ylpcunhFKvtRs8D6VedHd3TtL6fTz/E6y5ubmFR3MeffTRXq+3devWfr//jW98Y8V3HhkZOXLkyNjY2K5du7Zs2XL27NmjR49u3ry52UtmWGVfx8cff/y3v/3tvffeu3Hjxm9961tf+cpXfve73918881NXjPVlHqt3eB5KPU6urszkOjv4/1530QDABBU/idYAAANE1gAAIEJLACAwAQWAEBgAgsAIDCBBQAQmMACAAhMYAEABCawAAACE1gAAIEJLACAwAQWAEBgAgsAIDCBBQAQmMACAAhMYAEABCawAAACE1gAAIH9H5JnoseGMeTOAAAAAElFTkSuQmCC", "text/plain": [ "Figure()" ] }, "execution_count": 11, "metadata": {}, "output_type": "execute_result" } ], "source": [ "r = homomorphism(I, R; monic=true)\n", "l = homomorphism(I, L; monic=true)\n", "# Perform rewrite \n", "res = rewrite(l, r, G; monic=true) # homomorphism search will find a match, if any\n", "plot_sset(res, six_coords)" ] }, { "cell_type": "markdown", "id": "b16130d2", "metadata": {}, "source": [ "## Figure 7\n", "Demonstrating single-pushout rewriting with implicit deletion." ] }, { "cell_type": "code", "execution_count": 12, "id": "68f93836", "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "SSet with elements V = 1:3, E = 1:2, T = 1:0\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
Esrctgt
112
213
\n", "
\n" ], "text/plain": [ "SSet with elements V = 1:3, E = 1:2, T = 1:0\n", "┌───┬─────┬─────┐\n", "│\u001b[1m E \u001b[0m│\u001b[1m src \u001b[0m│\u001b[1m tgt \u001b[0m│\n", "├───┼─────┼─────┤\n", "│ 1 │ 1 │ 2 │\n", "│ 2 │ 1 │ 3 │\n", "└───┴─────┴─────┘\n" ] }, "execution_count": 12, "metadata": {}, "output_type": "execute_result" } ], "source": [ "Tri = @acset SSet begin \n", " T=1; E=3; V=3; \n", " d1=[1]; d2=[2]; d3=[3]; \n", " src=[1,1,2]; tgt=[3,2,3] \n", "end\n", "L = Tri\n", "l = homomorphisms(edge, L)[2]\n", "r = id(edge)\n", "m = homomorphism(L, quadrangle)\n", "can_pushout_complement(l, m)\n", "!can_pushout_complement(l, m) || error(\"Check that this does not make sense for DPO\")\n", "single_pushout_rewrite(l,r,m)" ] }, { "cell_type": "markdown", "id": "af16a04b", "metadata": {}, "source": [ "### Figure 8\n", "Demonstrating sesqui-pushout rewriting with implicit copying." ] }, { "cell_type": "code", "execution_count": 13, "id": "d74c7333", "metadata": {}, "outputs": [ { "data": { "image/png": "iVBORw0KGgoAAAANSUhEUgAAAyAAAAJYCAIAAAAVFBUnAAAABmJLR0QA/wD/AP+gvaeTAAAdkUlEQVR4nO3dX2yV9f3A8XN+UA2xSNMawXU2JV0ghHRC2hg3gwMS0QvTm10txkTZYrI7iVx44QXLMm9YHNnNMi/MosS7mUBiZoIyErnBtExFRjCQFpWgWAhNu5AAen4Xdd2xf8+f7/Pv+7xe8cLz8O3D9+L06buf85xDtVarVQAACOf/st4AAEBsBBYAQGACCwAgMIEFABCYwAIACExgAQAEJrAAAAITWAAAgQksAIDABBYAQGACCwAgMIEFABCYwAIACExgAQAEtjrrDdC0Q4cOffTRR/39/VlvBIAYTExMbNu27YUXXsh6I1ExwSqejz76aGJiIsippqena7VakFNBDk1NTWW9BUhKrVabnp4OcqqJiYmPPvooyKmYY4JVPP39/f39/QcOHGj/VJcvX96wYcOqVavaPxXk0Oeff97X15f1LiAR33777VdffdXb29v+qYL8QGEeEywAgMAEFgBAYAILACAwgQUAEJjAAgAITGABAAQmsAAAAhNYAACBCSwAgMAEFgBAYAILAFY2PDw8PDyc9S4oDIEFAI2SWTRIYAFAc2QWKxJYANAKmcUyBBYAtE5msSiBBQDtklnMszrrDUTou+++++c//3n48OG///3v09PT4+Pj/f39y6y/evXqiy+++M4779y6devRRx999dVXt27dmtZmc8cVCiiu2SvY6Oho1hsheyZY4Z06deqVV17ZsWPH/v37V1x8+/btPXv2XLhw4fTp05cuXerp6dm5c+eVK1dS2CcASTDNoiKwkvCzn/3s/fff37t377333rvi4rfeeuvjjz9+/fXX+/v7e3p6XnvttVu3bh08eDCFfQKQHJlVcgIrY0ePHh0YGNiyZcvsw87Ozt27dx85ciTbXQEQhMwqLYGVsbNnz27atKn+yObNm8fHx2/evJnVlgAIS2aVkMDK2PXr19etW1d/pKurq1ar3bhxI6stAZAEmVUq3kWYsVqttvyRP/7xj/NuyXrooYcGBwcvX77c/t/e++Mft3+SwIaGst4BQIKGh4dHx8baP8+qSqW3Urn85Zftn2p6enrt2rXtn4d6Aitj3d3dU1NT9Uempqaq1WpXV9fsw9/+9rfPPPNM/YI///nPq1ev3rBhQ/t/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", "text/plain": [ "Figure()" ] }, "execution_count": 13, "metadata": {}, "output_type": "execute_result" } ], "source": [ "G = Tri\n", "L = @acset SSet begin V=1 end\n", "I = @acset SSet begin V=2 end\n", "l = homomorphism(I,L); \n", "r=id(I); \n", "m = CSetTransformation(L, G, V=[1]);\n", "nparts(sesqui_pushout_rewrite(l, r, m), :T) == 4 || error(\"We get 4 'triangles' when we ignore equations\")\n", "resSqPO= sesqui_pushout_rewrite(l, r, m; pres=ThSemisimplicialSet) # pass in the equations\n", "plot_sset(resSqPO, [(0,0),(1,1),(0,1),(1,0),]) # only two triangles" ] }, { "cell_type": "markdown", "id": "939b8758", "metadata": {}, "source": [ "## Figure 9\n", "We highlight an aspect of directly rewriting in slice categories by computing the pushout complement of slices. We have special visualization written for Petri nets, so we define a function which migrates a morphism into the graph \"2\" to a Petri net. But our point is that the computations can be done entirely without moving into this larger schema. " ] }, { "cell_type": "code", "execution_count": 14, "id": "23a72808", "metadata": {}, "outputs": [], "source": [ "GraphSlice = Slice{Graph, ACSetTransformation}\n", "GraphSliceMorphism = SliceMorphism{Graph, ACSetTransformation}\n", "\n", "function graph_slice(s::GraphSlice) \n", " h = s.slice\n", " V, E = collect.([h[:V], h[:E]])\n", " g = dom(h)\n", " (S,T), (I,O) = [[findall(==(i),X) for i in 1:2] for X in [V,E]]\n", " nS,nT,nI,nO = length.([S,T,I,O])\n", " findS, findT = [x->findfirst(==(x), X) for X in [S,T]]\n", " AlgebraicPetri.Graph(@acset AlgebraicPetri.PetriNet begin \n", " S=nS; T=nT; I=nI; O=nO\n", " is=findS.(g[I,:src]); it=findT.(g[I, :tgt])\n", " ot=findT.(g[O,:src]); os=findS.(g[O, :tgt]) end)\n", "end;" ] }, { "cell_type": "markdown", "id": "cbd1fd66", "metadata": {}, "source": [ "Then we can set up our rewrite problem (given the slice constraint, there is only ever one choice for a map between slices, so we just visualize the objects)" ] }, { "cell_type": "code", "execution_count": 15, "id": "b3cc4428", "metadata": {}, "outputs": [ { "data": { "image/svg+xml": [ "\n", "\n", "\n", "\n", "\n", "\n", "G\n", "\n", "\n", "\n", "t1\n", "\n", "1\n", "\n", "\n", "\n" ], "text/plain": [ "Catlab.Graphics.Graphviz.Graph(\"G\", true, \"dot\", Catlab.Graphics.Graphviz.Statement[Catlab.Graphics.Graphviz.Node(\"t1\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"1\", :shape => \"square\", :color => \"#E28F41\", :pos => \"\"))], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:rankdir => \"LR\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:shape => \"plain\", :style => \"filled\", :color => \"white\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:splines => \"splines\"))" ] }, "execution_count": 15, "metadata": {}, "output_type": "execute_result" } ], "source": [ "two = @acset Graph begin V=2; E=2; src=[1,2]; tgt=[2,1] end # V1 = (S), V2 = [T]\n", "I_ = Graph(1)\n", "I = GraphSlice(ACSetTransformation(I_, two, V=[2])) # a transition [T]\n", "graph_slice(I)" ] }, { "cell_type": "code", "execution_count": 16, "id": "4a98137e", "metadata": {}, "outputs": [ { "data": { "image/svg+xml": [ "\n", "\n", "\n", "\n", "\n", "\n", "G\n", "\n", "\n", "\n", "s1\n", "\n", "1\n", "\n", "\n", "\n", "t1\n", "\n", "1\n", "\n", "\n", "\n", "t1->s1\n", "\n", "\n", "1\n", "\n", "\n", "\n" ], "text/plain": [ "Catlab.Graphics.Graphviz.Graph(\"G\", true, \"dot\", Catlab.Graphics.Graphviz.Statement[Catlab.Graphics.Graphviz.Node(\"s1\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"1\", :shape => \"circle\", :color => \"#6C9AC3\", :pos => \"\")), Catlab.Graphics.Graphviz.Node(\"t1\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"1\", :shape => \"square\", :color => \"#E28F41\", :pos => \"\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"t1\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"s1\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:labelfontsize => \"6\", :label => \"1\"))], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:rankdir => \"LR\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:shape => \"plain\", :style => \"filled\", :color => \"white\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:splines => \"splines\"))" ] }, "execution_count": 16, "metadata": {}, "output_type": "execute_result" } ], "source": [ "L_ = path_graph(Graph, 2)\n", "L = GraphSlice(ACSetTransformation(L_, two, V=[2,1], E=[2])) # [T] ⟶ (S)\n", "l = GraphSliceMorphism(I,L,ACSetTransformation(I_,L_,V=[1]))\n", "graph_slice(L)" ] }, { "cell_type": "code", "execution_count": 17, "id": "07556028", "metadata": {}, "outputs": [ { "data": { "image/svg+xml": [ "\n", "\n", "\n", "\n", "\n", "\n", "G\n", "\n", "\n", "\n", "s1\n", "\n", "1\n", "\n", "\n", "\n", "t1\n", "\n", "1\n", "\n", "\n", "\n" ], "text/plain": [ "Catlab.Graphics.Graphviz.Graph(\"G\", true, \"dot\", Catlab.Graphics.Graphviz.Statement[Catlab.Graphics.Graphviz.Node(\"s1\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"1\", :shape => \"circle\", :color => \"#6C9AC3\", :pos => \"\")), Catlab.Graphics.Graphviz.Node(\"t1\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"1\", :shape => \"square\", :color => \"#E28F41\", :pos => \"\"))], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:rankdir => \"LR\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:shape => \"plain\", :style => \"filled\", :color => \"white\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:splines => \"splines\"))" ] }, "execution_count": 17, "metadata": {}, "output_type": "execute_result" } ], "source": [ "R_ = Graph(2)\n", "R = GraphSlice(ACSetTransformation(R_, two, V=[2, 1])) # a transition and state [T] (S)\n", "r = GraphSliceMorphism(I,R,ACSetTransformation(I_, R_, V=[1]))\n", "graph_slice(R)" ] }, { "cell_type": "code", "execution_count": 18, "id": "f1b6d0bf", "metadata": {}, "outputs": [ { "data": { "image/svg+xml": [ "\n", "\n", "\n", "\n", "\n", "\n", "G\n", "\n", "\n", "\n", "s1\n", "\n", "1\n", "\n", "\n", "\n", "t1\n", "\n", "1\n", "\n", "\n", "\n", "s1->t1\n", "\n", "\n", "1\n", "\n", "\n", "\n", "s2\n", "\n", "2\n", "\n", "\n", "\n", "t1->s2\n", "\n", "\n", "1\n", "\n", "\n", "\n" ], "text/plain": [ "Catlab.Graphics.Graphviz.Graph(\"G\", true, \"dot\", Catlab.Graphics.Graphviz.Statement[Catlab.Graphics.Graphviz.Node(\"s1\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"1\", :shape => \"circle\", :color => \"#6C9AC3\", :pos => \"\")), Catlab.Graphics.Graphviz.Node(\"s2\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"2\", :shape => \"circle\", :color => \"#6C9AC3\", :pos => \"\")), Catlab.Graphics.Graphviz.Node(\"t1\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"1\", :shape => \"square\", :color => \"#E28F41\", :pos => \"\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"t1\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"s2\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:labelfontsize => \"6\", :label => \"1\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"s1\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"t1\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:labelfontsize => \"6\", :label => \"1\"))], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:rankdir => \"LR\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:shape => \"plain\", :style => \"filled\", :color => \"white\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:splines => \"splines\"))" ] }, "execution_count": 18, "metadata": {}, "output_type": "execute_result" } ], "source": [ "G_ = path_graph(Graph, 3)\n", "G = GraphSlice(ACSetTransformation(G_, two, V=[1,2,1], E=[1,2])) # (S) ⟶ [T] ⟶ (S)\n", "m = GraphSliceMorphism(L,G,ACSetTransformation(L_,G_,V=[2,3], E=[2]))\n", "graph_slice(G)" ] }, { "cell_type": "markdown", "id": "f05b0d34", "metadata": {}, "source": [ "Now we compute the rewrite in the slice category:" ] }, { "cell_type": "code", "execution_count": 19, "id": "9c8196f8", "metadata": {}, "outputs": [ { "data": { "image/svg+xml": [ "\n", "\n", "\n", "\n", "\n", "\n", "G\n", "\n", "\n", "\n", "s1\n", "\n", "1\n", "\n", "\n", "\n", "s2\n", "\n", "2\n", "\n", "\n", "\n", "t1\n", "\n", "1\n", "\n", "\n", "\n", "s2->t1\n", "\n", "\n", "1\n", "\n", "\n", "\n" ], "text/plain": [ "Catlab.Graphics.Graphviz.Graph(\"G\", true, \"dot\", Catlab.Graphics.Graphviz.Statement[Catlab.Graphics.Graphviz.Node(\"s1\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"1\", :shape => \"circle\", :color => \"#6C9AC3\", :pos => \"\")), Catlab.Graphics.Graphviz.Node(\"s2\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"2\", :shape => \"circle\", :color => \"#6C9AC3\", :pos => \"\")), Catlab.Graphics.Graphviz.Node(\"t1\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"1\", :shape => \"square\", :color => \"#E28F41\", :pos => \"\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"s2\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"t1\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:labelfontsize => \"6\", :label => \"1\"))], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:rankdir => \"LR\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:shape => \"plain\", :style => \"filled\", :color => \"white\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:splines => \"splines\"))" ] }, "execution_count": 19, "metadata": {}, "output_type": "execute_result" } ], "source": [ "graph_slice(rewrite_match(l, r, m))" ] }, { "cell_type": "markdown", "id": "cf1375ec", "metadata": {}, "source": [ "## Figure 10\n", "We show an example of computing DPO on structured cospans of Graphs, where the interface type is the discrete graph. We start with an open square, where 1 is the designated input and 2 is the designated output." ] }, { "cell_type": "code", "execution_count": 20, "id": "7f86b3d5", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "input [1] output [2]\n" ] }, { "data": { "image/svg+xml": [ "\n", "\n", "\n", "\n", "\n", "\n", "G\n", "\n", "\n", "\n", "n1\n", "\n", "1\n", "\n", "\n", "\n", "n2\n", "\n", "2\n", "\n", "\n", "\n", "n1->n2\n", "\n", "\n", "\n", "\n", "\n", "n3\n", "\n", "3\n", "\n", "\n", "\n", "n1->n3\n", "\n", "\n", "\n", "\n", "\n", "n4\n", "\n", "4\n", "\n", "\n", "\n", "n2->n4\n", "\n", "\n", "\n", "\n", "\n", "n3->n4\n", "\n", "\n", "\n", "\n", "\n" ], "text/plain": [ "Catlab.Graphics.Graphviz.Graph(\"G\", true, \"dot\", Catlab.Graphics.Graphviz.Statement[Catlab.Graphics.Graphviz.Node(\"n1\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"1\")), Catlab.Graphics.Graphviz.Node(\"n2\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"2\")), Catlab.Graphics.Graphviz.Node(\"n3\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"3\")), Catlab.Graphics.Graphviz.Node(\"n4\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"4\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n1\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n2\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}()), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n1\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n3\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}()), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n2\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n4\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}()), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n3\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n4\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}())], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:rankdir => \"LR\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:height => \"0.05\", :margin => \"0\", :shape => \"circle\", :width => \"0.05\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:arrowsize => \"0.5\"))" ] }, "execution_count": 20, "metadata": {}, "output_type": "execute_result" } ], "source": [ "const OpenGraphOb, OpenGraph = OpenCSetTypes(Graph, :V)\n", "\n", "# Some basic graphs and morphisms \n", "G1, G2, G3 = Graph.([1,2,3])\n", "Arrow = path_graph(Graph, 2)\n", "id_1 = id(Graph(1));\n", "f12 = CSetTransformation(G1, G2, V=[1]);\n", "f22 = CSetTransformation(G1, G2, V=[2]);\n", "up_ = ACSetTransformation(G2, Arrow, V=[1,2]);\n", "down_ = ACSetTransformation(G2, G1, V=[1,1]);\n", "\n", "# Graph to rewrite\n", "Square = @acset Graph begin V=4; E=4; src=[1,1,2,3]; tgt=[2,3,4,4] end\n", "opensquare = OpenGraph(Square, FinFunction([1], 4), FinFunction([2], 4));\n", "\n", "println(\"input \", collect(first(legs(opensquare))[:V]), \n", " \" output \", collect(last(legs(opensquare))[:V]),)\n", "to_graphviz(apex(opensquare), node_labels=true)\n" ] }, { "cell_type": "markdown", "id": "fe07b84b", "metadata": {}, "source": [ "We then match a rule which squashes an edge into a point, creating an open triangle." ] }, { "cell_type": "code", "execution_count": 21, "id": "33f3dbc2", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "input [1] output [1]\n" ] }, { "data": { "image/svg+xml": [ "\n", "\n", "\n", "\n", "\n", "\n", "G\n", "\n", "\n", "\n", "n1\n", "\n", "1\n", "\n", "\n", "\n", "n2\n", "\n", "2\n", "\n", "\n", "\n", "n1->n2\n", "\n", "\n", "\n", "\n", "\n", "n3\n", "\n", "3\n", "\n", "\n", "\n", "n1->n3\n", "\n", "\n", "\n", "\n", "\n", "n2->n3\n", "\n", "\n", "\n", "\n", "\n" ], "text/plain": [ "Catlab.Graphics.Graphviz.Graph(\"G\", true, \"dot\", Catlab.Graphics.Graphviz.Statement[Catlab.Graphics.Graphviz.Node(\"n1\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"1\")), Catlab.Graphics.Graphviz.Node(\"n2\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"2\")), Catlab.Graphics.Graphviz.Node(\"n3\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"3\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n1\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n2\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}()), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n1\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n3\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}()), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n2\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n3\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}())], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:rankdir => \"LR\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:height => \"0.05\", :margin => \"0\", :shape => \"circle\", :width => \"0.05\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:arrowsize => \"0.5\"))" ] }, "execution_count": 21, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Discrete open graphs\n", "o1 = OpenGraph(G1, id_1[:V], id_1[:V]);\n", "o2 = OpenGraph(G2, f12[:V], f22[:V]);\n", "\n", "# Open graph with an edge \n", "openarr = OpenGraph(Arrow, f12[:V], f22[:V]);\n", "\n", "\n", "# Map from discrete 2 point graph to an arrow, so we delete the arrow\n", "squash_l = StructuredMultiCospanHom(o2, openarr,\n", " ACSetTransformation[up_, id_1, id_1])\n", "\n", "# Map from discrete 2 point graph to the discrete 1 point graph\n", "squash_r = StructuredMultiCospanHom(o2, o1,\n", " ACSetTransformation[down_, id_1, id_1])\n", "\n", "# Putting together the two legs of the rule\n", "squash = openrule(Span(squash_l, squash_r))\n", "\n", "# match arrow to square edge that has an input and an output\n", "square_m = StructuredMultiCospanHom(openarr, opensquare,\n", " ACSetTransformation[\n", " ACSetTransformation(Arrow, Square, V=[1,2], E=[1]), \n", " id_1, id_1])\n", "\n", "# Input and output now merged\n", "res = open_rewrite_match(squash, square_m)\n", "println(\"input \", collect(first(legs(res))[:V]), \n", " \" output \", collect(last(legs(res))[:V]),)\n", "to_graphviz(apex(res), node_labels=true)\n" ] }, { "cell_type": "markdown", "id": "ee6124c3", "metadata": {}, "source": [ "## Figure 11\n", "We show the construction of a cube surface as a distributed semi-simplicial set. Start by defining the category of distributed Semisimplicial Sets as a special kind of diagram\n" ] }, { "cell_type": "code", "execution_count": 22, "id": "f5cd9fea", "metadata": {}, "outputs": [], "source": [ "const ACSetCat{S} = TypeCat{S, ACSetTransformation}\n", "const DistSSet{D} = Diagram{id, ACSetCat{SSet}, D}\n", "const DistSSetHom{F,Φ,D} = DiagramHom{id, ACSetCat{SSet}, F, Φ, D};" ] }, { "cell_type": "markdown", "id": "f6ab7d4b", "metadata": {}, "source": [ "We then specify the data of the network graph and declare its path to commute. " ] }, { "cell_type": "code", "execution_count": 23, "id": "d052b7a9", "metadata": {}, "outputs": [], "source": [ "\"\"\" \n", "Helper fn: category generated by a finite graph where all paths commute.\n", "\"\"\"\n", "\n", "dsrc = [2,2,3,3, 5,5, 6,6, 7,7, 8,8, 9,9, 11,11,13,13,15,15,16,16,17,17]\n", "dtgt = [1,4,1,10,1,14,4,10,4,12,4,14,1,18,10,12,12,14,10,18,12,18,14,18]\n", "d = @acset Graph begin \n", " V=6+12; # faces, edges: numbering comes from the figure →,↓\n", " E=24; # each face glued along four edges\n", " src=dsrc\n", " tgt=dtgt\n", "end;\n", "\n", "es = [i for (i, e) in enumerate(dsrc) if e in vcat([2,3,5,9,7,11,13,16],[8,15, 6, 17])] \n", "# 8 is good (lowers vertices from 16->14), 15 is good (lowers to 12)\n", "# 6 is good (lowers to 10)\n", "\n", "d_ = FinCatGraph(@acset Graph begin \n", " V=6+12; # faces, edges: numbering comes from the figure →,↓\n", " E=length(es); # each face glued along four edges\n", " src=dsrc[es]\n", " tgt=dtgt[es]\n", " end;)\n", "D = FinCatGraph(d);\n", "#to_graphviz(d, node_labels=true)" ] }, { "cell_type": "markdown", "id": "905313c3", "metadata": {}, "source": [ "Lastly, we construct the functor into the category of semisimplicial complexes\n" ] }, { "cell_type": "code", "execution_count": 24, "id": "88487acc", "metadata": {}, "outputs": [], "source": [ "\n", "# SSets corresponding to the vertices\n", "obs = repeat([edge], 18)\n", "obs[[1,4,10,12,14,18]] .= repeat([quadrangle], 6)\n", "\n", "# Use homomorphism finder to get all of the relevant morphisms\n", "_, purple, red, teal, green = homomorphisms(edge, quadrangle) # TODO: actually get this right\n", "\n", "# SSet morphisms corresponding to the edges of the diagram\n", "homs = [green, green, # E2\n", " red, teal, # E3\n", " teal, teal, # E5\n", " red, green, # E6\n", " purple, green,# E7\n", " teal, green, # E8\n", " purple, green, # E9\n", " red, red, # E11\n", " teal, red, # E13\n", " purple, red, # E15\n", " purple, purple, # E16\n", " purple, teal] # E17\n", "FF = FinDomFunctor(obs, homs, D)\n", "@assert is_functorial(FF)\n", "J = FreeDiagram(FF); \n" ] }, { "cell_type": "code", "execution_count": 25, "id": "770ba7df", "metadata": {}, "outputs": [ { "data": { "image/png": "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", "text/plain": [ "Scene (800px, 600px):\n", " 0 Plots\n", " 1 Child Scene:\n", " └ Scene (768px, 568px)" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "cube = apex(colimit(J));\n", "cube_coords = vcat(quad_coords, [(0,1,1), (1,1,1), (0,0,1),(1,0,1)])\n", "display(plot_sset(cube, cube_coords))" ] }, { "cell_type": "markdown", "id": "4fe24409", "metadata": {}, "source": [ "## Further extensions\n", "We start with parallel rewriting. We delete three self loops in parallel." ] }, { "cell_type": "code", "execution_count": 26, "id": "85cec81a", "metadata": {}, "outputs": [ { "data": { "image/svg+xml": [ "\n", "\n", "\n", "\n", "\n", "\n", "G\n", "\n", "\n", "\n", "n1\n", "\n", "\n", "\n", "\n", "n1->n1\n", "\n", "\n", "\n", "\n", "\n", "n2\n", "\n", "\n", "\n", "\n", "n2->n2\n", "\n", "\n", "\n", "\n", "\n", "n3\n", "\n", "\n", "\n", "\n", "n3->n3\n", "\n", "\n", "\n", "\n", "\n" ], "text/plain": [ "Catlab.Graphics.Graphviz.Graph(\"G\", true, \"dot\", Catlab.Graphics.Graphviz.Statement[Catlab.Graphics.Graphviz.Node(\"n1\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"\")), Catlab.Graphics.Graphviz.Node(\"n2\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"\")), Catlab.Graphics.Graphviz.Node(\"n3\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n1\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n1\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}()), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n2\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n2\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}()), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n3\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n3\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}())], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:rankdir => \"LR\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:height => \"0.05\", :margin => \"0\", :shape => \"point\", :width => \"0.05\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:arrowsize => \"0.5\"))" ] }, "execution_count": 26, "metadata": {}, "output_type": "execute_result" } ], "source": [ "t = apex(terminal(Graph))\n", "G = t ⊕ t ⊕ t\n", "to_graphviz(G)\n" ] }, { "cell_type": "code", "execution_count": 27, "id": "0b2497dc", "metadata": {}, "outputs": [ { "data": { "image/svg+xml": [ "\n", "\n", "\n", "\n", "\n", "\n", "G\n", "\n", "\n", "\n", "n1\n", "\n", "\n", "\n", "\n", "n2\n", "\n", "\n", "\n", "\n", "n3\n", "\n", "\n", "\n", "\n" ], "text/plain": [ "Catlab.Graphics.Graphviz.Graph(\"G\", true, \"dot\", Catlab.Graphics.Graphviz.Statement[Catlab.Graphics.Graphviz.Node(\"n1\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"\")), Catlab.Graphics.Graphviz.Node(\"n2\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"\")), Catlab.Graphics.Graphviz.Node(\"n3\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"\"))], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:rankdir => \"LR\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:height => \"0.05\", :margin => \"0\", :shape => \"point\", :width => \"0.05\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:arrowsize => \"0.5\"))" ] }, "execution_count": 27, "metadata": {}, "output_type": "execute_result" } ], "source": [ "L = homomorphism(Graph(1), t)\n", "rule = Rule(L,id(Graph(1)))\n", "to_graphviz(apply_parallel_rule(rule, G))\n" ] }, { "cell_type": "markdown", "id": "271299a4", "metadata": {}, "source": [ "This rewrite rule matches a span of arrows and removes the edges." ] }, { "cell_type": "code", "execution_count": 28, "id": "9a7443a2", "metadata": {}, "outputs": [ { "data": { "image/svg+xml": [ "\n", "\n", "\n", "\n", "\n", "\n", "G\n", "\n", "\n", "\n", "n1\n", "\n", "\n", "\n", "\n", "n2\n", "\n", "\n", "\n", "\n", "n1->n2\n", "\n", "\n", "\n", "\n", "\n", "n3\n", "\n", "\n", "\n", "\n", "n1->n3\n", "\n", "\n", "\n", "\n", "\n" ], "text/plain": [ "Catlab.Graphics.Graphviz.Graph(\"G\", true, \"dot\", Catlab.Graphics.Graphviz.Statement[Catlab.Graphics.Graphviz.Node(\"n1\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"\")), Catlab.Graphics.Graphviz.Node(\"n2\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"\")), Catlab.Graphics.Graphviz.Node(\"n3\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n1\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n2\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}()), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n1\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n3\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}())], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:rankdir => \"LR\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:height => \"0.05\", :margin => \"0\", :shape => \"point\", :width => \"0.05\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:arrowsize => \"0.5\"))" ] }, "execution_count": 28, "metadata": {}, "output_type": "execute_result" } ], "source": [ "l = @acset Graph begin V=3; E=2; src=[1,1]; tgt=[2,3] end\n", "L = homomorphism(Graph(3), l; monic=true); R=id(Graph(3))\n", "to_graphviz(l)" ] }, { "cell_type": "markdown", "id": "db0714b8", "metadata": {}, "source": [ "The pattern has 6 possible matches (given a `monic` constraint), but only one can be run in parallel." ] }, { "cell_type": "code", "execution_count": 29, "id": "9a9991d0", "metadata": {}, "outputs": [ { "data": { "image/svg+xml": [ "\n", "\n", "\n", "\n", "\n", "\n", "G\n", "\n", "\n", "\n", "n1\n", "\n", "\n", "\n", "\n", "n2\n", "\n", "\n", "\n", "\n", "n1->n2\n", "\n", "\n", "\n", "\n", "\n", "n3\n", "\n", "\n", "\n", "\n", "n1->n3\n", "\n", "\n", "\n", "\n", "\n", "n4\n", "\n", "\n", "\n", "\n", "n1->n4\n", "\n", "\n", "\n", "\n", "\n" ], "text/plain": [ "Catlab.Graphics.Graphviz.Graph(\"G\", true, \"dot\", Catlab.Graphics.Graphviz.Statement[Catlab.Graphics.Graphviz.Node(\"n1\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"\")), Catlab.Graphics.Graphviz.Node(\"n2\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"\")), Catlab.Graphics.Graphviz.Node(\"n3\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"\")), Catlab.Graphics.Graphviz.Node(\"n4\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n1\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n2\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}()), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n1\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n3\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}()), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n1\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n4\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}())], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:rankdir => \"LR\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:height => \"0.05\", :margin => \"0\", :shape => \"point\", :width => \"0.05\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:arrowsize => \"0.5\"))" ] }, "execution_count": 29, "metadata": {}, "output_type": "execute_result" } ], "source": [ "G = @acset Graph begin V=4; E=3; src=[1,1,1]; tgt=[2,3,4] end\n", "to_graphviz(G)" ] }, { "cell_type": "markdown", "id": "6559727a", "metadata": {}, "source": [ "So we expect one edge remaining from applying the rule in parallel." ] }, { "cell_type": "code", "execution_count": 30, "id": "2ca24b67", "metadata": {}, "outputs": [ { "data": { "image/svg+xml": [ "\n", "\n", "\n", "\n", "\n", "\n", "G\n", "\n", "\n", "\n", "n1\n", "\n", "\n", "\n", "\n", "n4\n", "\n", "\n", "\n", "\n", "n1->n4\n", "\n", "\n", "\n", "\n", "\n", "n2\n", "\n", "\n", "\n", "\n", "n3\n", "\n", "\n", "\n", "\n" ], "text/plain": [ "Catlab.Graphics.Graphviz.Graph(\"G\", true, \"dot\", Catlab.Graphics.Graphviz.Statement[Catlab.Graphics.Graphviz.Node(\"n1\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"\")), Catlab.Graphics.Graphviz.Node(\"n2\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"\")), Catlab.Graphics.Graphviz.Node(\"n3\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"\")), Catlab.Graphics.Graphviz.Node(\"n4\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n1\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n4\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}())], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:rankdir => \"LR\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:height => \"0.05\", :margin => \"0\", :shape => \"point\", :width => \"0.05\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:arrowsize => \"0.5\"))" ] }, "execution_count": 30, "metadata": {}, "output_type": "execute_result" } ], "source": [ "to_graphviz(apply_parallel_rule(Rule(L,R), G; monic=true))" ] }, { "cell_type": "markdown", "id": "88969d05", "metadata": {}, "source": [ "Negative application conditions allow us to restrict us from deleting edges that are pointing to something with a self loop, for example." ] }, { "cell_type": "code", "execution_count": 31, "id": "bd0cc218", "metadata": {}, "outputs": [ { "data": { "image/svg+xml": [ "\n", "\n", "\n", "\n", "\n", "\n", "G\n", "\n", "\n", "\n", "n1\n", "\n", "\n", "\n", "\n", "n2\n", "\n", "\n", "\n", "\n", "n1->n2\n", "\n", "\n", "\n", "\n", "\n", "n3\n", "\n", "\n", "\n", "\n", "n1->n3\n", "\n", "\n", "\n", "\n", "\n", "n2->n2\n", "\n", "\n", "\n", "\n", "\n", "n3->n3\n", "\n", "\n", "\n", "\n", "\n" ], "text/plain": [ "Catlab.Graphics.Graphviz.Graph(\"G\", true, \"dot\", Catlab.Graphics.Graphviz.Statement[Catlab.Graphics.Graphviz.Node(\"n1\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"\")), Catlab.Graphics.Graphviz.Node(\"n2\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"\")), Catlab.Graphics.Graphviz.Node(\"n3\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n1\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n2\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}()), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n1\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n3\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}()), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n2\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n2\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}()), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n3\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n3\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}())], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:rankdir => \"LR\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:height => \"0.05\", :margin => \"0\", :shape => \"point\", :width => \"0.05\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:arrowsize => \"0.5\"))" ] }, "execution_count": 31, "metadata": {}, "output_type": "execute_result" } ], "source": [ "n = @acset Graph begin V=3; E=4; src=[1,1,2,3]; tgt=[2,3,2,3] end\n", "N = homomorphism(l,n; monic=true)\n", "to_graphviz(n) # this pattern is forbidden in a match" ] }, { "cell_type": "markdown", "id": "aeb3e007", "metadata": {}, "source": [ "Now we'll modify `G` to have self loops on all but one of the edges. With the monic constraint, there are no longer any possible matches." ] }, { "cell_type": "code", "execution_count": 32, "id": "19d8b3f2", "metadata": {}, "outputs": [ { "data": { "image/svg+xml": [ "\n", "\n", "\n", "\n", "\n", "\n", "G\n", "\n", "\n", "\n", "n1\n", "\n", "\n", "\n", "\n", "n4\n", "\n", "\n", "\n", "\n", "n1->n4\n", "\n", "\n", "\n", "\n", "\n", "n2\n", "\n", "\n", "\n", "\n", "n2->n2\n", "\n", "\n", "\n", "\n", "\n", "n3\n", "\n", "\n", "\n", "\n", "n4->n4\n", "\n", "\n", "\n", "\n", "\n" ], "text/plain": [ "Catlab.Graphics.Graphviz.Graph(\"G\", true, \"dot\", Catlab.Graphics.Graphviz.Statement[Catlab.Graphics.Graphviz.Node(\"n1\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"\")), Catlab.Graphics.Graphviz.Node(\"n2\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"\")), Catlab.Graphics.Graphviz.Node(\"n3\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"\")), Catlab.Graphics.Graphviz.Node(\"n4\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n1\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n4\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}()), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n2\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n2\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}()), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n4\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n4\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}())], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:rankdir => \"LR\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:height => \"0.05\", :margin => \"0\", :shape => \"point\", :width => \"0.05\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:arrowsize => \"0.5\"))" ] }, "execution_count": 32, "metadata": {}, "output_type": "execute_result" } ], "source": [ "G = @acset Graph begin V=4; E=5; src=[1,1,1,2,3]; tgt=[2,3,4,2,3] end\n", "#@assert is_isomorphic(apply_parallel_rule(Rule(L,R,N), G; monic=true), G)\n", "to_graphviz(apply_parallel_rule(Rule(L,R,N), G; monic=true))" ] }, { "cell_type": "markdown", "id": "62c9c903", "metadata": {}, "source": [ "We last show some rewriting with attributes (Attributed C-Sets, or ACSets). We'll define a graph with weights on edges. (note, visualization will not show the weights on the edges by default)" ] }, { "cell_type": "code", "execution_count": 33, "id": "f6a40f41", "metadata": {}, "outputs": [ { "data": { "image/svg+xml": [ "\n", "\n", "\n", "\n", "\n", "\n", "G\n", "\n", "\n", "\n", "n1\n", "\n", "\n", "\n", "\n", "n2\n", "\n", "\n", "\n", "\n", "n1->n2\n", "\n", "\n", "\n", "\n", "\n", "n1->n2\n", "\n", "\n", "\n", "\n", "\n" ], "text/plain": [ "Catlab.Graphics.Graphviz.Graph(\"G\", true, \"dot\", Catlab.Graphics.Graphviz.Statement[Catlab.Graphics.Graphviz.Node(\"n1\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"\")), Catlab.Graphics.Graphviz.Node(\"n2\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n1\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n2\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}()), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n1\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n2\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}())], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:rankdir => \"LR\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:height => \"0.05\", :margin => \"0\", :shape => \"point\", :width => \"0.05\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:arrowsize => \"0.5\"))" ] }, "execution_count": 33, "metadata": {}, "output_type": "execute_result" } ], "source": [ "using Catlab.Graphs.BasicGraphs: TheoryGraph\n", "@present TheoryLabeledGraph <: TheoryGraph begin\n", " (Weight)::AttrType\n", " weight::Attr(E,Weight)\n", "end\n", "@acset_type LabeledGraph(TheoryLabeledGraph, index=[:src,:tgt]) <: AbstractGraph\n", "WeightedGraph = LabeledGraph{Float64}\n", "WeightedGraphVar = LabeledGraph{Union{Expr, Var, Float64}}\n", "l = @acset WeightedGraph begin V=2; E=2; src=[1,1]; tgt=[2,2]; weight=[1.0, 2.0] end\n", "to_graphviz(l)" ] }, { "cell_type": "markdown", "id": "fd4ff6c6", "metadata": {}, "source": [ "Algorithms using ACSet morphisms (e.g. pushouts) typically demand equality on attributes. Therefore, the above pattern can only match pairs of edges that are equal to 1.0 and 2.0. Not very useful. Rather, when we match on attributes, we often want the pattern to have some sort of _variable_. The `apply_parallel_rule` and homomorphism finding functions are designed to treat attributes of type `Var` differently. This rule matches two edges and replaces them with one edge (with the sum of the weights)." ] }, { "cell_type": "code", "execution_count": null, "id": "263e3f74", "metadata": {}, "outputs": [], "source": [ "l = @acset WeightedGraphVar begin V=2; E=2; src=[1,1]; tgt=[2,2]; weight=[Var(:a), Var(:b)] end\n", "i = @acset WeightedGraphVar begin V=2 end\n", "r = @acset WeightedGraphVar begin V=2; E=1; src=[1]; tgt=[2]; weight=[:(Var(:a)+Var(:b))] end \n", "L = homomorphism(i,l;monic=true); R = homomorphism(i,r;monic=true)\n", "rule = Rule(L,R)\n", "\n", "G = @acset WeightedGraph begin V=3; E=5; src=[1,1,1,1,1]; tgt=[2,2,2,3,3]; weight = [1,2,3,10,20] end\n", "res = normalize([rule], G)[:weight];\n", "res" ] }, { "cell_type": "markdown", "id": "dc995251", "metadata": {}, "source": [ "The way this works under the hood is that homomorphism search for a match actually returns a normal ACSet morphism and a dictionary saying what it substituted for each variable. This dictionary is then used to update `R` (and the negative application condition, if any) on the fly, and then a normal DPO rewrite proceeds." ] } ], "metadata": { "@webio": { "lastCommId": null, "lastKernelId": null }, "kernelspec": { "display_name": "Julia O3 1.7.1", "language": "julia", "name": "julia-o3-1.7" }, "language_info": { "file_extension": ".jl", "mimetype": "application/julia", "name": "julia", "version": "1.7.1" } }, "nbformat": 4, "nbformat_minor": 5 }