Skip to content

Commit 32318b8

Browse files
committed
WIP: parsing Decapodes
1 parent b7049e2 commit 32318b8

10 files changed

Lines changed: 1497 additions & 4 deletions

File tree

packages/algjulia-interop/Project.toml

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
name = "CatColabInterop"
22
uuid = "9ecda8fb-39ab-46a2-a496-7285fa6368c1"
33
license = "MIT"
4-
version = "0.1.1"
54
authors = ["CatColab team"]
5+
version = "0.1.1"
66

77
[deps]
88
HTTP = "cd3eb016-35fb-5094-929b-558a96fad6f3"
@@ -14,12 +14,17 @@ StructTypes = "856f2bd8-1eba-4b0a-8007-ebc267875bd4"
1414
[weakdeps]
1515
ACSets = "227ef7b5-1206-438b-ac65-934d6da304b8"
1616
Catlab = "134e5e36-593f-5add-ad60-77f754baafbe"
17+
Decapodes = "679ab3ea-c928-4fe6-8d59-fd451142d391"
18+
DiagrammaticEquations = "6f00c28b-6bed-4403-80fa-30e0dc12f317"
1719

1820
[extensions]
1921
CatlabExt = ["Catlab", "ACSets"]
22+
DecapodesExt = ["Decapodes", "DiagrammaticEquations", "ACSets"]
2023

2124
[compat]
2225
Catlab = "0.17.2"
26+
Decapodes = "0.6.5"
27+
DiagrammaticEquations = "0.2.1"
2328
HTTP = "1.10.19"
2429
MLStyle = "0.4.17"
2530
Oxygen = "1.7.5"
Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
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

packages/algjulia-interop/scripts/endpoint.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ function CorsHandler(handle)
2929
end
3030
end
3131

32-
defaults = [:Catlab,:ACSets] # all extensions to date
32+
defaults = [:Catlab,:ACSets,:DiagrammaticEquations,:Decapodes] # all extensions to date
3333

3434
# Dynamically load packages in command lin eargs
3535
for pkg in (isempty(ARGS) ? defaults : ARGS )

packages/algjulia-interop/test/Project.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,10 @@
22
ACSets = "227ef7b5-1206-438b-ac65-934d6da304b8"
33
CatColabInterop = "9ecda8fb-39ab-46a2-a496-7285fa6368c1"
44
Catlab = "134e5e36-593f-5add-ad60-77f754baafbe"
5+
Decapodes = "679ab3ea-c928-4fe6-8d59-fd451142d391"
6+
DiagrammaticEquations = "6f00c28b-6bed-4403-80fa-30e0dc12f317"
57
HTTP = "cd3eb016-35fb-5094-929b-558a96fad6f3"
68
JSON3 = "0f8b85d8-7281-11e9-16c2-39a750bddbf1"
79
Oxygen = "df9a0d86-3283-4920-82dc-4555fc0d1d8b"
810
StructTypes = "856f2bd8-1eba-4b0a-8007-ebc267875bd4"
11+
Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
module TestDecapodes
2+
3+
using CatColabInterop
4+
using DiagrammaticEquations, Decapodes, ACSets
5+
using HTTP, Test, Oxygen, JSON3
6+
7+
const DecapodesExt = Base.get_extension(CatColabInterop, :DecapodesExt)
8+
9+
# Example JSON
10+
#-------------
11+
body = read((@__DIR__)*"/data/diagrams/ns_vort/analysis.json", String)
12+
13+
# Parse the JSON
14+
#---------------
15+
p = JSON3.read(body, ModelDiagram)
16+
17+
# Optinally test the endpoint if running endpoint.jl
18+
resp = HTTP.post("http://127.0.0.1:8080/decapodes"; body)
19+
# @test resp.status == 200
20+
21+
end

0 commit comments

Comments
 (0)