|
| 1 | +module DecapodesExt |
| 2 | + |
| 3 | +using MLStyle |
| 4 | + |
| 5 | +using DiagrammaticEquations |
| 6 | +import DiagrammaticEquations: SummationDecapode |
| 7 | +using Decapodes |
| 8 | +using ACSets |
| 9 | + |
| 10 | +using CatColabInterop, Oxygen, HTTP |
| 11 | +import CatColabInterop: endpoint |
| 12 | + |
| 13 | +struct ImplError <: Exception |
| 14 | + name::String |
| 15 | +end |
| 16 | +export ImplError |
| 17 | +Base.showerror(io::IO, e::ImplError) = print(io, "$(e.name) not implemented") |
| 18 | + |
| 19 | +""" Helper function to convert CatColab values (Obs) in Decapodes """ |
| 20 | +function ob_type(name::String) |
| 21 | + @match lowercase(name) begin |
| 22 | + "0-form" => :Form0 |
| 23 | + "1-form" => :Form1 |
| 24 | + "2-form" => :Form2 |
| 25 | + "primal 0-form" => :Form0 |
| 26 | + "primal 1-form" => :Form1 |
| 27 | + "primal 2-form" => :Form2 |
| 28 | + "dual 0-form" => :DualForm0 |
| 29 | + "dual 1-form" => :DualForm1 |
| 30 | + "dual 2-form" => :DualForm2 |
| 31 | + x => throw(ImplError(x)) |
| 32 | + end |
| 33 | +end |
| 34 | + |
| 35 | +""" Helper function to convert CatColab values (Homs) in Decapodes """ |
| 36 | +function mor_name(name::String) |
| 37 | + @match replace(name," " => "") begin |
| 38 | + "∂t" || "∂ₜ" => :∂ₜ |
| 39 | + "Δ" => :Δ |
| 40 | + "Δ⁻¹" => :Δ⁻¹ |
| 41 | + "d*" || "d̃₁" => :dual_d₁ |
| 42 | + "⋆" || "⋆₁" || "★₁" || "★1" => :⋆₁ |
| 43 | + "⋆⁻¹" || "⋆₀⁻¹" => :⋆₀⁻¹ |
| 44 | + "★" || "★⁻¹" => :⋆₁ |
| 45 | + "d" || "d₀" || "d01" => :d₀ |
| 46 | + "d12" => :d₁ |
| 47 | + "⋆2" => :⋆₂ |
| 48 | + "♭♯" => :♭♯ |
| 49 | + "lamb" => :dpsw # dual-primal self-wedge |
| 50 | + "-" => :neg |
| 51 | + x => throw(ImplError(x)) |
| 52 | + end |
| 53 | +end |
| 54 | + |
| 55 | +function model_to_pode(m::Types.Model) |
| 56 | + obs, mors = [], [] |
| 57 | + names = Dict{String, String}() |
| 58 | + for stmt in m.obGenerators |
| 59 | + names[stmt.id] = only(stmt.label) |
| 60 | + if stmt.obType.content == "Object" |
| 61 | + push!(obs, names[stmt.id]) |
| 62 | + end |
| 63 | + end |
| 64 | + for stmt in m.morGenerators |
| 65 | + h = (only(stmt.label), names[stmt.dom.content], names[stmt.cod.content]) |
| 66 | + names[stmt.id] = h[1] |
| 67 | + if stmt.morType.content == "Nonscalar" |
| 68 | + push!(mors, h) |
| 69 | + end |
| 70 | + end |
| 71 | + (names, obs, mors) |
| 72 | +end |
| 73 | +export model_to_pode |
| 74 | + |
| 75 | +function diagram_to_pode(md::Types.ModelDiagram) |
| 76 | + # TODO would be nice to just index the model |
| 77 | + names, obs, mors = model_to_pode(md.model) |
| 78 | + |
| 79 | + pode = SummationDecapode(parse_decapode(quote end)) |
| 80 | + diagram_names = Dict{String, Symbol}() |
| 81 | + for stmt in md.diagram.obGenerators |
| 82 | + if stmt.obType.content == "Object" |
| 83 | + # TODO label can be a vector |
| 84 | + name = only(stmt.label) # TODO may be integer |
| 85 | + type = ob_type(names[stmt.over.content]) |
| 86 | + diagram_names[stmt.id] = Symbol(name) |
| 87 | + id = add_part!(pode, :Var, name=Symbol(name), type=type) |
| 88 | + end |
| 89 | + end |
| 90 | + for stmt in md.diagram.morGenerators |
| 91 | + if stmt.morType.content == "Nonscalar" |
| 92 | + dom = incident(pode, diagram_names[stmt.dom.content], :name) |
| 93 | + cod = incident(pode, diagram_names[stmt.cod.content], :name) |
| 94 | + name = names[stmt.over.content] |
| 95 | + id = add_part!(pode, :Op1, src=only(dom), tgt=only(cod), op1=name) |
| 96 | + if name == :∂ₜ |
| 97 | + add_part!(pode, :TVar, incl=cod) |
| 98 | + end |
| 99 | + end |
| 100 | + end |
| 101 | + infer_types!(pode) |
| 102 | + return pode |
| 103 | +end |
| 104 | +export diagram_to_pode |
| 105 | + |
| 106 | +""" |
| 107 | +""" |
| 108 | + |
| 109 | +function endpoint(::Val{:Decapodes}) |
| 110 | + @post "/decapodes" function (req::HTTP.Request) |
| 111 | + payload = json(req, ModelDiagram) |
| 112 | + pode = diagram_to_pode(payload) |
| 113 | + end |
| 114 | +end |
| 115 | + |
| 116 | +end # module |
0 commit comments