diff --git a/packages/algjulia-interop/Project.toml b/packages/algjulia-interop/Project.toml index 9e270ce35..ba2395379 100644 --- a/packages/algjulia-interop/Project.toml +++ b/packages/algjulia-interop/Project.toml @@ -5,6 +5,15 @@ authors = ["CatColab team"] version = "0.1.1" [deps] +HTTP = "cd3eb016-35fb-5094-929b-558a96fad6f3" +JSON3 = "0f8b85d8-7281-11e9-16c2-39a750bddbf1" +MLStyle = "d8e11817-5142-5d16-987a-aa16d5891078" +Oxygen = "df9a0d86-3283-4920-82dc-4555fc0d1d8b" +Reexport = "189a3867-3050-52da-a836-e630ba90ab69" +StructTypes = "856f2bd8-1eba-4b0a-8007-ebc267875bd4" +TOML = "fa267f1f-6049-4f14-aa54-33bafae1ed76" + +[weakdeps] ACSets = "227ef7b5-1206-438b-ac65-934d6da304b8" Catlab = "134e5e36-593f-5add-ad60-77f754baafbe" CombinatorialSpaces = "b1c52339-7909-45ad-8b6a-6e388f7c67f2" @@ -14,40 +23,21 @@ Decapodes = "679ab3ea-c928-4fe6-8d59-fd451142d391" DiagrammaticEquations = "6f00c28b-6bed-4403-80fa-30e0dc12f317" Distributions = "31c24e10-a181-5473-b8eb-7969acd0382f" GeometryBasics = "5c1252a2-5f33-56bf-86c9-59e7332b4326" -IJulia = "7073ff75-c697-5162-941a-fcdaad2a7d2a" -JSON3 = "0f8b85d8-7281-11e9-16c2-39a750bddbf1" LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" -MLStyle = "d8e11817-5142-5d16-987a-aa16d5891078" OrdinaryDiffEq = "1dea7af3-3e70-54e6-95c3-0bf5283fa5ed" -Preferences = "21216c6a-2e73-6563-6e65-726566657250" -REPL = "3fa0cd96-eef1-5676-8a61-b3b8758bbffb" -Reexport = "189a3867-3050-52da-a836-e630ba90ab69" StaticArrays = "90137ffa-7385-5640-81b9-e52037218182" -[weakdeps] -PackageCompiler = "9b87118b-4619-50d2-8e1e-99f35a4d4d9d" - [extensions] -SysImageExt = "PackageCompiler" +CatlabExt = ["Catlab", "ACSets"] +DecapodesExt = ["DiagrammaticEquations", "Decapodes", "ACSets", "CombinatorialSpaces", "JSON3", "StaticArrays", "LinearAlgebra", "ComponentArrays", "Distributions", "CoordRefSystems", "GeometryBasics", "OrdinaryDiffEq"] [compat] -ACSets = "0.2.21" -Catlab = "0.16.20" -CombinatorialSpaces = "0.7.4" -ComponentArrays = "0.15" -CoordRefSystems = "0.18.9" -Decapodes = "0.6" -DiagrammaticEquations = "0.2" -Distributions = "0.25" -GeometryBasics = "0.5.7" -IJulia = "1.26.0" -JSON3 = "1" -LinearAlgebra = "1" -MLStyle = "0.4" -OrdinaryDiffEq = "6.101.0" -PackageCompiler = "2.2.1" -Preferences = "1.5.0" -REPL = "1.11.0" +Catlab = "0.17.3" +HTTP = "1.10.19" +JSON3 = "1.14.3" +MLStyle = "0.4.17" +Oxygen = "1.7.5" Reexport = "1.2.2" -StaticArrays = "1" +StructTypes = "1.11.0" +TOML = "1.0.3" julia = "1.11" diff --git a/packages/algjulia-interop/ext/CatlabExt.jl b/packages/algjulia-interop/ext/CatlabExt.jl new file mode 100644 index 000000000..572307943 --- /dev/null +++ b/packages/algjulia-interop/ext/CatlabExt.jl @@ -0,0 +1,86 @@ +module CatlabExt + +using ACSets +using Catlab: Presentation, FreeSchema +import Catlab: id, dom +using Catlab.CategoricalAlgebra.Pointwise.FunctorialDataMigrations.Yoneda: + yoneda, colimit_representables, DiagramData +using CatColabInterop, Oxygen, HTTP +import CatColabInterop: endpoint + +# workaround, could be upstreamed +""" +If we call `id(X::FreeSchema.Ob{:generator})` we get a FreeSchema.Hom. However, +there is no analogue for attribute types. For `list_to_hom` (a function within) +`colimit_representables` to be concisely defined, we need such an analogue. +`IdAttr` is workaround type intended to fill this absence. +""" +struct IdAttr{T} x::FreeSchema.AttrType{:generator} end +dom(i::IdAttr) = i.x +id(x::FreeSchema.AttrType{:generator}) = IdAttr{:id}(x) + + +function model_to_schema(m::Model)::Tuple{Schema, Dict{String,Symbol}} + obs, homs, attrtypes, attrs = Symbol[],[],[],[] + names = Dict{String, Symbol}() + for stmt in m.obGenerators + names[stmt.id] = Symbol(only(stmt.label)) + if stmt.obType.content == "Entity" + push!(obs, names[stmt.id]) + elseif stmt.obType.content == "AttrType" + push!(attrtypes, names[stmt.id]) + else + error(stmt.obType) + end + end + for stmt in m.morGenerators + h = (Symbol(only(stmt.label)), names[stmt.dom.content], names[stmt.cod.content]) + names[stmt.id] = h[1] + if stmt.morType.content == "Attr" + push!(attrs, h) + else + push!(homs, h) + end + end + (Schema(Presentation(BasicSchema{Symbol}(obs, homs, attrtypes, attrs, []))), names) +end + +function diagram_to_data(d::Types.Diagram, names::Dict{String,Symbol})::DiagramData + data = DiagramData() + for o in d.obGenerators + names[o.id] = Symbol(only(o.label)) + push!(data.reprs[names[o.over.content]], names[o.id]) + end + for m in d.morGenerators + p1 = names[m.cod.content] => Symbol[] + p2 = names[m.dom.content] => [names[m.over.content]] + push!(data.eqs, p1 => p2) + end + data +end + +""" Receiver of the data already knows the schema """ +function acset_to_json(X::ACSet, S::Schema)::AbstractDict + Dict{Symbol, Union{Int,Vector{Int}}}( + [t => nparts(X, t) for t in types(S)] + ∪ [f => X[f] for f in homs(S; just_names=true)] + ∪ [f => getvalue.(X[f]) for f in attrs(S; just_names=true)] ) +end + +""" +Compute ACSet colimit of a diagrammatic instance. Return a tabular representation +""" +function endpoint(::Val{:ACSetColim}) + @post "/acsetcolim" function(req::HTTP.Request) + payload = json(req, ModelDiagram) + schema, names = model_to_schema(payload.model) + data = diagram_to_data(payload.diagram, names) + acset_type = AnonACSet( + schema; type_assignment=Dict(a=>Nothing for a in schema.attrtypes)) + y = yoneda(constructor(acset_type)) + res = colimit_representables(data, y) + acset_to_json(res, schema) + end +end + +end # module diff --git a/packages/algjulia-interop/ext/DecapodesExt/DecapodesExt.jl b/packages/algjulia-interop/ext/DecapodesExt/DecapodesExt.jl new file mode 100644 index 000000000..7526416f0 --- /dev/null +++ b/packages/algjulia-interop/ext/DecapodesExt/DecapodesExt.jl @@ -0,0 +1,65 @@ +module DecapodesExt + +import Base: run + +# algebraicjulia dependencies +using ACSets +using DiagrammaticEquations +using Decapodes +using CombinatorialSpaces + +# dependencies +import JSON3 +using StaticArrays +using MLStyle +using LinearAlgebra +using ComponentArrays +using Distributions # for initial conditions + +# meshing +using CoordRefSystems +using GeometryBasics: Point2, Point3 +Point3D = Point3{Float64} + +# simulation +using OrdinaryDiffEq + + +using CatColabInterop, Oxygen, HTTP +import CatColabInterop: Model, ModelDiagram, ObGenerator, MorGenerator, DiagramObGenerator, DiagramMorGenerator +import CatColabInterop: endpoint + +# necessary to export +export infer_types!, evalsim, default_dec_generate, default_dec_matrix_generate, DiagonalHodge, ComponentArray + +include("interop.jl") + +# functions for geometry and initial conditions +include("geometry.jl") + +# helper functions for Navier-Stokes +include("ns_helper.jl") + +# constructing initial conditions +include("initial_conditions.jl") + +# constructs a simulation from the payload +include("simulation.jl") + +# executes the analysis +include("execute.jl") + +""" +""" +function endpoint(::Val{:DecapodeSimulation}) + @post "/decapodes-simulation" function(req::HTTP.Request) + payload = json(req, ModelDiagrma) + simulation = DecapodesSimulation(payload) + sim = evalsim(simulation.pode) + f = sim(simulation.geometry.dualmesh, simulation.generate, DiagonalHodge()) + res = run(f, simulation, ComponentArray(k=0.5,)) + sim_to_json(res) + end +end + +end diff --git a/packages/algjulia-interop/ext/DecapodesExt/execute.jl b/packages/algjulia-interop/ext/DecapodesExt/execute.jl new file mode 100644 index 000000000..11f66427c --- /dev/null +++ b/packages/algjulia-interop/ext/DecapodesExt/execute.jl @@ -0,0 +1,73 @@ +""" """ +function Base.run(fm, sim::DecapodeSimulation, constparam) + prob = ODEProblem(fm, sim.init, sim.duration, constparam) + soln = solve(prob, Tsit5(), saveat=0.01) + SimResult(soln, sim) +end + +abstract type AbstractResult end + +struct SimResult <: AbstractResult + retcode::Enum{Int32} # ReturnCode + time::Vector{Float64} + state::Dict{String, Vector{AbstractArray{SVector{3, Float64}}}} + x::Vector{Float64} # axis + y::Vector{Float64} +end +export SimResult + +function SimResult(soln::ODESolution, system::DecapodeSimulation) + idx_bounds = indexing_bounds(system) + state_val_dict = variables_state(soln, system) # Dict("UUID1" => VectorMatrixSVectr...) + SimResult(soln.retcode, soln.t, state_val_dict, 0:idx_bounds.x, 0:idx_bounds.y) +end +# TODO generalize to HasDeltaSet + +points(system::DecapodeSimulation) = collect(values(system.geometry.dualmesh.subparts.point.m)) +indexing_bounds(system::DecapodeSimulation) = indexing_bounds(system.geometry.domain) + +""" for the variables in a system, associate them to their state values over the duration of the simulation """ +function variables_state(soln::ODESolution, system::DecapodeSimulation) + plottedVars = [ k for (k, v) in system.plotVariables if v == true ] + uuid2symb = Dict([ v => k for (k, v) in system.uuiddict]) # TODO why reverse again? + Dict([ String(uuid2symb[var]) => state_entire_sim(soln, system, uuid2symb[var]) for var ∈ plottedVars ]) +end + +""" given a simulation, a domain, and a variable, gets the state values over the duration of a simulation. +Called by `variables_state`[@ref] """ +function state_entire_sim(soln::ODESolution, system::DecapodeSimulation, var::Symbol) + map(1:length(soln.t)) do i + state_at_time(soln, system, var, i) + end +end + +# TODO type `points` +function state_at_time(soln::ODESolution, system::DecapodeSimulation, plotvar::Symbol, t::Int) + @match system.geometry.domain begin + # TODO check time indexing here + domain::Rectangle => state_at_time(soln, domain, plotvar, t) + domain::Sphere => state_at_time(soln, domain, plotvar, t, points(system)) + _ => throw(ImplError("state_at_time function for domain $domain")) + end +end + +function state_at_time(soln::ODESolution, domain::Rectangle, var::Symbol, t::Int) + (x, y) = indexing_bounds(domain) + [SVector(i, j, getproperty(soln.u[t], var)[(x+1)*(i-1) + j]) for i in 1:x+1, j in 1:y+1] +end + +# TODO just separated this from the SimResult function and added type parameters, but need to generalize +function grid(pt3::Point3, grid_size::Vector{Int}) + pt2 = [(pt3[1]+1)/2, (pt3[2]+1)/2] + [round(Int, pt2[1]*grid_size[1]), round(Int, pt2[2]*grid_size[2])] +end + +function state_at_time(soln::ODESolution, domain::Sphere, var::Symbol, t::Int, points) + l , _ = indexing_bounds(domain) # TODO this is hardcoded to return 100, 100 + northern_indices = filter(i -> points[i][3] > 0, keys(points)) + map(northern_indices) do n + i, j = grid(points[n], [l, l]) # TODO + SVector(i, j, getproperty(soln.u[t], var)[n]) + end +end + diff --git a/packages/algjulia-interop/src/decapodes-service/geometry.jl b/packages/algjulia-interop/ext/DecapodesExt/geometry.jl similarity index 92% rename from packages/algjulia-interop/src/decapodes-service/geometry.jl rename to packages/algjulia-interop/ext/DecapodesExt/geometry.jl index addb0201c..bd14a146a 100644 --- a/packages/algjulia-interop/src/decapodes-service/geometry.jl +++ b/packages/algjulia-interop/ext/DecapodesExt/geometry.jl @@ -83,6 +83,16 @@ function Geometry(json_object::AbstractDict) Geometry(domain) end +function Geometry(analysis::Analysis) + domain = PREDEFINED_MESHES[Symbol(analysis.analysis[:mesh])] + Geometry(domain) +end + +# function Geometry(payload::DiagramPayload{ThDecapode}) +# domain = PREDEFINED_MESHES[Symbol(payload.data[:mesh])] +# Geometry(domain) +# end + # function Geometry(d::Domain, args...) # throw(ImplError("The mesh ($(d)) is")) # end diff --git a/packages/algjulia-interop/src/decapodes-service/analysis/initial_conditions.jl b/packages/algjulia-interop/ext/DecapodesExt/initial_conditions.jl similarity index 97% rename from packages/algjulia-interop/src/decapodes-service/analysis/initial_conditions.jl rename to packages/algjulia-interop/ext/DecapodesExt/initial_conditions.jl index 29ce151f6..5d0df3951 100644 --- a/packages/algjulia-interop/src/decapodes-service/analysis/initial_conditions.jl +++ b/packages/algjulia-interop/ext/DecapodesExt/initial_conditions.jl @@ -80,7 +80,7 @@ end function initial_conditions(ics::GaussianIC, geometry::Geometry) c_dist = MvNormal(ics.ξ) - c = [pdf(c_dist, [p[1], p[2]]) for p ∈ geometry.dualmesh[:point]] + c = [Distributions.pdf(c_dist, [p[1], p[2]]) for p ∈ geometry.dualmesh[:point]] return c end diff --git a/packages/algjulia-interop/ext/DecapodesExt/interop.jl b/packages/algjulia-interop/ext/DecapodesExt/interop.jl new file mode 100644 index 000000000..d0f5337c9 --- /dev/null +++ b/packages/algjulia-interop/ext/DecapodesExt/interop.jl @@ -0,0 +1,86 @@ +# TODO change to Analysis + +@kwdef mutable struct DecapodeDiagram + pode::SummationDecapode = SummationDecapode(parse_decapode(quote end)) + scalars::Dict{Symbol, String} = Dict{Symbol, String}() + vars::Dict{String, Int} = Dict{String, Int}() + nc::Dict{Int, String} = Dict{Int, String}() +end + +function Base.push!(diagram::DecapodeDiagram, analysis::Analysis, ob::DiagramObGenerator) + model_elem = only(filter(x->x.id==ob.over.content, analysis.model.obGenerators)) + name = if isempty(ob.label) + id = isempty(keys(diagram.nc)) ? 1 : maximum(keys(diagram.mc)) + 1 + push!(diagram.nc, id => "") + Symbol("•$id") + else + Symbol(join(string.(ob.label),".")) + end + id = add_part!(diagram.pode, :Var, name=name, type=nameof(model_elem)) + push!(diagram.vars, ob.id => id) + diagram +end + +# TODO remove only when we have multiple source/targets +function mor_dom(diagram::Diagram, mor::DiagramMorGenerator) + filter(ob -> ob.id == mor.dom.content, diagram.obGenerators) |> only +end + +function mor_cod(diagram::Diagram, mor::DiagramMorGenerator) + filter(ob -> ob.id == mor.dom.content, diagram.obGenerators) |> only +end + +function Base.nameof(model::Model, mor::DiagramMorGenerator) + model_mor = filter(m -> m.id == mor.over.content, model.morGenerators) |> only + join(model_mor.label, ".") # TODO +end + +function Base.push!(diagram::DecapodeDiagram, analysis::Analysis, mor::DiagramMorGenerator) + dom = mor_dom(analysis.diagram, mor) # get ObGenerator + cod = mor_cod(analysis.diagram, mor) + dom_id = check_endpoint!(diagram, dom) + cod_id = check_endpoint!(diagram, cod) + # get the name of the Op1 and add it to the model + op1 = nameof(analysis.model, mor) + add_part!(diagram.pode, :Op1, src=dom_id, tgt=cod_id, op1=op1) + if op1 == :∂ₜ + add_part!(diagram.pode, :TVar, incl=cod_id) + end + if mor.morType.content isa JSON3.Object + scalar = analysis.model.mor_generators[mor.over.content] + push!(diagram.scalars, scalar.label => mor.over.content) + end + diagram +end + +function DecapodeDiagram(analysis::Analysis) + diagram = DecapodeDiagram() + for ob in analysis.diagram.obGenerators + push!(diagram, analysis, ob) + end + for mor in analysis.diagram.morGenerators + push!(diagram, analysis, mor) + end + return diagram +end + +function check_endpoint!(diagram::DecapodeDiagram, endpoint::DiagramObGenerator) + if haskey(diagram.vars, endpoint.id) + diagram.vars[endpoint.id] + else + if endpoint.id ∉ values(diagram.nc) + id = isempty(keys(diagram.nc)) ? 1 : length(keys(diagram.nc)) + 1 + name = Symbol("•$id") + acset_id = add_part!(diagram.pode, :Var, name=name, type=:infer) + push!(diagram.nc, acset_id => endpoint.label) + acset_id + else + out = filter(x -> x[2] == endpoint, pairs(diagram.nc)) + first(keys(out)) + end + end +end + +function uuid_to_symb(decapode::SummationDecapode, vars::Dict{String, Int}) + Dict([key => (subpart(decapode, vars[key], :name)) for key ∈ keys(vars)]) +end diff --git a/packages/algjulia-interop/ext/DecapodesExt/model.jl b/packages/algjulia-interop/ext/DecapodesExt/model.jl new file mode 100644 index 000000000..17fe741c4 --- /dev/null +++ b/packages/algjulia-interop/ext/DecapodesExt/model.jl @@ -0,0 +1,75 @@ +#= Build the model + +A model for the Decapodes integration is the same as the default Model method. +A dictionary mapping UUID strings with ModelElements is instantiated. +=# +function ObGenerator(::ThDecapode, obgen::AbstractDict) + ObGenerator(obgen[:id], ob_name(ThDecapode(), obgen[:label]), obgen[:obType]) +end +export ObGenerator + +""" Helper function to convert CatColab values (Obs) in Decapodes """ +function ob_name(model::ThDecapode, name::String) + @match lowercase(name) begin + "0-form" => :Form0 + "1-form" => :Form1 + "2-form" => :Form2 + "primal 0-form" => :Form0 + "primal 1-form" => :Form1 + "primal 2-form" => :Form2 + "dual 0-form" => :DualForm0 + "dual 1-form" => :DualForm1 + "dual 2-form" => :DualForm2 + x => throw(ImplError(x)) + end +end +export ob_name + +ob_name(model::ThDecapode, name::AbstractVector) = ob_name(model, join(String.(name), "")) + +# XXX the use of an `only` here means we're being hostile to multiarrows +function MorGenerator(::ThDecapode, ob_generators::Vector{ObGenerator}, morgen::AbstractDict) + dom = only(filter(ob -> ob.id == morgen[:dom][:content], ob_generators)) + cod = only(filter(ob -> ob.id == morgen[:cod][:content], ob_generators)) + MorGenerator(morgen[:id], mor_name(ThDecapode(), morgen[:label]), morgen[:morType], dom, cod) +end +export MorGenerator + +""" Helper function to convert CatColab values (Homs) in Decapodes """ +function mor_name(model::ThDecapode, name::String) + @match replace(name," " => "") begin + "∂t" || "∂ₜ" => :∂ₜ + "Δ" => :Δ + "Δ⁻¹" => :Δ⁻¹ + "d*" || "d̃₁" => :dual_d₁ + "⋆" || "⋆₁" || "★₁" || "★1" => :⋆₁ + "⋆⁻¹" || "⋆₀⁻¹" => :⋆₀⁻¹ + "★" || "★⁻¹" => :⋆₁ + "d" || "d₀" || "d01" => :d₀ + "d12" => :d₁ + "⋆2" => :⋆₂ + "♭♯" => :♭♯ + "lamb" => :dpsw # dual-primal self-wedge + "-" => :neg + x => throw(ImplError(x)) + end +end +export mor_name + +mor_name(model::ThDecapode, name::AbstractVector) = mor_name(model, join(String.(name), "")) + +function Model(::ThDecapode, path::String) + json = JSON3.read(read(path, String)) + Model(ThDecapode(), json) +end + +# for each cell, if it is... +# ...an object, we convert its type to a symbol and add it to the modeldict +# ...a morphism, we add it to the modeldict with a field for the ids of its +# domain and codomain to its +function Model(::ThDecapode, json_model::JSON3.Object) # AbstractDict is the JSON + ob_generators = ObGenerator.(Ref(ThDecapode()), json_model[:obGenerators]) + mor_generators = MorGenerator.(Ref(ThDecapode()), Ref(ob_generators), json_model[:morGenerators]) + Model(ThDecapode(), ob_generators, mor_generators) +end +export Model diff --git a/packages/algjulia-interop/src/decapodes-service/analysis/ns_helper.jl b/packages/algjulia-interop/ext/DecapodesExt/ns_helper.jl similarity index 100% rename from packages/algjulia-interop/src/decapodes-service/analysis/ns_helper.jl rename to packages/algjulia-interop/ext/DecapodesExt/ns_helper.jl diff --git a/packages/algjulia-interop/ext/DecapodesExt/simulation.jl b/packages/algjulia-interop/ext/DecapodesExt/simulation.jl new file mode 100644 index 000000000..747f327cd --- /dev/null +++ b/packages/algjulia-interop/ext/DecapodesExt/simulation.jl @@ -0,0 +1,70 @@ +# ======================================================================= + +""" DecapodeSimulation + +This analysis contains the data necessary to execute a simulation. +""" +struct DecapodeSimulation + pode::SummationDecapode + plotVariables::Dict{String, Bool} + scalars::Dict{Symbol, Any} # closures + geometry::Geometry + init::ComponentArray + generate::Any + uuiddict::Dict{Symbol, String} + duration::Int +end +export DecapodeSimulation + +function DecapodeSimulation(path::String; kwargs...) + payload = JSON3.read(path, Analysis) + DecapodeSimulation(payload; kwargs...) +end + +# TODO we need to amend this so other parameters are provided +function DecapodeSimulation(analysis::Analysis; hodge=GeometricHodge()) + wrapped = DecapodeDiagram(analysis) + plotVars = @match analysis.analysis[:plotVariables] begin + vars::AbstractArray => Dict{String, Bool}(key => key ∈ vars for key ∈ keys(wrapped.vars)) + vars => Dict{String, Bool}( "$key" => var for (key, var) in vars) # TODO + end + dot_rename!(wrapped.pode) + uuid2symb = uuid_to_symb(wrapped.pode, wrapped.vars) + geometry = Geometry(analysis) + ♭♯_m = ♭♯_mat(geometry.dualmesh) + wedge_dp10 = dec_wedge_product_dp(Tuple{1,0}, geometry.dualmesh) + dual_d1_m = dec_dual_derivative(1, geometry.dualmesh) + star0_inv_m = dec_inv_hodge_star(0, geometry.dualmesh, hodge) + Δ0 = Δ(0,geometry.dualmesh) + #fΔ0 = factorize(Δ0); + function sys_generate(s, my_symbol) + op = @match my_symbol begin + sym && if haskey(wrapped.scalars, sym) end => x -> begin + k = scalars[wrapped.scalars[sym]] + k * x + end + :♭♯ => x -> ♭♯_m * x + :dpsw => x -> wedge_dp10(x, star0_inv_m*(dual_d1_m*x)) + :Δ⁻¹ => x -> begin + y = Δ0 \ x + y .- minimum(y) + end + _ => default_dec_matrix_generate(s, my_symbol, hodge) + end + return (args...) -> op(args...) + end + # + @info analysis.analysis[:initialConditions] + u0 = initial_conditions(analysis.analysis[:initialConditions], geometry, uuid2symb) + + # reversing `uuid2symb` into `symbol => uuid.` we need this to reassociate the var to its UUID + symb2uuid = Dict([v => k for (k,v) in pairs(uuid2symb)]) + + # TODO what is anons doing here? + anons = Dict{Symbol, Any}() + DecapodeSimulation(wrapped.pode, plotVars, wrapped.scalars, geometry, u0, sys_generate, symb2uuid, analysis.analysis[:duration]) +end + +Base.show(io::IO, system::DecapodeSimulation) = println(io, system.pode) + + diff --git a/packages/algjulia-interop/ext/SysImageExt.jl b/packages/algjulia-interop/ext/SysImageExt.jl deleted file mode 100644 index 698555ae1..000000000 --- a/packages/algjulia-interop/ext/SysImageExt.jl +++ /dev/null @@ -1,24 +0,0 @@ -module SysImageExt - -import CatColabInterop: ServerConfig, load_kernels!, install_ccl_kernel!, CONFIG -import PackageCompiler: create_sysimage -import IJulia: installkernel - -function install_ccl_kernel!(::Val{:sysimg}; config::ServerConfig=CONFIG, sysimg = "CatColabInteropSysImage.so") - @info "Creating the sys image. This may take a while..." - mktemp() do path, io - write(io, """import CatColabInterop - include(joinpath(pkgdir(CatColabInterop), "test", "runtests.jl")) - """) - flush(io) - create_sysimage(["CatColabInterop"], sysimage_path=sysimg, precompile_execution_file=path) - end - - @info "Adding $sysimg to IJulia kernel" - installkernel("CatColabInteropSysImage", "--project=@.", "--sysimage=$sysimg") - - load_kernels!() - @info "Done!" -end - -end diff --git a/packages/algjulia-interop/make_sysimage.jl b/packages/algjulia-interop/make_sysimage.jl deleted file mode 100755 index eb1c2e763..000000000 --- a/packages/algjulia-interop/make_sysimage.jl +++ /dev/null @@ -1,24 +0,0 @@ -#!/usr/bin/env julia - -@info "Verifying PackageCompiler is installed globally" -using Pkg; Pkg.activate(); Pkg.add("PackageCompiler") -using PackageCompiler - -@info "Activating sysimage environment" -Pkg.activate(@__DIR__) - -@info "Creating the sysimage. This may take a while..." -sysimg="CatColabInterop.so" -create_sysimage(["CatColabInterop"], sysimage_path=sysimg, - precompile_execution_file="sysimage_precompile.jl") -sysimg_path=joinpath(@__DIR__, sysimg); - -@info "Adding $sysimg_path to IJulia kernel" -Pkg.activate(); Pkg.add("IJulia") -using IJulia -Pkg.build("IJulia") - -installkernel("Julia CatColab Interop", "--project=@.", "--sysimage=$sysimg_path") - -@info "Done!" -exit() diff --git a/packages/algjulia-interop/scripts/endpoint.jl b/packages/algjulia-interop/scripts/endpoint.jl new file mode 100644 index 000000000..02144bda1 --- /dev/null +++ b/packages/algjulia-interop/scripts/endpoint.jl @@ -0,0 +1,60 @@ + +# Example usage: + +# julia --project=my_alg_julia_env --threads 4 endpoint.jl Catlab AlgebraicPetri + +# Where my_alg_julia_env is a Julia environment with CatColabInterop, Oxygen, +# HTTP, and any AlgJulia dependencies. + +using CatColabInterop +using Oxygen +using HTTP + +using TOML +using ArgParse + +const CORS_HEADERS = [ + "Access-Control-Allow-Origin" => "*", + "Access-Control-Allow-Headers" => "*", + "Access-Control-Allow-Methods" => "POST, GET, OPTIONS" +] + +function CorsHandler(handle) + return function (req::HTTP.Request) + # return headers on OPTIONS request + if HTTP.method(req) == "OPTIONS" + return HTTP.Response(200, CORS_HEADERS) + else + r = handle(req) + append!(r.headers, ["Access-Control-Allow-Origin" => "*"]) + r + + end + end +end + +s = ArgParseSettings() +@add_arg_table s begin + "--toml", "-t" + arg_type = String + default = "Project.toml" + "--pkg", "-p" + arg_type = String + default = "CatlabExt" +end +parsed_args = parse_args(ARGS, s) + +# TODO +@ext DecapodesExt("../Project.toml") + +for m in methods(CatColabInterop.endpoint) + sig = m.sig.parameters + (length(sig)==2 && sig[2].instance isa Val) || error("Unexpected signature $sig") + name = only(sig[2].parameters) + @info "Loading endpoint $name" + name isa Symbol || error("Unexpected endpoint name $name") + fntype, argtypes... = m.sig.types + invoke(fntype.instance, Tuple{argtypes...}, Val(name)) +end + +serve(middleware=[CorsHandler]) diff --git a/packages/algjulia-interop/src/CatColabInterop.jl b/packages/algjulia-interop/src/CatColabInterop.jl index a0b0d2320..ad82ffbf6 100644 --- a/packages/algjulia-interop/src/CatColabInterop.jl +++ b/packages/algjulia-interop/src/CatColabInterop.jl @@ -1,86 +1,47 @@ module CatColabInterop -using MLStyle -using Reexport - -# this code tracks integrations and allows for basic theory/model-building code to dispatch from it. -# the intent is that this is an interface for AlgebraicJulia code to interoperate with CatColab -abstract type AlgebraicJuliaIntegration end - -# cells in the JSON are tagged. these are just objects for dispatching `to_model` -@data ModelElementTag begin - ObTag() - HomTag() -end -export ObTag, HomTag +using TOML -#= -@active patterns are MLStyle-implementations of F# active patterns that forces us to work in the Maybe/Option pattern. -Practically, yet while a matter of opinion, they make @match statements cleaner; a statement amounts to a helpful pattern -name and the variables we intend to capture. -=# -@active IsObject(x) begin; x[:content][:tag] == "object" ? Some(x[:content]) : nothing end -@active IsMorphism(x) begin; x[:content][:tag] == "morphism" ? Some(x[:content]) : nothing end -export IsObject, IsMorphism +export endpoint -# Obs, Homs -@data ModelElementValue begin - ObValue() - HomValue(dom,cod) -end -export ObValue, HomValue +using MLStyle: @match +using Reexport """ -Struct capturing the name of the object and its relevant information. -ModelElementValue may be objects or homs, each of which has different data. +Extend this method with endpoint(::Val{my_analysis_name}) in extension packages. """ -struct ModelElement - name::Union{Symbol, Nothing} - val::Union{<:ModelElementValue, Nothing} - function ModelElement(;name::Symbol=nothing,val::Any=nothing) - new(name, val) - end -end -export ModelElement - -Base.nameof(t::ModelElement) = t.name +function endpoint end -""" Struct wrapping a dictionary """ -struct Model{T<:AlgebraicJuliaIntegration} - data::Dict{String, ModelElement} -end -export Model - -function Model(::T) where T<:AlgebraicJuliaIntegration - Model{T}(Dict{String, ModelElement}()) -end +include("Types.jl") +@reexport using .Types -Base.values(model::Model) = values(model.data) - -""" -Functions to build a dictionary associating ids in the theory to elements in the model """ -function to_model end -export to_model - +Loads an extension -# TODO supposes bijection between theories, models, diagrams, etc. -abstract type AbstractDiagram{T<:AlgebraicJuliaIntegration} end +Usage: -abstract type AbstractAnalysis{T<:AlgebraicJuliaIntegration} end - -struct ImplError <: Exception - name::String +``` + const DecapodesExt = @ext DecapodesExt(relative_path_of_Project.toml) +``` +""" +macro ext(body) + (extension, toml) = @match body begin + Expr(:call, ex, toml) => (ex, toml) + ::Symbol => (body, "Project.toml") + _ => error("!: $body") + end + parsed_toml = TOML.parsefile(toml) + pkgs = Symbol.(parsed_toml["extensions"][String(extension)]) + l = length(pkgs) + result = Expr(:block) + for (i, pkg) in enumerate(pkgs) + push!(result.args, Expr(:macrocall, Symbol("@info"), LineNumberNode(i), "using $pkg ($i/$l)")) + push!(result.args, Expr(:using, Expr(Symbol("."), pkg))) + end + push!(result.args, Expr(:call, Expr(Symbol("."), :Base, QuoteNode(:get_extension)), + :CatColabInterop, QuoteNode(extension))) + esc(result) end -export ImplError - -Base.showerror(io::IO, e::ImplError) = print(io, "$(e.name) not implemented") - -include("result.jl") -include("kernel_management.jl") -include("kernel_support.jl") -include("decapodes-service/DecapodesService.jl") +export @ext -@reexport using .DecapodesService - -end +end # module diff --git a/packages/algjulia-interop/src/Types.jl b/packages/algjulia-interop/src/Types.jl new file mode 100644 index 000000000..1553274c7 --- /dev/null +++ b/packages/algjulia-interop/src/Types.jl @@ -0,0 +1,101 @@ +# TODO make this automatically generated by CatColab +""" Common types useful for deserializing CatColab JSON payloads """ +module Types + +export ObType, MorType, DiagramObGenerator, DiagramMorGenerator, ObGenerator, + MorGenerator, Diagram, Model, ModelDiagram, Analysis + +import JSON3: read +using StructTypes + +struct ObType + tag::String + content::String +end +StructTypes.StructType(::Type{ObType}) = StructTypes.Struct() + +Base.nameof(ob::ObType) = ob.tag + +struct MorType + tag::String + content::Union{String,ObType} +end +StructTypes.StructType(::Type{MorType}) = StructTypes.Struct() + +Base.nameof(mor::MorType) = mor.tag + +struct DiagramObGenerator + id::String + label::Vector{Union{Integer, String}} + obType::ObType + over::ObType +end +StructTypes.StructType(::Type{DiagramObGenerator}) = StructTypes.Struct() + +Base.nameof(dob::DiagramObGenerator) = join(string.(dob.label), ".") + +struct DiagramMorGenerator + id::String + morType::MorType + over::ObType + dom::ObType + cod::ObType +end +StructTypes.StructType(::Type{DiagramMorGenerator}) = StructTypes.Struct() + +Base.nameof(dmor::DiagramMorGenerator) = join(string.(dmor.label), ".") + +struct ObGenerator + id::String + label::Vector{Union{Integer, String}} + obType::ObType +end +StructTypes.StructType(::Type{ObGenerator}) = StructTypes.Struct() + +Base.nameof(obg::ObGenerator) = join(string.(obg.label), ".") + +struct MorGenerator + id::String + label::Vector{Union{Integer, String}} + morType::MorType + dom::ObType + cod::ObType +end +StructTypes.StructType(::Type{MorGenerator}) = StructTypes.Struct() + +Base.nameof(morg::MorGenerator) = join(string.(morg.label), ".") + +struct Diagram + obGenerators::Vector{DiagramObGenerator} + morGenerators::Vector{DiagramMorGenerator} +end +StructTypes.StructType(::Type{Diagram}) = StructTypes.Struct() + +struct Model + obGenerators::Vector{ObGenerator} + morGenerators::Vector{MorGenerator} +end +StructTypes.StructType(::Type{Model}) = StructTypes.Struct() + +struct ModelDiagram + model::Model + diagram::Diagram +end +StructTypes.StructType(::Type{ModelDiagram}) = StructTypes.Struct() + +# Intermediate variables enter as integers +struct Analysis + model::Model + diagram::Diagram + analysis::Dict{Symbol, Any} +end + +function read(content::String, ::Type{Analysis}) + obj = read(content) + model = StructTypes.constructfrom(Model, obj[:model]) + diagram = StructTypes.constructfrom(Diagram, obj[:diagram]) + Analysis(model, diagram, obj[:analysis]) +end + + +end # module diff --git a/packages/algjulia-interop/src/decapodes-service/DecapodesService.jl b/packages/algjulia-interop/src/decapodes-service/DecapodesService.jl deleted file mode 100644 index 1539cbbfb..000000000 --- a/packages/algjulia-interop/src/decapodes-service/DecapodesService.jl +++ /dev/null @@ -1,42 +0,0 @@ -module DecapodesService - -# algebraicjulia dependencies -using ACSets -using DiagrammaticEquations -using Decapodes -using CombinatorialSpaces - -# dependencies -import JSON3 -using StaticArrays -using MLStyle -using LinearAlgebra -using ComponentArrays -using Distributions # for initial conditions - -# meshing -using CoordRefSystems -using GeometryBasics: Point2, Point3 -Point3D = Point3{Float64}; - -# simulation -using OrdinaryDiffEq - -using ..CatColabInterop -using ..CatColabInterop: AlgebraicJuliaIntegration, AbstractDiagram, AbstractAnalysis -import ..CatColabInterop: Model, to_model - -# necessary to export -export infer_types!, evalsim, default_dec_generate, default_dec_matrix_generate, - DiagonalHodge, ComponentArray - -struct ThDecapode <: AlgebraicJuliaIntegration end -export ThDecapode - -# funcitons for geometry and initial conditions -include("geometry.jl") -include("model.jl") ## model-building -include("diagram.jl") ## diagram-building -include("analysis/Analysis.jl") - -end diff --git a/packages/algjulia-interop/src/decapodes-service/analysis/Analysis.jl b/packages/algjulia-interop/src/decapodes-service/analysis/Analysis.jl deleted file mode 100644 index af3f267a3..000000000 --- a/packages/algjulia-interop/src/decapodes-service/analysis/Analysis.jl +++ /dev/null @@ -1,3 +0,0 @@ -include("ns_helper.jl") -include("initial_conditions.jl") -include("simulation.jl") diff --git a/packages/algjulia-interop/src/decapodes-service/analysis/simulation.jl b/packages/algjulia-interop/src/decapodes-service/analysis/simulation.jl deleted file mode 100644 index 044a261d8..000000000 --- a/packages/algjulia-interop/src/decapodes-service/analysis/simulation.jl +++ /dev/null @@ -1,161 +0,0 @@ -""" Constructs an analysis from the diagram of a Decapode Model""" -function Analysis(analysis::JSON3.Object, diagram::DecapodeDiagram, hodge=GeometricHodge()) - - # TODO want a safer way to get this information - id = findfirst(cell -> haskey(cell, :content), analysis[:notebook][:cells]) - content = analysis[:notebook][:cells][id][:content][:content] - - PodeSystem(content, diagram, hodge) -end -export Analysis - -# accepts payload -function Analysis(::ThDecapode, payload::String, args...) - analysis = JSON3.read(payload) - Analysis(ThDecapode(), analysis) -end - -function Analysis(::ThDecapode, analysis::JSON3.Object, args...) - model = Model(ThDecapode(), analysis.model) - diagram = Diagram(analysis.diagram, model) - PodeSystem(analysis, diagram, args...) -end - -struct PodeSystem <: AbstractAnalysis{ThDecapode} - pode::SummationDecapode - plotVars::Dict{String, Bool} - scalars::Dict{Symbol, Any} # closures - geometry::Geometry - init::ComponentArray - generate::Any - uuiddict::Dict{Symbol, String} - duration::Int -end -export PodeSystem - -function Base.show(io::IO, system::PodeSystem) - println(io, system.pode) -end - -# the origin is the SimulationData payload -function PodeSystem(content::JSON3.Object, diagram::DecapodeDiagram, hodge=GeometricHodge()) - - domain = content[:domain] - duration = content[:duration] - initialConditions = content[:initialConditions] - mesh = content[:mesh] - # TODO we need a more principled way of defining this - plotVars = @match content[:plotVariables] begin - vars::AbstractArray => Dict{String, Bool}([ k => k ∈ vars for k in keys(diagram.vars)]) - vars => Dict{String, Bool}([ "$k" => v for (k,v) in vars]) - end - scalars = content[:scalars] - anons = Dict{Symbol, Any}() - - dot_rename!(diagram.pode) - uuid2symb = uuid_to_symb(diagram.pode, diagram.vars) - - geometry = Geometry(content) - - ♭♯_m = ♭♯_mat(geometry.dualmesh) - wedge_dp10 = dec_wedge_product_dp(Tuple{1,0}, geometry.dualmesh) - dual_d1_m = dec_dual_derivative(1, geometry.dualmesh) - star0_inv_m = dec_inv_hodge_star(0, geometry.dualmesh, hodge) - Δ0 = Δ(0,geometry.dualmesh) - #fΔ0 = factorize(Δ0); - function sys_generate(s, my_symbol) - op = @match my_symbol begin - sym && if haskey(diagram.scalars, sym) end => x -> begin - k = scalars[diagram.scalars[sym]] - k * x - end - :♭♯ => x -> ♭♯_m * x - # TODO are we indexing right? - :dpsw => x -> wedge_dp10(x, star0_inv_m*(dual_d1_m*x)) - :Δ⁻¹ => x -> begin - y = Δ0 \ x - y .- minimum(y) - end - _ => default_dec_matrix_generate(s, my_symbol, hodge) - end - return (args...) -> op(args...) - end - - u0 = initial_conditions(initialConditions, geometry, uuid2symb) - - # reversing `uuid2symb` into `symbol => uuid.` we need this to reassociate the var to its UUID - symb2uuid = Dict([v => k for (k,v) in pairs(uuid2symb)]) - - # TODO return the whole system - return PodeSystem(diagram.pode, plotVars, anons, geometry, u0, sys_generate, symb2uuid, duration) -end - -points(system::PodeSystem) = collect(values(system.geometry.dualmesh.subparts.point.m)) -indexing_bounds(system::PodeSystem) = indexing_bounds(system.geometry.domain) - -function run_sim(fm, u0, t0, constparam) - prob = ODEProblem(fm, u0, (0, t0), constparam) - soln = solve(prob, Tsit5(), saveat=0.01) -end -export run_sim - -struct SimResult - time::Vector{Float64} - state::Dict{String, Vector{AbstractArray{SVector{3, Float64}}}} - x::Vector{Float64} # axis - y::Vector{Float64} -end -export SimResult - -function SimResult(soln::ODESolution, system::PodeSystem) - idx_bounds = indexing_bounds(system) - state_val_dict = variables_state(soln, system) # Dict("UUID1" => VectorMatrixSVectr...) - SimResult(soln.t, state_val_dict, 0:idx_bounds.x, 0:idx_bounds.y) -end -# TODO generalize to HasDeltaSet - -""" for the variables in a system, associate them to their state values over the duration of the simulation """ -function variables_state(soln::ODESolution, system::PodeSystem) - plottedVars = [ k for (k, v) in system.plotVars if v == true ] - uuid2symb = Dict([ v => k for (k, v) in system.uuiddict]) # TODO why reverse again? - Dict([ String(uuid2symb[var]) => state_entire_sim(soln, system, uuid2symb[var]) for var ∈ plottedVars ]) -end - -""" given a simulation, a domain, and a variable, gets the state values over the duration of a simulation. -Called by `variables_state`[@ref] """ -function state_entire_sim(soln::ODESolution, system::PodeSystem, var::Symbol) - map(1:length(soln.t)) do i - state_at_time(soln, system, var, i) - end -end - -# TODO type `points` -function state_at_time(soln::ODESolution, system::PodeSystem, plotvar::Symbol, t::Int) - @match system.geometry.domain begin - # TODO check time indexing here - domain::Rectangle => state_at_time(soln, domain, plotvar, t) - domain::Sphere => state_at_time(soln, domain, plotvar, t, points(system)) - _ => throw(ImplError("state_at_time function for domain $domain")) - end -end - -function state_at_time(soln::ODESolution, domain::Rectangle, var::Symbol, t::Int) - (x, y) = indexing_bounds(domain) - [SVector(i, j, getproperty(soln.u[t], var)[(x+1)*(i-1) + j]) for i in 1:x+1, j in 1:y+1] -end - -# TODO just separated this from the SimResult function and added type parameters, but need to generalize -function grid(pt3::Point3, grid_size::Vector{Int}) - pt2 = [(pt3[1]+1)/2, (pt3[2]+1)/2] - [round(Int, pt2[1]*grid_size[1]), round(Int, pt2[2]*grid_size[2])] -end - -function state_at_time(soln::ODESolution, domain::Sphere, var::Symbol, t::Int, points) - l , _ = indexing_bounds(domain) # TODO this is hardcoded to return 100, 100 - northern_indices = filter(i -> points[i][3] > 0, keys(points)) - map(northern_indices) do n - i, j = grid(points[n], [l, l]) # TODO - SVector(i, j, getproperty(soln.u[t], var)[n]) - end -end - diff --git a/packages/algjulia-interop/src/decapodes-service/diagram.jl b/packages/algjulia-interop/src/decapodes-service/diagram.jl deleted file mode 100644 index fee454d4e..000000000 --- a/packages/algjulia-interop/src/decapodes-service/diagram.jl +++ /dev/null @@ -1,113 +0,0 @@ -## DIAGRAM BUILDING - - -@kwdef mutable struct DecapodeDiagram <: AbstractDiagram{ThDecapode} - pode::SummationDecapode = SummationDecapode(parse_decapode(quote end)) - scalars::Dict{Symbol, String} = Dict{Symbol, String}() - vars::Dict{String, Int} = Dict{String, Int}() - nc::Dict{Int, String} = Dict{Int, String}() -end - -function Base.nameof(model::Model, content::AbstractDict) - if isnothing(content[:over]) - :no_name - else - Symbol(model.data[content[:over][:content]].name) - end -end - -# endpoint being `dom` or `codom` -function check_endpoint!(diagram::DecapodeDiagram, endpoint) - if haskey(diagram.vars, endpoint) - diagram.vars[endpoint] - else - if endpoint ∉ values(diagram.nc) - id = isempty(keys(diagram.nc)) ? 1 : length(keys(diagram.nc)) + 1 - name = Symbol("•$id") - acset_id = add_part!(diagram.pode, :Var, name=name, type=:infer) - push!(diagram.nc, acset_id => endpoint) - acset_id - else - out = filter(x -> x[2] == endpoint, pairs(diagram.nc)) - first(keys(out)) - end - end -end - -function add_to_pode!(diagram::DecapodeDiagram, - model::Any, - content::AbstractDict, - ::ObTag) - # indexes the model by UUID - model_element = model.data[content[:over][:content]] - # checks if the cell is an anonymous (intermediate) variable. - # if so, we increment the intermediate variable counter and make an intermediate variable name. - # otherwise we use the existing name of the given content. - name = if isempty(content[:name]) - id = isempty(keys(diagram.nc)) ? 1 : maximum(keys(diagram.nc)) + 1 - push!(diagram.nc, id => "") - Symbol("•$id") - else - Symbol(content[:name]) - end - id = add_part!(diagram.pode, :Var, name=name, type=nameof(model_element)) - push!(diagram.vars, content[:id] => id) - return diagram -end -export add_to_pode! - -# TODO we are restricted to Op1 -function add_to_pode!(diagram::DecapodeDiagram, - model::Model{ThDecapode}, - content::AbstractDict, - ::HomTag) - dom = content[:dom][:content] - cod = content[:cod][:content] - - # TODO Simpler to extend the Decapodes Var table by a UUID attribute - dom_id = check_endpoint!(diagram, dom) - cod_id = check_endpoint!(diagram, cod) - - # get the name of the Op1 and add it to the model - op1 = nameof(model, content) - - add_part!(diagram.pode, :Op1, src=dom_id, tgt=cod_id, op1=op1) - # we need to add an inclusion to the TVar table - if op1 == :∂ₜ - add_part!(diagram.pode, :TVar, incl=cod_id) - end - if content[:morType][:content] isa JSON3.Object - scalar = model.data[content[:over][:content]].name - push!(diagram.scalars, scalar => content[:over][:content]) - end - diagram -end - -""" Diagram(diagram::AbstractVector{<:AbstractDict}, model::Model{ThDecapode}) => (::SummationDecapode, ::Dict{Symbol, Any}, ::Dict{String, Int}) - -This returns - 1. a Decapode - 2. a dictionary of symbols mapped to anonymous functions - 3. a dictionary of JSON UUIDs mapped to symbols -""" -function Diagram(json_array::JSON3.Array{T}, model::Model{ThDecapode}; scalars=[]) where T - diagram = DecapodeDiagram() - for cell in json_array - cell = haskey(cell, :content) ? cell[:content] : cell - @match cell begin - content && if haskey(content, :obType) end => add_to_pode!(diagram, model, content, ObTag()) - content && if haskey(content, :morType) end => add_to_pode!(diagram, model, content, HomTag()) - _ => throw(ImplError(cell)) - end - end - return diagram -end -export Diagram - -function Diagram(json_diagram::JSON3.Object, model::Model{ThDecapode}; scalars=[]) - Diagram(json_diagram[:cells], model; scalars) -end - -function uuid_to_symb(decapode::SummationDecapode, vars::Dict{String, Int}) - Dict([key => (subpart(decapode, vars[key], :name)) for key ∈ keys(vars)]) -end diff --git a/packages/algjulia-interop/src/decapodes-service/model.jl b/packages/algjulia-interop/src/decapodes-service/model.jl deleted file mode 100644 index e1b4bb0c3..000000000 --- a/packages/algjulia-interop/src/decapodes-service/model.jl +++ /dev/null @@ -1,107 +0,0 @@ -# Build the model - -export Model - -""" -A model for the Decapodes integration is the same as the default Model method. -A dictionary mapping UUID strings with ModelElements is instantiated. -""" -Model(::ThDecapode) = Model{ThDecapode}(Dict{String, ModelElement}()) - -""" Helper function to convert CatColab values (Obs) in Decapodes """ -function to_model(model::ThDecapode, type::ObTag, name::String) - @match lowercase(name) begin - "0-form" => :Form0 - "1-form" => :Form1 - "2-form" => :Form2 - "primal 0-form" => :Form0 - "primal 1-form" => :Form1 - "primal 2-form" => :Form2 - "dual 0-form" => :DualForm0 - "dual 1-form" => :DualForm1 - "dual 2-form" => :DualForm2 - x => throw(ImplError(x)) - end -end - -""" Helper function to convert CatColab values (Homs) in Decapodes """ -function to_model(model::ThDecapode, type::HomTag, name::String) - @match replace(name," " => "") begin - "∂t" || "∂ₜ" => :∂ₜ - "Δ" => :Δ - "Δ⁻¹" => :Δ⁻¹ - "d*" || "d̃₁" => :dual_d₁ - "⋆" || "⋆₁" || "★₁" || "★1" => :⋆₁ - "⋆⁻¹" || "⋆₀⁻¹" => :⋆₀⁻¹ - "★" || "★⁻¹" => :⋆₁ - "d" || "d₀" || "d01" => :d₀ - "d12" => :d₁ - "⋆2" => :⋆₂ - "♭♯" => :♭♯ - "lamb" => :dpsw # dual-primal self-wedge - "-" => :neg - x => throw(ImplError(x)) - end -end - -# add_to_model! - -@active IsMorphismNonScalar(x) begin - x[:morType][:content] == "Nonscalar" ? Some(x) : nothing -end - -function add_to_model! end -export add_to_model! - -function add_to_model!(model::Model{ThDecapode}, content::AbstractDict, type::ObTag) - push!(model.data, content[:id] => ModelElement(;name=to_model(ThDecapode(), type, content[:name]))) -end - -function add_to_model!(model::Model{ThDecapode}, content::AbstractDict, type::HomTag) - @match content begin - IsMorphismNonScalar(x) => push!(model.data, content[:id] => - ModelElement(;name=to_model(ThDecapode(), type, content[:name]), - val=HomValue(content[:dom][:content], - content[:cod][:content]))) - _ => push!(model.data, content[:id] => - ModelElement(;name=Symbol(content[:name]), - val=HomValue(content[:dom][:content], - content[:cod][:content]))) - end -end - -# TODO generalize -function Model(::ThDecapode, path::String) - json = JSON3.read(read(path, String)) - Model(ThDecapode(), json) -end - -# for each cell, if it is... -# ...an object, we convert its type to a symbol and add it to the modeldict -# ...a morphism, we add it to the modeldict with a field for the ids of its -# domain and codomain to its -function Model(::ThDecapode, json_model::JSON3.Object) # AbstractDict is the JSON - newmodel = Model(ThDecapode()) - __name = json_model[:name] # TODO unused - for cell in json_model[:notebook][:cells] - @match cell begin - IsObject(content) => add_to_model!(newmodel, content, ObTag()) - IsMorphism(content) => add_to_model!(newmodel, content, HomTag()) - _ => throw(ImplError(cell)) - end - end - return newmodel -end -export Model - -function Model(::ThDecapode, json_array::JSON3.Array{T}; name="model") where T - newmodel = Model(ThDecapode()) - for cell in json_array - @match cell begin - content && if haskey(content, :obType) end => add_to_model!(newmodel, content, ObTag()) - content && if haskey(content, :morType) end => add_to_model!(newmodel, content, HomTag()) - _ => throw(ImplError(cell)) - end - end - return newmodel -end diff --git a/packages/algjulia-interop/src/kernel_management.jl b/packages/algjulia-interop/src/kernel_management.jl deleted file mode 100644 index c658ddb89..000000000 --- a/packages/algjulia-interop/src/kernel_management.jl +++ /dev/null @@ -1,256 +0,0 @@ -using IJulia -using Preferences -import REPL -using REPL.TerminalMenus -using MLStyle - -struct KernelNotFoundException <: Exception - dir::String -end - -KernelNotFoundException() = KernelNotFoundException(IJulia.kerneldir()) - -function Base.showerror(io::IO, err::KernelNotFoundException) - print(io, """ - IJulia cannot find any kernels in the directory `$(err.dir)`. - - To install a kernel, you may run `CatColabInterop.install_ccl_kernel()`. - Refer to the [IJulia documentation](https://julialang.github.io/IJulia.jl/stable/library/public/#IJulia.installkernel) - for more information about managing Jupyter kernels in IJulia. - - If you wish to install a sysimage instead, run - ```julia - using PackageCompiler - install_ccl_kernel(Val(:sysimge)) - ``` - """) -end - -const YESNO = ["Yes", "No"] - -const MODES = Dict("dev" => "http://localhost:5173", - "staging" => "https://next.catcolab.org", - "production" => "https://catcolab.org") - -@kwdef mutable struct ServerConfig - sysimg_path::Union{String, Nothing} = nothing - kernels::Vector{String} = readdir(IJulia.kerneldir(), join=true) - kernel::Union{String, Nothing} = @load_preference("kernel", nothing) - modes::Dict{String, String} = MODES - mode::String = @load_preference("mode", "production") - limit::Int = 1e9 - server::Union{Base.Process, Nothing} = nothing -end - -const CONFIG::ServerConfig = ServerConfig() -export CONFIG - -function origin(s::ServerConfig) - s.modes[s.mode] -end - -function Base.show(io::IO, config::ServerConfig) - kernel = !isnothing(config.kernel) ? config.kernel : "No kernel selected" - status = !isnothing(config.server) ? "Running" : "Not running." - s = """ - Current kernel: $kernel - Server: $status - Origin: $(origin(config)) - """ - print(io, s) -end - -function set_mode!(config::ServerConfig, mode::String) - if mode ∈ collect(keys(config.modes)) - config.mode = mode - @info """"$mode" set!""" - else - error("""Your selection "$mode" is not a valid mode. Please choose from $(join(config.modes, ", ", " or "))""") - end -end - -function change_mode!(prefer::Bool=true; config::ServerConfig=CONFIG) - modes = collect(keys(config.modes)) - menu = RadioMenu(modes, pagesize=3) - cursor = something(findfirst(==(config.mode), modes), 0) - choice = request("Select a mode: ", menu; cursor = cursor) - if choice != -1 - config.mode = modes[choice] - if prefer - @set_preferences!("mode" => modes[choice]) - @info "Preferred mode set to $(modes[choice])" - end - Ok("""Mode "$(config.mode)" chosen.""") - else - Err("Mode selection canceled") - end -end -export change_mode! - -function change_kernel!(prefer::Bool=true; config::ServerConfig=CONFIG) - menu = RadioMenu(config.kernels, pagesize=4) - cursor = something(findfirst(==(config.kernel), config.kernels), 0) - choice = request("Select a kernel: ", menu; cursor=cursor) - if choice != -1 - config.kernel = config.kernels[choice] - if prefer - @set_preferences!("kernel" => config.kernel) - @info "Preferred kernel set to $(config.kernels[choice])" - end - Ok("Kernel $(config.kernel) chosen.") - else - Err("Kernel selection canceled") - end -end -export change_kernel! - -""" load_kernels() - -Loads kernels visible to IJulia's [kernel_dir](@ref IJulia.kerneldir) function. -""" -function load_kernels!(;config::ServerConfig=CONFIG, warn=false) - dir = IJulia.kerneldir() - kernels = readdir(dir, join=true) - if !isempty(kernels) - config.kernels = kernels - return Ok("Kernels reloaded!") - end - # otherwise, throw a warning or an error - warn ? @warn(sprint(showerror, KernelNotFoundException(dir))) : throw(KernelNotFoundException(dir)) -end - -""" uninstall_kernel!(;config::ServerConfig=CONFIG)::Union{Nothing, Bool} - -Wraps `Base.rm` in a terminal menu interface to uninstall Julia kernels. Using `Base.rm` is recommended by IJulia. - -Usage: -``` -uninstall_kernel!() -``` -""" -function uninstall_kernel!(;config::ServerConfig=CONFIG) - isempty(config.kernels) && throw(KernelNotFoundException()) - menu = MultiSelectMenu(config.kernels, pagesize=4) - cursor = something(findfirst(==(config.kernel), config.kernels), 0) - choices = request("Select a kernel to be uninstalled: ", menu; cursor=cursor) - if !isempty(choices) - selections = getindex(config.kernels, collect(choices)) - confirm = RadioMenu(YESNO, pagesize=2) - permission = request("Kernel(s) will be uninstalled from your machine. Continue?", confirm) - if YESNO[permission] == "Yes" - for selection in selections - isdir(selection) && rm(selection; recursive=true) - @info selection isdir(selection) "Removed!" - end - preferred = @load_preference("kernel", nothing) - if preferred ∈ selections - @delete_preferences!("kernel") - @info "Preferred kernel $preferred was removed." - end - load_kernels!(;config=config, warn=true) - Ok() - else - Err("Kernel uninstallation cancelled.") - end - Ok("Kernel deletion successful.") - else - Err("Kernel uninstallation cancelled") - end -end -export uninstall_kernel! - - -""" install_ccl_kernel!() - -This calls IJulia to install a kernel `CatColabInteropKernel` in the current project directory. - -To build a sysimage, load the `SysImageExt` package extension by loading `PackageCompiler.jl`. This adds an additional method to `install_ccl_kernel!` which builds the sysimg. - -You can see installed kernels visible to IJulia by running `change_kernel!()`. - -Usage: - -For building an IJulia kernel -``` -using CatColabInterop -install_ccl_kernel!() -``` -For building the sysimg: -``` -using CatColabInterop -using PackageCompiler # loads Julia extension for building the sysimage -install_ccl_kernel!(Val(:sysimg)) -``` -""" -function install_ccl_kernel!(;config::ServerConfig=CONFIG, kwargs...) - kernel = installkernel("CatColabInteropKernel", "--project=@.", kwargs...) - load_kernels!(config=config) - preferred = @load_preference("kernel", nothing) - if isnothing(preferred) || length(config.kernels) == 1 - @set_preferences!("kernel" => kernel) - @info "Preferred kernel set to $(kernel)" - end -end -export install_ccl_kernel! - -function build_jupyter_server_cmd(args::Dict{String, Any}) - return ` - jupyter server \ - --IdentityProvider.token="" \ - --ServerApp.disable_check_xsrf=True \ - --ServerApp.allow_origin="$(args["mode"])" \ - --ServerApp.allow_credentials=True \ - --ServerApp.iopub_data_rate_limit=$(args["limit"]) \ - --MultiKernelManager.default_kernel_name="$(basename(args["kernel"]))" - ` -end - -function build_jupyter_server_cmd(config::ServerConfig) - build_jupyter_server_cmd(Dict{String, Any}("limit" => config.limit, "kernel" => config.kernel, "mode" => origin(config))) -end - -""" start_server(;config::ServerConfig=CONFIG, mode::Union{String, Nothing}=nothing, manual=false) - -This starts a Jupyter server with an optional kernel and mode. - -The **mode** is the origin for the Jupyter server. Eligible values are "dev", "staging", and "production". - -The available kernels can be checked by running `jupyter-server kernelspec list` from the command line or `;jupyter-server kernelspec list` from the REPL. - -## Usage: - -```julia -start_server!() -# do stuff -stop_server!() -``` -To select the kernel and mode in a wizard-like interface, -```julia -start_server!(;manual=true) -``` -""" -function start_server!(;config::ServerConfig=CONFIG, mode::Union{String, Nothing}=nothing, manual=false) - if manual - change_kernel!(;config=config) | Err("Start server process aborted because kernel selection was cancelled.") - change_mode!(;config=config) | Err("Start server process aborted because mode selection was cancelled.") - end - if isnothing(config.kernel) - change_kernel!(;config=config) - end - if !isnothing(mode) - set_mode!(config, mode) - end - cmd = build_jupyter_server_cmd(config) - @info "Starting server: - kernel: $(config.kernel) - mode: $(origin(config))" - config.server = open(pipeline(cmd)) -end -export start_server! - -function stop_server!(;config::ServerConfig=CONFIG) - if !isnothing(config.server) - kill(config.server, Base.SIGTERM) - end -end -export stop_server! diff --git a/packages/algjulia-interop/src/kernel_support.jl b/packages/algjulia-interop/src/kernel_support.jl deleted file mode 100644 index 15bfde4da..000000000 --- a/packages/algjulia-interop/src/kernel_support.jl +++ /dev/null @@ -1,32 +0,0 @@ -import JSON3 - -export JsonValue - -# NOTE: JsonValue should not be used for returning large amounts of data (Anything over 1kb? -# Whatever the size is for "trivially readable by humans"), there is a catastrophic performance -# dropoff as payload size increases. Performance of JsonValue vs -# display(MIME"application/json"(), JSON3.write()) has not been studied in detail, both have bad -# performance, but one might be worse than the other. Whether or not the performance is different might -# help inform a future investigation. -# -# NOTE: the use of the `show` methods is the only way I was able to get the contents of the message -# (`content["data"]?.["application/json"]`) to be interpreted as JSON in the browser. using something -# like `display(MIME"application/json"(), JSON3.write(...))` caused the -# content to be the JSON in string form, even though the mime type was "application/json" -# -# NOTE: It looks like IJulia is delivering payloads for each mime type available according to this -# docstring https://github.com/JuliaLang/IJulia.jl/blob/master/src/display.jl -# -# NOTE: Jason is not 100% confident that these show methods do what it looks like they're doing. -# -# NOTE: Sometime the Jupyter server needs to be restarted. Do not trust performance tests are run twice -# back to back right after server startup. - -""" Container for an arbitrary JSON value. """ -struct JsonValue - value::Any -end - -function Base.show(io::IO, ::MIME"application/json", json::JsonValue) - JSON3.write(io, json.value) -end diff --git a/packages/algjulia-interop/src/result.jl b/packages/algjulia-interop/src/result.jl deleted file mode 100644 index 1178e2dd9..000000000 --- a/packages/algjulia-interop/src/result.jl +++ /dev/null @@ -1,23 +0,0 @@ -struct ResultException <: Exception - msg::String -end - -Base.showerror(io::IO, err::ResultException) = print(io, err.msg) - -@data Result begin - Ok(msg::String) - Err(msg::String) -end - -Ok() = Ok("") - -Base.show(io::IO, ok::Ok) = !isempty(ok.msg) ? print(io, ok.msg) : nothing -Base.show(io::IO, err::Err) = !isempty(err.msg) ? print(io, err.msg) : nothing - -import Base: | - -(|)(left::Ok, right) = handle(left) -(|)(left::Err, right) = handle(right) - -handle(ok::Ok) = ok -handle(err::Err) = throw(ResultException(err.msg)) diff --git a/packages/algjulia-interop/sysimage_precompile.jl b/packages/algjulia-interop/sysimage_precompile.jl deleted file mode 100755 index 2fb9f0d7b..000000000 --- a/packages/algjulia-interop/sysimage_precompile.jl +++ /dev/null @@ -1,2 +0,0 @@ -import CatColabInterop -include(joinpath(pkgdir(CatColabInterop), "test", "runtests.jl")) diff --git a/packages/algjulia-interop/test/Project.toml b/packages/algjulia-interop/test/Project.toml index afd8e968a..6e976a3ab 100644 --- a/packages/algjulia-interop/test/Project.toml +++ b/packages/algjulia-interop/test/Project.toml @@ -1,13 +1,20 @@ [deps] ACSets = "227ef7b5-1206-438b-ac65-934d6da304b8" CatColabInterop = "9ecda8fb-39ab-46a2-a496-7285fa6368c1" +Catlab = "134e5e36-593f-5add-ad60-77f754baafbe" CombinatorialSpaces = "b1c52339-7909-45ad-8b6a-6e388f7c67f2" ComponentArrays = "b0b7db55-cfe3-40fc-9ded-d10e2dbeff66" +CoordRefSystems = "b46f11dc-f210-4604-bfba-323c1ec968cb" Decapodes = "679ab3ea-c928-4fe6-8d59-fd451142d391" DiagrammaticEquations = "6f00c28b-6bed-4403-80fa-30e0dc12f317" +Distributions = "31c24e10-a181-5473-b8eb-7969acd0382f" +GeometryBasics = "5c1252a2-5f33-56bf-86c9-59e7332b4326" +HTTP = "cd3eb016-35fb-5094-929b-558a96fad6f3" JSON3 = "0f8b85d8-7281-11e9-16c2-39a750bddbf1" LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" MLStyle = "d8e11817-5142-5d16-987a-aa16d5891078" OrdinaryDiffEq = "1dea7af3-3e70-54e6-95c3-0bf5283fa5ed" +Oxygen = "df9a0d86-3283-4920-82dc-4555fc0d1d8b" StaticArrays = "90137ffa-7385-5640-81b9-e52037218182" +StructTypes = "856f2bd8-1eba-4b0a-8007-ebc267875bd4" Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" diff --git a/packages/algjulia-interop/test/TestCatlab.jl b/packages/algjulia-interop/test/TestCatlab.jl new file mode 100644 index 000000000..be90f421b --- /dev/null +++ b/packages/algjulia-interop/test/TestCatlab.jl @@ -0,0 +1,44 @@ +module TestCatlab + +using CatColabInterop, Catlab +using Catlab.CategoricalAlgebra.Pointwise.FunctorialDataMigrations.Yoneda: + colimit_representables +using HTTP, Test, Oxygen, JSON3 +const CatlabExt = Base.get_extension(CatColabInterop, :CatlabExt) + +# Example JSON +#------------- +body = read((@__DIR__)*"/data/diagrams/acset.json", String) + +# Parse the JSON +#--------------- +p = JSON3.read(body, ModelDiagram) + +# Convert to ACSet +#----------------- +schema, names = CatlabExt.model_to_schema(p.model) +acset_type = AnonACSet( + schema; type_assignment=Dict(a=>Nothing for a in schema.attrtypes)) +y = yoneda(constructor(acset_type)) +data = CatlabExt.diagram_to_data(p.diagram, names) +res = colimit_representables(data, y) + +# This is what we expect +#------------------------ +expected = acset_type +add_part!.(Ref(expected), [:X,:Y,:Z]) +expected[1, :f] = 1 +expected[1, :g] = AttrVar(1) + +@test is_isomorphic(res, expected) + +# Test final JSON output +#----------------------- +expected_json = Dict(:Z => 1,:f => [1],:X => 1,:Y => 1,:g => [1]) +@test expected_json == acset_to_json(res, schema) + +# Optionally test the endpoint if running endpoint.jl: +# resp = HTTP.post("http://127.0.0.1:8080/acsetcolim"; body) +# @test resp.status == 200 + +end # module diff --git a/packages/algjulia-interop/test/data/diagrams/acset.json b/packages/algjulia-interop/test/data/diagrams/acset.json new file mode 100644 index 000000000..ff637da03 --- /dev/null +++ b/packages/algjulia-interop/test/data/diagrams/acset.json @@ -0,0 +1,166 @@ +{ + "model": { + "obGenerators": [ + { + "id": "019a6042-1241-77bd-8055-bfea5c206bc7", + "label": [ + "X" + ], + "obType": { + "tag": "Basic", + "content": "Entity" + } + }, + { + "id": "019a6042-1f1c-745e-bfea-753eeaccedf2", + "label": [ + "Y" + ], + "obType": { + "tag": "Basic", + "content": "Entity" + } + }, + { + "id": "019a60e3-1785-72b9-90d2-84dc8bdddc85", + "label": [ + "Z" + ], + "obType": { + "tag": "Basic", + "content": "AttrType" + } + } + ], + "morGenerators": [ + { + "id": "019a6042-2872-7654-a9b4-67becc9ef693", + "label": [ + "f" + ], + "morType": { + "tag": "Hom", + "content": { + "tag": "Basic", + "content": "Entity" + } + }, + "dom": { + "tag": "Basic", + "content": "019a6042-1241-77bd-8055-bfea5c206bc7" + }, + "cod": { + "tag": "Basic", + "content": "019a6042-1f1c-745e-bfea-753eeaccedf2" + } + }, + { + "id": "019a60e3-2ccf-74ef-a1e1-1c940564e1ca", + "label": [ + "g" + ], + "morType": { + "tag": "Basic", + "content": "Attr" + }, + "dom": { + "tag": "Basic", + "content": "019a6042-1241-77bd-8055-bfea5c206bc7" + }, + "cod": { + "tag": "Basic", + "content": "019a60e3-1785-72b9-90d2-84dc8bdddc85" + } + } + ] + }, + "diagram": { + "obGenerators": [ + { + "id": "019a6042-7531-77c7-83db-67018685b551", + "label": [ + "x" + ], + "obType": { + "tag": "Basic", + "content": "Entity" + }, + "over": { + "tag": "Basic", + "content": "019a6042-1241-77bd-8055-bfea5c206bc7" + } + }, + { + "id": "019a6042-88fb-73f5-bd90-9d337485793a", + "label": [ + "y" + ], + "obType": { + "tag": "Basic", + "content": "Entity" + }, + "over": { + "tag": "Basic", + "content": "019a6042-1f1c-745e-bfea-753eeaccedf2" + } + }, + { + "id": "019a60e3-5bdb-745c-acd5-6f341f56833a", + "label": [ + "z" + ], + "obType": { + "tag": "Basic", + "content": "AttrType" + }, + "over": { + "tag": "Basic", + "content": "019a60e3-1785-72b9-90d2-84dc8bdddc85" + } + } + ], + "morGenerators": [ + { + "id": "019a6042-98ab-7120-80b7-3223fa942e96", + "morType": { + "tag": "Hom", + "content": { + "tag": "Basic", + "content": "Entity" + } + }, + "over": { + "tag": "Basic", + "content": "019a6042-2872-7654-a9b4-67becc9ef693" + }, + "dom": { + "tag": "Basic", + "content": "019a6042-7531-77c7-83db-67018685b551" + }, + "cod": { + "tag": "Basic", + "content": "019a6042-88fb-73f5-bd90-9d337485793a" + } + }, + { + "id": "019a60e3-6dbf-74cf-8bd9-be0d073a4ee8", + "morType": { + "tag": "Basic", + "content": "Attr" + }, + "over": { + "tag": "Basic", + "content": "019a60e3-2ccf-74ef-a1e1-1c940564e1ca" + }, + "dom": { + "tag": "Basic", + "content": "019a6042-7531-77c7-83db-67018685b551" + }, + "cod": { + "tag": "Basic", + "content": "019a60e3-5bdb-745c-acd5-6f341f56833a" + } + } + ] + } +} \ No newline at end of file diff --git a/packages/algjulia-interop/test/data/diagrams/inverse_laplacian_longtrip/analysis.json b/packages/algjulia-interop/test/data/diagrams/inverse_laplacian_longtrip/analysis.json new file mode 100644 index 000000000..9d12f6cef --- /dev/null +++ b/packages/algjulia-interop/test/data/diagrams/inverse_laplacian_longtrip/analysis.json @@ -0,0 +1,393 @@ +{ + "diagram": { + "obGenerators": [ + { + "id": "019b1f4e-5c83-7278-bbe8-b34486d42fc6", + "label": [ + "u" + ], + "obType": { + "tag": "Basic", + "content": "Object" + }, + "over": { + "tag": "Basic", + "content": "0194d398-d0cb-7308-b7e0-eace5b21af24" + } + }, + { + "id": "019b1f4e-6ddb-73e1-a136-04a6b9593579", + "label": [ + "du/dt" + ], + "obType": { + "tag": "Basic", + "content": "Object" + }, + "over": { + "tag": "Basic", + "content": "0194d398-d0cb-7308-b7e0-eace5b21af24" + } + }, + { + "id": "019b1f50-723f-720e-9d4b-0cf6619f5c3b", + "label": [ + 1 + ], + "obType": { + "tag": "Basic", + "content": "Object" + }, + "over": { + "tag": "Basic", + "content": "0194d398-a28e-7433-89f8-563bae6e6875" + } + }, + { + "id": "019b1f50-b3d5-75da-a625-8021f6582d61", + "label": [ + 2 + ], + "obType": { + "tag": "Basic", + "content": "Object" + }, + "over": { + "tag": "Basic", + "content": "0194d39a-89cf-762b-9d2a-5678b878d6c7" + } + }, + { + "id": "019b1f50-e249-776f-9657-dfceeb95223a", + "label": [ + 3 + ], + "obType": { + "tag": "Basic", + "content": "Object" + }, + "over": { + "tag": "Basic", + "content": "0194d398-b3ef-728d-bd88-60b48fd7349a" + } + } + ], + "morGenerators": [ + { + "id": "019b1f4e-c8d9-7176-ad29-603e326545fc", + "morType": { + "tag": "Basic", + "content": "Nonscalar" + }, + "over": { + "tag": "Basic", + "content": "0194d399-34f3-773c-91b9-857da9c4311f" + }, + "dom": { + "tag": "Basic", + "content": "019b1f4e-5c83-7278-bbe8-b34486d42fc6" + }, + "cod": { + "tag": "Basic", + "content": "019b1f50-723f-720e-9d4b-0cf6619f5c3b" + } + }, + { + "id": "019b1f50-7cd3-7468-89ef-2d00f0836bf9", + "morType": { + "tag": "Basic", + "content": "Nonscalar" + }, + "over": { + "tag": "Basic", + "content": "0194d39a-6084-7537-aec1-caf560ba416b" + }, + "dom": { + "tag": "Basic", + "content": "019b1f50-723f-720e-9d4b-0cf6619f5c3b" + }, + "cod": { + "tag": "Basic", + "content": "019b1f50-b3d5-75da-a625-8021f6582d61" + } + }, + { + "id": "019b1f50-be96-769d-858a-38b5d440240d", + "morType": { + "tag": "Basic", + "content": "Nonscalar" + }, + "over": { + "tag": "Basic", + "content": "0194d39a-ed25-710f-b53f-89541021281f" + }, + "dom": { + "tag": "Basic", + "content": "019b1f50-b3d5-75da-a625-8021f6582d61" + }, + "cod": { + "tag": "Basic", + "content": "019b1f50-e249-776f-9657-dfceeb95223a" + } + }, + { + "id": "019b1f50-ec80-70da-9759-b698e4b81ce9", + "morType": { + "tag": "Basic", + "content": "Nonscalar" + }, + "over": { + "tag": "Basic", + "content": "0194d39d-d297-77a9-95a2-6ed7105fdca3" + }, + "dom": { + "tag": "Basic", + "content": "019b1f50-e249-776f-9657-dfceeb95223a" + }, + "cod": { + "tag": "Basic", + "content": "019b1f4e-6ddb-73e1-a136-04a6b9593579" + } + }, + { + "id": "019b1f4f-03a0-7288-8b3b-da2c46b0b675", + "morType": { + "tag": "Basic", + "content": "Nonscalar" + }, + "over": { + "tag": "Basic", + "content": "0194d39c-622d-7599-bc5c-e7e8208d6cdd" + }, + "dom": { + "tag": "Basic", + "content": "019b1f4e-5c83-7278-bbe8-b34486d42fc6" + }, + "cod": { + "tag": "Basic", + "content": "019b1f4e-6ddb-73e1-a136-04a6b9593579" + } + } + ] + }, + "model": { + "obGenerators": [ + { + "id": "0194d398-a28e-7433-89f8-563bae6e6875", + "label": [ + "0-form" + ], + "obType": { + "tag": "Basic", + "content": "Object" + } + }, + { + "id": "0194d398-b3ef-728d-bd88-60b48fd7349a", + "label": [ + "Dual 1-form" + ], + "obType": { + "tag": "Basic", + "content": "Object" + } + }, + { + "id": "0194d398-d0cb-7308-b7e0-eace5b21af24", + "label": [ + "Dual 2-form" + ], + "obType": { + "tag": "Basic", + "content": "Object" + } + }, + { + "id": "0194d39a-89cf-762b-9d2a-5678b878d6c7", + "label": [ + "Primal 1-form" + ], + "obType": { + "tag": "Basic", + "content": "Object" + } + } + ], + "morGenerators": [ + { + "id": "0194d399-34f3-773c-91b9-857da9c4311f", + "label": [ + " ⋆₀⁻¹" + ], + "morType": { + "tag": "Basic", + "content": "Nonscalar" + }, + "dom": { + "tag": "Basic", + "content": "0194d398-d0cb-7308-b7e0-eace5b21af24" + }, + "cod": { + "tag": "Basic", + "content": "0194d398-a28e-7433-89f8-563bae6e6875" + } + }, + { + "id": "0194d399-b2a2-73ff-aece-cb0f26644045", + "label": [ + "Δ⁻¹" + ], + "morType": { + "tag": "Basic", + "content": "Nonscalar" + }, + "dom": { + "tag": "Basic", + "content": "0194d398-a28e-7433-89f8-563bae6e6875" + }, + "cod": { + "tag": "Basic", + "content": "0194d398-a28e-7433-89f8-563bae6e6875" + } + }, + { + "id": "0194d39a-6084-7537-aec1-caf560ba416b", + "label": [ + "d₀" + ], + "morType": { + "tag": "Basic", + "content": "Nonscalar" + }, + "dom": { + "tag": "Basic", + "content": "0194d398-a28e-7433-89f8-563bae6e6875" + }, + "cod": { + "tag": "Basic", + "content": "0194d39a-89cf-762b-9d2a-5678b878d6c7" + } + }, + { + "id": "0194d39a-ed25-710f-b53f-89541021281f", + "label": [ + "⋆₁" + ], + "morType": { + "tag": "Basic", + "content": "Nonscalar" + }, + "dom": { + "tag": "Basic", + "content": "0194d39a-89cf-762b-9d2a-5678b878d6c7" + }, + "cod": { + "tag": "Basic", + "content": "0194d398-b3ef-728d-bd88-60b48fd7349a" + } + }, + { + "id": "0194d39b-587f-7559-a1ff-b6ed58899461", + "label": [ + "lamb" + ], + "morType": { + "tag": "Basic", + "content": "Nonscalar" + }, + "dom": { + "tag": "Basic", + "content": "0194d398-b3ef-728d-bd88-60b48fd7349a" + }, + "cod": { + "tag": "Basic", + "content": "0194d398-b3ef-728d-bd88-60b48fd7349a" + } + }, + { + "id": "0194d39b-a70a-77d5-8e89-66f0e767a9da", + "label": [ + " ♭♯" + ], + "morType": { + "tag": "Basic", + "content": "Nonscalar" + }, + "dom": { + "tag": "Basic", + "content": "0194d398-b3ef-728d-bd88-60b48fd7349a" + }, + "cod": { + "tag": "Basic", + "content": "0194d39a-89cf-762b-9d2a-5678b878d6c7" + } + }, + { + "id": "0194d39d-d297-77a9-95a2-6ed7105fdca3", + "label": [ + "d̃₁" + ], + "morType": { + "tag": "Basic", + "content": "Nonscalar" + }, + "dom": { + "tag": "Basic", + "content": "0194d398-b3ef-728d-bd88-60b48fd7349a" + }, + "cod": { + "tag": "Basic", + "content": "0194d398-d0cb-7308-b7e0-eace5b21af24" + } + }, + { + "id": "0194d39c-622d-7599-bc5c-e7e8208d6cdd", + "label": [ + "∂ₜ" + ], + "morType": { + "tag": "Basic", + "content": "Nonscalar" + }, + "dom": { + "tag": "Basic", + "content": "0194d398-d0cb-7308-b7e0-eace5b21af24" + }, + "cod": { + "tag": "Basic", + "content": "0194d398-d0cb-7308-b7e0-eace5b21af24" + } + }, + { + "id": "0194d39e-5d44-77cd-bc5e-156c5c56ae85", + "label": [ + "-" + ], + "morType": { + "tag": "Basic", + "content": "Nonscalar" + }, + "dom": { + "tag": "Basic", + "content": "0194d398-d0cb-7308-b7e0-eace5b21af24" + }, + "cod": { + "tag": "Basic", + "content": "0194d398-d0cb-7308-b7e0-eace5b21af24" + } + } + ] + }, + "analysis": { + "domain": "Plane", + "mesh": "Rectangle", + "initialConditions": { + "019b1f4e-5c83-7278-bbe8-b34486d42fc6": "Gaussian" + }, + "plotVariables": [ + "019b1f4e-5c83-7278-bbe8-b34486d42fc6" + ], + "scalars": {}, + "duration": 10 + } +} diff --git a/packages/algjulia-interop/test/test_jsons/diagrams/inverse_laplacian_longtrip/diagram.json b/packages/algjulia-interop/test/data/diagrams/inverse_laplacian_longtrip/diagram.json similarity index 100% rename from packages/algjulia-interop/test/test_jsons/diagrams/inverse_laplacian_longtrip/diagram.json rename to packages/algjulia-interop/test/data/diagrams/inverse_laplacian_longtrip/diagram.json diff --git a/packages/algjulia-interop/test/data/diagrams/inverse_laplacian_longtrip/diagram_analysis.json b/packages/algjulia-interop/test/data/diagrams/inverse_laplacian_longtrip/diagram_analysis.json new file mode 100644 index 000000000..ebb5612d8 --- /dev/null +++ b/packages/algjulia-interop/test/data/diagrams/inverse_laplacian_longtrip/diagram_analysis.json @@ -0,0 +1,391 @@ +{ + "diagram": { + "obGenerators": [ + { + "id": "019a5ace-3497-71db-a8f9-c2d02e5e7182", + "label": [ + "u" + ], + "obType": { + "tag": "Basic", + "content": "Object" + }, + "over": { + "tag": "Basic", + "content": "0194d398-d0cb-7308-b7e0-eace5b21af24" + } + }, + { + "id": "019a5ace-4426-77a8-8242-7930b07560fe", + "label": [ + "du/dt" + ], + "obType": { + "tag": "Basic", + "content": "Object" + }, + "over": { + "tag": "Basic", + "content": "0194d398-d0cb-7308-b7e0-eace5b21af24" + } + }, + { + "id": "019a5ace-7078-7799-babf-1b3d8043759f", + "label": [ + 1 + ], + "obType": { + "tag": "Basic", + "content": "Object" + }, + "over": { + "tag": "Basic", + "content": "0194d398-a28e-7433-89f8-563bae6e6875" + } + }, + { + "id": "019a5ace-a18b-71b3-9aa1-7948b0ad138f", + "label": [ + 2 + ], + "obType": { + "tag": "Basic", + "content": "Object" + }, + "over": { + "tag": "Basic", + "content": "0194d39a-89cf-762b-9d2a-5678b878d6c7" + } + }, + { + "id": "019a5acf-10cb-7083-84aa-191fa52123ae", + "label": [ + 3 + ], + "obType": { + "tag": "Basic", + "content": "Object" + }, + "over": { + "tag": "Basic", + "content": "0194d398-b3ef-728d-bd88-60b48fd7349a" + } + } + ], + "morGenerators": [ + { + "id": "019a5ace-ea37-70a5-ab29-74183295ba2e", + "morType": { + "tag": "Basic", + "content": "Nonscalar" + }, + "over": { + "tag": "Basic", + "content": "0194d39c-622d-7599-bc5c-e7e8208d6cdd" + }, + "dom": { + "tag": "Basic", + "content": "019a5ace-3497-71db-a8f9-c2d02e5e7182" + }, + "cod": { + "tag": "Basic", + "content": "019a5ace-4426-77a8-8242-7930b07560fe" + } + }, + { + "id": "019a5ace-5fd7-708e-813e-a4e9201ee874", + "morType": { + "tag": "Basic", + "content": "Nonscalar" + }, + "over": { + "tag": "Basic", + "content": "0194d399-34f3-773c-91b9-857da9c4311f" + }, + "dom": { + "tag": "Basic", + "content": "019a5ace-3497-71db-a8f9-c2d02e5e7182" + }, + "cod": { + "tag": "Basic", + "content": "019a5ace-7078-7799-babf-1b3d8043759f" + } + }, + { + "id": "019a5ace-9226-73aa-a51a-1b88a752d247", + "morType": { + "tag": "Basic", + "content": "Nonscalar" + }, + "over": { + "tag": "Basic", + "content": "0194d39a-6084-7537-aec1-caf560ba416b" + }, + "dom": { + "tag": "Basic", + "content": "019a5ace-7078-7799-babf-1b3d8043759f" + }, + "cod": { + "tag": "Basic", + "content": "019a5ace-a18b-71b3-9aa1-7948b0ad138f" + } + }, + { + "id": "019a5ace-beb6-71fa-8efa-3585825be090", + "morType": { + "tag": "Basic", + "content": "Nonscalar" + }, + "over": { + "tag": "Basic", + "content": "0194d39a-ed25-710f-b53f-89541021281f" + }, + "dom": { + "tag": "Basic", + "content": "019a5ace-a18b-71b3-9aa1-7948b0ad138f" + }, + "cod": { + "tag": "Basic", + "content": "019a5acf-10cb-7083-84aa-191fa52123ae" + } + }, + { + "id": "019a5acf-193d-720c-96b4-42680fe15ab6", + "morType": { + "tag": "Basic", + "content": "Nonscalar" + }, + "over": { + "tag": "Basic", + "content": "0194d39d-d297-77a9-95a2-6ed7105fdca3" + }, + "dom": { + "tag": "Basic", + "content": "019a5acf-10cb-7083-84aa-191fa52123ae" + }, + "cod": { + "tag": "Basic", + "content": "019a5ace-4426-77a8-8242-7930b07560fe" + } + } + ] + }, + "model": { + "obGenerators": [ + { + "id": "0194d398-a28e-7433-89f8-563bae6e6875", + "label": [ + "0-form" + ], + "obType": { + "tag": "Basic", + "content": "Object" + } + }, + { + "id": "0194d398-b3ef-728d-bd88-60b48fd7349a", + "label": [ + "Dual 1-form" + ], + "obType": { + "tag": "Basic", + "content": "Object" + } + }, + { + "id": "0194d398-d0cb-7308-b7e0-eace5b21af24", + "label": [ + "Dual 2-form" + ], + "obType": { + "tag": "Basic", + "content": "Object" + } + }, + { + "id": "0194d39a-89cf-762b-9d2a-5678b878d6c7", + "label": [ + "Primal 1-form" + ], + "obType": { + "tag": "Basic", + "content": "Object" + } + } + ], + "morGenerators": [ + { + "id": "0194d399-34f3-773c-91b9-857da9c4311f", + "label": [ + " ⋆₀⁻¹" + ], + "morType": { + "tag": "Basic", + "content": "Nonscalar" + }, + "dom": { + "tag": "Basic", + "content": "0194d398-d0cb-7308-b7e0-eace5b21af24" + }, + "cod": { + "tag": "Basic", + "content": "0194d398-a28e-7433-89f8-563bae6e6875" + } + }, + { + "id": "0194d399-b2a2-73ff-aece-cb0f26644045", + "label": [ + "Δ⁻¹" + ], + "morType": { + "tag": "Basic", + "content": "Nonscalar" + }, + "dom": { + "tag": "Basic", + "content": "0194d398-a28e-7433-89f8-563bae6e6875" + }, + "cod": { + "tag": "Basic", + "content": "0194d398-a28e-7433-89f8-563bae6e6875" + } + }, + { + "id": "0194d39a-6084-7537-aec1-caf560ba416b", + "label": [ + "d₀" + ], + "morType": { + "tag": "Basic", + "content": "Nonscalar" + }, + "dom": { + "tag": "Basic", + "content": "0194d398-a28e-7433-89f8-563bae6e6875" + }, + "cod": { + "tag": "Basic", + "content": "0194d39a-89cf-762b-9d2a-5678b878d6c7" + } + }, + { + "id": "0194d39a-ed25-710f-b53f-89541021281f", + "label": [ + "⋆₁" + ], + "morType": { + "tag": "Basic", + "content": "Nonscalar" + }, + "dom": { + "tag": "Basic", + "content": "0194d39a-89cf-762b-9d2a-5678b878d6c7" + }, + "cod": { + "tag": "Basic", + "content": "0194d398-b3ef-728d-bd88-60b48fd7349a" + } + }, + { + "id": "0194d39b-587f-7559-a1ff-b6ed58899461", + "label": [ + "lamb" + ], + "morType": { + "tag": "Basic", + "content": "Nonscalar" + }, + "dom": { + "tag": "Basic", + "content": "0194d398-b3ef-728d-bd88-60b48fd7349a" + }, + "cod": { + "tag": "Basic", + "content": "0194d398-b3ef-728d-bd88-60b48fd7349a" + } + }, + { + "id": "0194d39b-a70a-77d5-8e89-66f0e767a9da", + "label": [ + " ♭♯" + ], + "morType": { + "tag": "Basic", + "content": "Nonscalar" + }, + "dom": { + "tag": "Basic", + "content": "0194d398-b3ef-728d-bd88-60b48fd7349a" + }, + "cod": { + "tag": "Basic", + "content": "0194d39a-89cf-762b-9d2a-5678b878d6c7" + } + }, + { + "id": "0194d39d-d297-77a9-95a2-6ed7105fdca3", + "label": [ + "d̃₁" + ], + "morType": { + "tag": "Basic", + "content": "Nonscalar" + }, + "dom": { + "tag": "Basic", + "content": "0194d398-b3ef-728d-bd88-60b48fd7349a" + }, + "cod": { + "tag": "Basic", + "content": "0194d398-d0cb-7308-b7e0-eace5b21af24" + } + }, + { + "id": "0194d39c-622d-7599-bc5c-e7e8208d6cdd", + "label": [ + "∂ₜ" + ], + "morType": { + "tag": "Basic", + "content": "Nonscalar" + }, + "dom": { + "tag": "Basic", + "content": "0194d398-d0cb-7308-b7e0-eace5b21af24" + }, + "cod": { + "tag": "Basic", + "content": "0194d398-d0cb-7308-b7e0-eace5b21af24" + } + }, + { + "id": "0194d39e-5d44-77cd-bc5e-156c5c56ae85", + "label": [ + "-" + ], + "morType": { + "tag": "Basic", + "content": "Nonscalar" + }, + "dom": { + "tag": "Basic", + "content": "0194d398-d0cb-7308-b7e0-eace5b21af24" + }, + "cod": { + "tag": "Basic", + "content": "0194d398-d0cb-7308-b7e0-eace5b21af24" + } + } + ] + }, + "domain": "Plane", + "mesh": "Rectangle", + "initialConditions": { + "019a5ace-3497-71db-a8f9-c2d02e5e7182": "Gaussian" + }, + "plotVariables": [ + "019a5ace-3497-71db-a8f9-c2d02e5e7182" + ], + "scalars": {}, + "duration": 10 +} diff --git a/packages/algjulia-interop/test/data/diagrams/ns_vort/analysis.json b/packages/algjulia-interop/test/data/diagrams/ns_vort/analysis.json new file mode 100644 index 000000000..812d4a795 --- /dev/null +++ b/packages/algjulia-interop/test/data/diagrams/ns_vort/analysis.json @@ -0,0 +1,559 @@ +{ + "diagram": { + "obGenerators": [ + { + "id": "019a57e3-4df4-7399-b7ed-0cd4d7522ddb", + "label": [ + "v" + ], + "obType": { + "tag": "Basic", + "content": "Object" + }, + "over": { + "tag": "Basic", + "content": "0194d398-b3ef-728d-bd88-60b48fd7349a" + } + }, + { + "id": "019a57e3-5f93-71d8-8dc5-1c9e62a5a072", + "label": [ + "dv" + ], + "obType": { + "tag": "Basic", + "content": "Object" + }, + "over": { + "tag": "Basic", + "content": "0194d398-d0cb-7308-b7e0-eace5b21af24" + } + }, + { + "id": "019a57e3-795f-770b-9c97-417b08162302", + "label": [ + "ψ" + ], + "obType": { + "tag": "Basic", + "content": "Object" + }, + "over": { + "tag": "Basic", + "content": "0194d398-a28e-7433-89f8-563bae6e6875" + } + }, + { + "id": "019a57e3-ba4f-76ea-bb74-089679300d6e", + "label": [ + 1 + ], + "obType": { + "tag": "Basic", + "content": "Object" + }, + "over": { + "tag": "Basic", + "content": "0194d398-a28e-7433-89f8-563bae6e6875" + } + }, + { + "id": "019a57e4-07f9-728f-abf2-fb904a25947a", + "label": [ + 2 + ], + "obType": { + "tag": "Basic", + "content": "Object" + }, + "over": { + "tag": "Basic", + "content": "0194d39a-89cf-762b-9d2a-5678b878d6c7" + } + }, + { + "id": "019a57e4-4416-76aa-a619-a2751769ce55", + "label": [ + 3 + ], + "obType": { + "tag": "Basic", + "content": "Object" + }, + "over": { + "tag": "Basic", + "content": "0194d398-b3ef-728d-bd88-60b48fd7349a" + } + }, + { + "id": "019a57e4-6e30-701d-8ebf-5cfa1694d240", + "label": [ + 4 + ], + "obType": { + "tag": "Basic", + "content": "Object" + }, + "over": { + "tag": "Basic", + "content": "0194d39a-89cf-762b-9d2a-5678b878d6c7" + } + }, + { + "id": "019a57e4-8cac-72ae-8a61-ae889c4cab82", + "label": [ + 5 + ], + "obType": { + "tag": "Basic", + "content": "Object" + }, + "over": { + "tag": "Basic", + "content": "0194d398-b3ef-728d-bd88-60b48fd7349a" + } + }, + { + "id": "019a57e4-ba19-72fb-a891-78a28a81042c", + "label": [ + 6 + ], + "obType": { + "tag": "Basic", + "content": "Object" + }, + "over": { + "tag": "Basic", + "content": "0194d398-d0cb-7308-b7e0-eace5b21af24" + } + }, + { + "id": "019a57f2-c8f8-70b0-9868-baff77d2ba3a", + "label": [ + 7 + ], + "obType": { + "tag": "Basic", + "content": "Object" + }, + "over": { + "tag": "Basic", + "content": "0194d398-d0cb-7308-b7e0-eace5b21af24" + } + } + ], + "morGenerators": [ + { + "id": "019a57e3-a85a-7369-92e2-ae06706cd003", + "morType": { + "tag": "Basic", + "content": "Nonscalar" + }, + "over": { + "tag": "Basic", + "content": "0194d399-34f3-773c-91b9-857da9c4311f" + }, + "dom": { + "tag": "Basic", + "content": "019a57e3-5f93-71d8-8dc5-1c9e62a5a072" + }, + "cod": { + "tag": "Basic", + "content": "019a57e3-ba4f-76ea-bb74-089679300d6e" + } + }, + { + "id": "019a57e3-c2f3-765e-9114-8bd4c87f0ae9", + "morType": { + "tag": "Basic", + "content": "Nonscalar" + }, + "over": { + "tag": "Basic", + "content": "0194d399-b2a2-73ff-aece-cb0f26644045" + }, + "dom": { + "tag": "Basic", + "content": "019a57e3-ba4f-76ea-bb74-089679300d6e" + }, + "cod": { + "tag": "Basic", + "content": "019a57e3-795f-770b-9c97-417b08162302" + } + }, + { + "id": "019a57e3-e94e-775e-98e9-c99c2d94e97b", + "morType": { + "tag": "Basic", + "content": "Nonscalar" + }, + "over": { + "tag": "Basic", + "content": "0194d39a-6084-7537-aec1-caf560ba416b" + }, + "dom": { + "tag": "Basic", + "content": "019a57e3-795f-770b-9c97-417b08162302" + }, + "cod": { + "tag": "Basic", + "content": "019a57e4-07f9-728f-abf2-fb904a25947a" + } + }, + { + "id": "019a57e4-1014-72ac-b068-0174b22e7526", + "morType": { + "tag": "Basic", + "content": "Nonscalar" + }, + "over": { + "tag": "Basic", + "content": "0194d39a-ed25-710f-b53f-89541021281f" + }, + "dom": { + "tag": "Basic", + "content": "019a57e4-07f9-728f-abf2-fb904a25947a" + }, + "cod": { + "tag": "Basic", + "content": "019a57e3-4df4-7399-b7ed-0cd4d7522ddb" + } + }, + { + "id": "019a57e4-354a-7722-a6d5-db01ce3eed64", + "morType": { + "tag": "Basic", + "content": "Nonscalar" + }, + "over": { + "tag": "Basic", + "content": "0194d39b-587f-7559-a1ff-b6ed58899461" + }, + "dom": { + "tag": "Basic", + "content": "019a57e3-4df4-7399-b7ed-0cd4d7522ddb" + }, + "cod": { + "tag": "Basic", + "content": "019a57e4-4416-76aa-a619-a2751769ce55" + } + }, + { + "id": "019a57e4-4c71-76f2-936b-4862c73cf167", + "morType": { + "tag": "Basic", + "content": "Nonscalar" + }, + "over": { + "tag": "Basic", + "content": "0194d39b-a70a-77d5-8e89-66f0e767a9da" + }, + "dom": { + "tag": "Basic", + "content": "019a57e4-4416-76aa-a619-a2751769ce55" + }, + "cod": { + "tag": "Basic", + "content": "019a57e4-6e30-701d-8ebf-5cfa1694d240" + } + }, + { + "id": "019a57e4-758a-71df-89db-56ef0d89048d", + "morType": { + "tag": "Basic", + "content": "Nonscalar" + }, + "over": { + "tag": "Basic", + "content": "0194d39a-ed25-710f-b53f-89541021281f" + }, + "dom": { + "tag": "Basic", + "content": "019a57e4-6e30-701d-8ebf-5cfa1694d240" + }, + "cod": { + "tag": "Basic", + "content": "019a57e4-8cac-72ae-8a61-ae889c4cab82" + } + }, + { + "id": "019a57e4-a86a-76ab-804d-26c74ccd887a", + "morType": { + "tag": "Basic", + "content": "Nonscalar" + }, + "over": { + "tag": "Basic", + "content": "0194d39c-622d-7599-bc5c-e7e8208d6cdd" + }, + "dom": { + "tag": "Basic", + "content": "019a57e3-5f93-71d8-8dc5-1c9e62a5a072" + }, + "cod": { + "tag": "Basic", + "content": "019a57e4-ba19-72fb-a891-78a28a81042c" + } + }, + { + "id": "019a57f2-a590-743b-99aa-debd43ba9b19", + "morType": { + "tag": "Basic", + "content": "Nonscalar" + }, + "over": { + "tag": "Basic", + "content": "0194d39d-d297-77a9-95a2-6ed7105fdca3" + }, + "dom": { + "tag": "Basic", + "content": "019a57e4-8cac-72ae-8a61-ae889c4cab82" + }, + "cod": { + "tag": "Basic", + "content": "019a57f2-c8f8-70b0-9868-baff77d2ba3a" + } + }, + { + "id": "019a57f2-d229-74bd-a923-838743189fa3", + "morType": { + "tag": "Basic", + "content": "Nonscalar" + }, + "over": { + "tag": "Basic", + "content": "0194d39e-5d44-77cd-bc5e-156c5c56ae85" + }, + "dom": { + "tag": "Basic", + "content": "019a57f2-c8f8-70b0-9868-baff77d2ba3a" + }, + "cod": { + "tag": "Basic", + "content": "019a57e4-ba19-72fb-a891-78a28a81042c" + } + } + ] + }, + "model": { + "obGenerators": [ + { + "id": "0194d398-a28e-7433-89f8-563bae6e6875", + "label": [ + "0-form" + ], + "obType": { + "tag": "Basic", + "content": "Object" + } + }, + { + "id": "0194d398-b3ef-728d-bd88-60b48fd7349a", + "label": [ + "Dual 1-form" + ], + "obType": { + "tag": "Basic", + "content": "Object" + } + }, + { + "id": "0194d398-d0cb-7308-b7e0-eace5b21af24", + "label": [ + "Dual 2-form" + ], + "obType": { + "tag": "Basic", + "content": "Object" + } + }, + { + "id": "0194d39a-89cf-762b-9d2a-5678b878d6c7", + "label": [ + "Primal 1-form" + ], + "obType": { + "tag": "Basic", + "content": "Object" + } + } + ], + "morGenerators": [ + { + "id": "0194d399-34f3-773c-91b9-857da9c4311f", + "label": [ + " ⋆₀⁻¹" + ], + "morType": { + "tag": "Basic", + "content": "Nonscalar" + }, + "dom": { + "tag": "Basic", + "content": "0194d398-d0cb-7308-b7e0-eace5b21af24" + }, + "cod": { + "tag": "Basic", + "content": "0194d398-a28e-7433-89f8-563bae6e6875" + } + }, + { + "id": "0194d399-b2a2-73ff-aece-cb0f26644045", + "label": [ + "Δ⁻¹" + ], + "morType": { + "tag": "Basic", + "content": "Nonscalar" + }, + "dom": { + "tag": "Basic", + "content": "0194d398-a28e-7433-89f8-563bae6e6875" + }, + "cod": { + "tag": "Basic", + "content": "0194d398-a28e-7433-89f8-563bae6e6875" + } + }, + { + "id": "0194d39a-6084-7537-aec1-caf560ba416b", + "label": [ + "d₀" + ], + "morType": { + "tag": "Basic", + "content": "Nonscalar" + }, + "dom": { + "tag": "Basic", + "content": "0194d398-a28e-7433-89f8-563bae6e6875" + }, + "cod": { + "tag": "Basic", + "content": "0194d39a-89cf-762b-9d2a-5678b878d6c7" + } + }, + { + "id": "0194d39a-ed25-710f-b53f-89541021281f", + "label": [ + "⋆₁" + ], + "morType": { + "tag": "Basic", + "content": "Nonscalar" + }, + "dom": { + "tag": "Basic", + "content": "0194d39a-89cf-762b-9d2a-5678b878d6c7" + }, + "cod": { + "tag": "Basic", + "content": "0194d398-b3ef-728d-bd88-60b48fd7349a" + } + }, + { + "id": "0194d39b-587f-7559-a1ff-b6ed58899461", + "label": [ + "lamb" + ], + "morType": { + "tag": "Basic", + "content": "Nonscalar" + }, + "dom": { + "tag": "Basic", + "content": "0194d398-b3ef-728d-bd88-60b48fd7349a" + }, + "cod": { + "tag": "Basic", + "content": "0194d398-b3ef-728d-bd88-60b48fd7349a" + } + }, + { + "id": "0194d39b-a70a-77d5-8e89-66f0e767a9da", + "label": [ + " ♭♯" + ], + "morType": { + "tag": "Basic", + "content": "Nonscalar" + }, + "dom": { + "tag": "Basic", + "content": "0194d398-b3ef-728d-bd88-60b48fd7349a" + }, + "cod": { + "tag": "Basic", + "content": "0194d39a-89cf-762b-9d2a-5678b878d6c7" + } + }, + { + "id": "0194d39d-d297-77a9-95a2-6ed7105fdca3", + "label": [ + "d̃₁" + ], + "morType": { + "tag": "Basic", + "content": "Nonscalar" + }, + "dom": { + "tag": "Basic", + "content": "0194d398-b3ef-728d-bd88-60b48fd7349a" + }, + "cod": { + "tag": "Basic", + "content": "0194d398-d0cb-7308-b7e0-eace5b21af24" + } + }, + { + "id": "0194d39c-622d-7599-bc5c-e7e8208d6cdd", + "label": [ + "∂ₜ" + ], + "morType": { + "tag": "Basic", + "content": "Nonscalar" + }, + "dom": { + "tag": "Basic", + "content": "0194d398-d0cb-7308-b7e0-eace5b21af24" + }, + "cod": { + "tag": "Basic", + "content": "0194d398-d0cb-7308-b7e0-eace5b21af24" + } + }, + { + "id": "0194d39e-5d44-77cd-bc5e-156c5c56ae85", + "label": [ + "-" + ], + "morType": { + "tag": "Basic", + "content": "Nonscalar" + }, + "dom": { + "tag": "Basic", + "content": "0194d398-d0cb-7308-b7e0-eace5b21af24" + }, + "cod": { + "tag": "Basic", + "content": "0194d398-d0cb-7308-b7e0-eace5b21af24" + } + } + ] + }, + "analysis": { + "domain": "Sphere", + "mesh": "Icosphere6", + "initialConditions": { + "019a57e3-4df4-7399-b7ed-0cd4d7522ddb": "TaylorVortex", + "019a57e3-5f93-71d8-8dc5-1c9e62a5a072": "TaylorVortex" + }, + "plotVariables": [ + "019a57e3-5f93-71d8-8dc5-1c9e62a5a072" + ], + "scalars": {}, + "duration": 10 + } +} diff --git a/packages/algjulia-interop/test/test_jsons/models/model_dec.json b/packages/algjulia-interop/test/data/models/model_dec.json similarity index 83% rename from packages/algjulia-interop/test/test_jsons/models/model_dec.json rename to packages/algjulia-interop/test/data/models/model_dec.json index f7053967f..1096c3af6 100644 --- a/packages/algjulia-interop/test/test_jsons/models/model_dec.json +++ b/packages/algjulia-interop/test/data/models/model_dec.json @@ -1,8 +1,8 @@ { "name": "DEC for vorticity", "notebook": { - "cells": [ - { + "cellContents": { + "0194d398-a28e-7433-89f8-5a563b37d845": { "content": { "id": "0194d398-a28e-7433-89f8-563bae6e6875", "name": "0-form", @@ -15,7 +15,7 @@ "id": "0194d398-a28e-7433-89f8-5a563b37d845", "tag": "formal" }, - { + "0194d398-b3ef-728d-bd88-64aa410935d0": { "content": { "id": "0194d398-b3ef-728d-bd88-60b48fd7349a", "name": "Dual 1-form", @@ -28,7 +28,7 @@ "id": "0194d398-b3ef-728d-bd88-64aa410935d0", "tag": "formal" }, - { + "0194d398-d0cb-7308-b7e0-ed7c6bca5073": { "content": { "id": "0194d398-d0cb-7308-b7e0-eace5b21af24", "name": "Dual 2-form", @@ -41,20 +41,7 @@ "id": "0194d398-d0cb-7308-b7e0-ed7c6bca5073", "tag": "formal" }, - { - "content": { - "id": "0194d39a-89cf-762b-9d2a-5678b878d6c7", - "name": "Primal 1-form", - "obType": { - "content": "Object", - "tag": "Basic" - }, - "tag": "object" - }, - "id": "0194d39a-89cf-762b-9d2a-58435e3f239e", - "tag": "formal" - }, - { + "0194d399-34f3-773c-91b9-8ba5ecdb1ae3": { "content": { "cod": { "content": "0194d398-a28e-7433-89f8-563bae6e6875", @@ -75,7 +62,7 @@ "id": "0194d399-34f3-773c-91b9-8ba5ecdb1ae3", "tag": "formal" }, - { + "0194d399-b2a2-73ff-aece-ccafcd2f4901": { "content": { "cod": { "content": "0194d398-a28e-7433-89f8-563bae6e6875", @@ -96,7 +83,7 @@ "id": "0194d399-b2a2-73ff-aece-ccafcd2f4901", "tag": "formal" }, - { + "0194d39a-6084-7537-aec1-cf63f29c9a9f": { "content": { "cod": { "content": "0194d39a-89cf-762b-9d2a-5678b878d6c7", @@ -117,7 +104,20 @@ "id": "0194d39a-6084-7537-aec1-cf63f29c9a9f", "tag": "formal" }, - { + "0194d39a-89cf-762b-9d2a-58435e3f239e": { + "content": { + "id": "0194d39a-89cf-762b-9d2a-5678b878d6c7", + "name": "Primal 1-form", + "obType": { + "content": "Object", + "tag": "Basic" + }, + "tag": "object" + }, + "id": "0194d39a-89cf-762b-9d2a-58435e3f239e", + "tag": "formal" + }, + "0194d39a-ed25-710f-b53f-8dfad8f332aa": { "content": { "cod": { "content": "0194d398-b3ef-728d-bd88-60b48fd7349a", @@ -138,7 +138,7 @@ "id": "0194d39a-ed25-710f-b53f-8dfad8f332aa", "tag": "formal" }, - { + "0194d39b-587f-7559-a1ff-b9a4cc198cff": { "content": { "cod": { "content": "0194d398-b3ef-728d-bd88-60b48fd7349a", @@ -159,7 +159,7 @@ "id": "0194d39b-587f-7559-a1ff-b9a4cc198cff", "tag": "formal" }, - { + "0194d39b-a70a-77d5-8e89-6a34504e2754": { "content": { "cod": { "content": "0194d39a-89cf-762b-9d2a-5678b878d6c7", @@ -180,49 +180,49 @@ "id": "0194d39b-a70a-77d5-8e89-6a34504e2754", "tag": "formal" }, - { + "0194d39c-622d-7599-bc5c-e86b88f88031": { "content": { "cod": { "content": "0194d398-d0cb-7308-b7e0-eace5b21af24", "tag": "Basic" }, "dom": { - "content": "0194d398-b3ef-728d-bd88-60b48fd7349a", + "content": "0194d398-d0cb-7308-b7e0-eace5b21af24", "tag": "Basic" }, - "id": "0194d39d-d297-77a9-95a2-6ed7105fdca3", + "id": "0194d39c-622d-7599-bc5c-e7e8208d6cdd", "morType": { "content": "Nonscalar", "tag": "Basic" }, - "name": "d̃₁", + "name": "∂ₜ", "tag": "morphism" }, - "id": "0194d39d-d297-77a9-95a2-71f5210cecf2", + "id": "0194d39c-622d-7599-bc5c-e86b88f88031", "tag": "formal" }, - { + "0194d39d-d297-77a9-95a2-71f5210cecf2": { "content": { "cod": { "content": "0194d398-d0cb-7308-b7e0-eace5b21af24", "tag": "Basic" }, "dom": { - "content": "0194d398-d0cb-7308-b7e0-eace5b21af24", + "content": "0194d398-b3ef-728d-bd88-60b48fd7349a", "tag": "Basic" }, - "id": "0194d39c-622d-7599-bc5c-e7e8208d6cdd", + "id": "0194d39d-d297-77a9-95a2-6ed7105fdca3", "morType": { "content": "Nonscalar", "tag": "Basic" }, - "name": "∂ₜ", + "name": "d̃₁", "tag": "morphism" }, - "id": "0194d39c-622d-7599-bc5c-e86b88f88031", + "id": "0194d39d-d297-77a9-95a2-71f5210cecf2", "tag": "formal" }, - { + "0194d39e-5d44-77cd-bc5e-1aa6b0a2d8d4": { "content": { "cod": { "content": "0194d398-d0cb-7308-b7e0-eace5b21af24", @@ -243,8 +243,24 @@ "id": "0194d39e-5d44-77cd-bc5e-1aa6b0a2d8d4", "tag": "formal" } + }, + "cellOrder": [ + "0194d398-a28e-7433-89f8-5a563b37d845", + "0194d398-b3ef-728d-bd88-64aa410935d0", + "0194d398-d0cb-7308-b7e0-ed7c6bca5073", + "0194d39a-89cf-762b-9d2a-58435e3f239e", + "0194d399-34f3-773c-91b9-8ba5ecdb1ae3", + "0194d399-b2a2-73ff-aece-ccafcd2f4901", + "0194d39a-6084-7537-aec1-cf63f29c9a9f", + "0194d39a-ed25-710f-b53f-8dfad8f332aa", + "0194d39b-587f-7559-a1ff-b9a4cc198cff", + "0194d39b-a70a-77d5-8e89-6a34504e2754", + "0194d39d-d297-77a9-95a2-71f5210cecf2", + "0194d39c-622d-7599-bc5c-e86b88f88031", + "0194d39e-5d44-77cd-bc5e-1aa6b0a2d8d4" ] }, "theory": "unary-dec", - "type": "model" -} \ No newline at end of file + "type": "model", + "version": "1" +} diff --git a/packages/algjulia-interop/test/test_jsons/models/model_dec_scalar.json b/packages/algjulia-interop/test/data/models/model_dec_scalar.json similarity index 100% rename from packages/algjulia-interop/test/test_jsons/models/model_dec_scalar.json rename to packages/algjulia-interop/test/data/models/model_dec_scalar.json diff --git a/packages/algjulia-interop/test/runtests.jl b/packages/algjulia-interop/test/runtests.jl index 4688b379c..16f14886f 100644 --- a/packages/algjulia-interop/test/runtests.jl +++ b/packages/algjulia-interop/test/runtests.jl @@ -1,239 +1,10 @@ using Test -# -using CatColabInterop -using ACSets -using CombinatorialSpaces -using Decapodes -using DiagrammaticEquations -# -using MLStyle -using JSON3 -using ComponentArrays -using StaticArrays -using LinearAlgebra -import OrdinaryDiffEq: ReturnCode -const KEYS = Set([:mesh, :plotVariables, :initialConditions, :domain, :diagram, :model, :scalars, :duration]) +# @testset "Catlab" begin +# include("TestCatlab.jl") +# end -@testset "Text-to-Pode" begin - @test to_model(ThDecapode(), ObTag(), "0-form") == :Form0 - @test to_model(ThDecapode(), ObTag(), "1-form") == :Form1 - @test to_model(ThDecapode(), ObTag(), "2-form") == :Form2 - @test to_model(ThDecapode(), ObTag(), "dual 0-form") == :DualForm0 - @test to_model(ThDecapode(), ObTag(), "dual 1-form") == :DualForm1 - @test to_model(ThDecapode(), ObTag(), "dual 2-form") == :DualForm2 - @test_throws CatColabInterop.ImplError to_model(ThDecapode(), ObTag(), "Form3") - @test to_model(ThDecapode(), HomTag(), "∂t") == :∂ₜ - @test to_model(ThDecapode(), HomTag(), "Δ") == :Δ - @test_throws CatColabInterop.ImplError to_model(ThDecapode(), HomTag(), "∧") -end - -modeljson = open(JSON3.read, joinpath(@__DIR__, "test_jsons", "models", "model_dec.json"), "r") -model_dec = Model(ThDecapode(), modeljson) -@testset "Validating the JSON object" begin - # validate the JSON - @test keys(modeljson) == Set([:name, :notebook, :theory, :type]) - cells = modeljson[:notebook][:cells] - @test @match cells[1] begin - IsObject(_) => true - _ => false - end - @test @match cells[5] begin - IsMorphism(_) => true - _ => false - end - model = Model(ThDecapode()) - @match cells[1] begin - IsObject(content) => add_to_model!(model, content, ObTag()) - _ => nothing - end -end -@testset "Validate model" begin - # caveat: \star and \bigstar are different, but indistinguishable in some fonts - @test Set(nameof.(values(model_dec))) == Set([:DualForm1, :⋆₀⁻¹, :dual_d₁, :dpsw, :Form1, :neg, :⋆₁, :DualForm2, :Form0, :Δ⁻¹, :♭♯, :∂ₜ, :d₀]) -end - -# ## load diagram -diagram_json = open(JSON3.read, joinpath(@__DIR__, "test_jsons", "diagrams", "inverse_laplacian", "diagram.json"), "r") -diagram = Diagram(diagram_json[:notebook], model_dec) -@testset "Diagram - Inverse Laplacian" begin - handcrafted_pode = SummationDecapode(parse_decapode(quote end)) - add_part!(handcrafted_pode, :Var, name=:A, type=:Form0) - add_part!(handcrafted_pode, :Var, name=:B, type=:Form0) - add_part!(handcrafted_pode, :Op1, src=1, tgt=2, op1=:Δ⁻¹) - @test diagram.pode == handcrafted_pode -end - -# TODO not specifying initial boundary conditions for `B` on the front-end -# means that it will be automatically specified -@testset "Analysis - Inverse Laplacian" begin - analysis_json = open(JSON3.read, joinpath(@__DIR__, "test_jsons", "diagrams", "inverse_laplacian", "analysis.json"), "r") - system = Analysis(analysis_json, diagram) - simulator = evalsim(system.pode) - f = simulator(system.geometry.dualmesh, system.generate, DiagonalHodge()) - soln = run_sim(f, system.init, 50.0, ComponentArray(k=0.5,)) - @test soln.retcode == ReturnCode.Success - result = SimResult(soln, system) - @test typeof(result.state) == Dict{String, Vector{AbstractArray{SVector{3, Float64}}}} - jv = JsonValue(result) -end - -# ## load diagram -diagram_json = open(JSON3.read, joinpath(@__DIR__, "test_jsons", "diagrams", "inverse_laplacian_longtrip", "diagram.json"), "r") -diagram = Diagram(diagram_json[:notebook], model_dec) -infer_types!(diagram.pode) -@testset "Diagram - Inverse Laplacian - Longtrip" begin - handcrafted_pode = SummationDecapode(parse_decapode(quote end)) - add_part!(handcrafted_pode, :Var, name=:u, type=:Form0) - add_part!(handcrafted_pode, :Var, name=:Δu, type=:Form0) - add_part!(handcrafted_pode, :Var, name=Symbol("•1"), type=:Form1) - add_part!(handcrafted_pode, :Var, name=Symbol("•2"), type=:DualForm1) - add_part!(handcrafted_pode, :Var, name=Symbol("•3"), type=:DualForm2) - add_part!(handcrafted_pode, :Op1, src=1, tgt=3, op1=:d₀) - add_part!(handcrafted_pode, :Op1, src=3, tgt=4, op1=:⋆₁) - add_part!(handcrafted_pode, :Op1, src=4, tgt=5, op1=:dual_d₁) - add_part!(handcrafted_pode, :Op1, src=5, tgt=2, op1=:⋆₀⁻¹) - add_part!(handcrafted_pode, :Op1, src=1, tgt=2, op1=:Δ⁻¹) - @test diagram.pode == handcrafted_pode -end -# TODO not specifying initial boundary conditions for `B` on the front-end means that it will be automatically specified -@testset "Analysis - Inverse Laplacian - Longtrip" begin - analysis_json = open(JSON3.read, joinpath(@__DIR__, "test_jsons", "diagrams", "inverse_laplacian_longtrip", "analysis.json"), "r") - system = Analysis(analysis_json, diagram) - simulator = evalsim(system.pode) - f = simulator(system.geometry.dualmesh, system.generate, DiagonalHodge()) - soln = run_sim(f, system.init, 50.0, ComponentArray(k=0.5,)) - @test soln.retcode == ReturnCode.Success - result = SimResult(soln, system) - @test typeof(result.state) == Dict{String, Vector{AbstractArray{SVector{3, Float64}}}} - jv = JsonValue(result) -end - -# ## load diagram -diagram_json = open(JSON3.read, joinpath(@__DIR__, "test_jsons", "diagrams", "ns_vort", "diagram.json"), "r") -diagram = Diagram(diagram_json[:notebook], model_dec) -infer_types!(diagram.pode) -@testset "Diagram - NS Vorticity" begin - # construct a decapode - handcrafted_pode = SummationDecapode(parse_decapode(quote end)) - add_part!(handcrafted_pode, :Var, name=:v, type=:DualForm1) - add_part!(handcrafted_pode, :Var, name=:dv, type=:DualForm2) - add_part!(handcrafted_pode, :Var, name=:ψ, type=:Form0) - # infer - add_part!(handcrafted_pode, :Var, name=Symbol("•1"), type=:Form0) - add_part!(handcrafted_pode, :Var, name=Symbol("•2"), type=:Form1) - add_part!(handcrafted_pode, :Var, name=Symbol("•3"), type=:infer) - add_part!(handcrafted_pode, :Var, name=Symbol("•4"), type=:infer) - add_part!(handcrafted_pode, :Var, name=Symbol("•5"), type=:infer) - add_part!(handcrafted_pode, :Var, name=Symbol("•6"), type=:infer) - add_part!(handcrafted_pode, :Var, name=Symbol("•7"), type=:infer) - # tvar - add_part!(handcrafted_pode, :TVar, incl=9) - # op1 - add_part!(handcrafted_pode, :Op1, src=2, tgt=4, op1=:⋆₀⁻¹) - add_part!(handcrafted_pode, :Op1, src=3, tgt=5, op1=:d₀) - add_part!(handcrafted_pode, :Op1, src=5, tgt=1, op1=:⋆₁) - add_part!(handcrafted_pode, :Op1, src=1, tgt=6, op1=:dpsw) # TODO breaks infer_types - add_part!(handcrafted_pode, :Op1, src=6, tgt=7, op1=:♭♯) - add_part!(handcrafted_pode, :Op1, src=7, tgt=8, op1=:⋆₁) - add_part!(handcrafted_pode, :Op1, src=2, tgt=9, op1=:∂ₜ) - add_part!(handcrafted_pode, :Op1, src=8, tgt=10, op1=:dual_d₁) - add_part!(handcrafted_pode, :Op1, src=10, tgt=9, op1=:neg) - infer_types!(handcrafted_pode) - @test diagram.pode == handcrafted_pode -end -# TODO not specifying initial boundary conditions for `B` on the front-end -# means that it will be automatically specified -@testset "Analysis - Navier-Stokes Vorticity" begin - analysis_json = open(JSON3.read, joinpath(@__DIR__, "test_jsons", "diagrams", "ns_vort", "analysis.json"), "r") - system = Analysis(analysis_json, diagram) - simulator = evalsim(system.pode) - f = simulator(system.geometry.dualmesh, system.generate, DiagonalHodge()) - soln = run_sim(f, system.init, system.duration, ComponentArray(k=0.5,)) - @test soln.retcode == ReturnCode.Success - result = SimResult(soln, system) - @test typeof(result.state) == Dict{String, Vector{AbstractArray{SVector{3, Float64}}}} - jv = JsonValue(result) -end - -## load diagram -modeljson = open(JSON3.read, joinpath(@__DIR__, "test_jsons", "models", "model_dec_scalar.json"), "r") -model_dec_scalar = Model(ThDecapode(), modeljson) -diagram_json = open(JSON3.read, joinpath(@__DIR__, "test_jsons", "diagrams", "diffusivity_constant", "diagram.json"), "r") -diagram = Diagram(diagram_json[:notebook], model_dec_scalar) -infer_types!(diagram.pode) -@testset "Diagram - Diffusivity Constant" begin - # construct a decapode - handcrafted_pode = SummationDecapode(parse_decapode(quote end)) - add_part!(handcrafted_pode, :Var, name=:u, type=:DualForm2) - add_part!(handcrafted_pode, :Var, name=Symbol("du/dt"), type=:DualForm2) - add_part!(handcrafted_pode, :Var, name=Symbol("•1"), type=:Form0) - add_part!(handcrafted_pode, :Var, name=Symbol("•2"), type=:Form1) - add_part!(handcrafted_pode, :Var, name=Symbol("•3"), type=:DualForm1) - add_part!(handcrafted_pode, :Var, name=Symbol("•4"), type=:DualForm2) - add_part!(handcrafted_pode, :TVar, incl=2) - add_part!(handcrafted_pode, :Op1, src=1, tgt=3, op1=:⋆₀⁻¹) - add_part!(handcrafted_pode, :Op1, src=3, tgt=4, op1=:d₀) - add_part!(handcrafted_pode, :Op1, src=4, tgt=5, op1=:⋆₁) - add_part!(handcrafted_pode, :Op1, src=5, tgt=6, op1=:dual_d₁) - add_part!(handcrafted_pode, :Op1, src=6, tgt=2, op1=:any_scalar) - add_part!(handcrafted_pode, :Op1, src=1, tgt=2, op1=:∂ₜ) - @test diagram.pode == handcrafted_pode -end -# TODO not specifying initial boundary conditions for `B` on the front-end -# means that it will be automatically specified -@testset "Analysis - Diffusivity Constant" begin - analysis_json = open(JSON3.read, joinpath(@__DIR__, "test_jsons", "diagrams", "diffusivity_constant", "analysis.json"), "r") - system = Analysis(analysis_json, diagram) - simulator = evalsim(system.pode) - f = simulator(system.geometry.dualmesh, system.generate, DiagonalHodge()) - soln = run_sim(f, system.init, system.duration, ComponentArray(k=0.5,)) - @test soln.retcode == ReturnCode.Success - result = SimResult(soln, system) - @test typeof(result.state) == Dict{String, Vector{AbstractArray{SVector{3, Float64}}}} - jv = JsonValue(result) -end - - -# Payload -payloadjson = open(JSON3.read, joinpath(@__DIR__, "test_jsons", "payload.json")) -model = Model(ThDecapode(), payloadjson.model) -diagram = Diagram(payloadjson.diagram, model) -infer_types!(diagram.pode) -# TODO need to verify -@testset "(Payload) Diagram - Diffusivity Constant" begin - # construct a decapode - handcrafted_pode = SummationDecapode(parse_decapode(quote end)) - add_part!(handcrafted_pode, :Var, name=Symbol("dv/dt"), type=:DualForm2) - add_part!(handcrafted_pode, :Var, name=Symbol("•1"), type=:Form0) - add_part!(handcrafted_pode, :Var, name=Symbol("•2"), type=:Form1) - add_part!(handcrafted_pode, :Var, name=Symbol("•3"), type=:DualForm1) - add_part!(handcrafted_pode, :Var, name=Symbol("•4"), type=:DualForm2) - add_part!(handcrafted_pode, :Var, name=:v, type=:DualForm2) - add_part!(handcrafted_pode, :TVar, incl=1) - add_part!(handcrafted_pode, :Op1, src=6, tgt=2, op1=:⋆₀⁻¹) - add_part!(handcrafted_pode, :Op1, src=3, tgt=4, op1=:⋆₁) - add_part!(handcrafted_pode, :Op1, src=5, tgt=1, op1=:any_scalar) - add_part!(handcrafted_pode, :Op1, src=6, tgt=1, op1=:∂ₜ) - add_part!(handcrafted_pode, :Op1, src=4, tgt=5, op1=:dual_d₁) - add_part!(handcrafted_pode, :Op1, src=2, tgt=3, op1=:d₀) - @test diagram.pode == handcrafted_pode -end -# TODO not specifying initial boundary conditions for `B` on the front-end -# means that it will be automatically specified -@testset "Analysis - Diffusivity Constant" begin - system = Analysis(ThDecapode(), payloadjson) - simulator = evalsim(system.pode) - # DEBUGGING SNIPPET: - # path = joinpath(@__DIR__, "testsim.jl") - # open(path, "w") do f - # write(f, string(gensim(system.pode))) - # end - # simulator = include(path) - f = simulator(system.geometry.dualmesh, system.generate, DiagonalHodge()) - soln = run_sim(f, system.init, system.duration, ComponentArray(k=0.5,)) - @test soln.retcode == ReturnCode.Success - result = SimResult(soln, system) - @test typeof(result.state) == Dict{String, Vector{AbstractArray{SVector{3, Float64}}}} - jv = JsonValue(result) +@testset "Decapodes" begin + include("test_decapodes/model_verification.jl") + include("test_decapodes/simulation.jl") end diff --git a/packages/algjulia-interop/test/test_decapodes/TestDecapodes.jl b/packages/algjulia-interop/test/test_decapodes/TestDecapodes.jl new file mode 100644 index 000000000..a841ac9c2 --- /dev/null +++ b/packages/algjulia-interop/test/test_decapodes/TestDecapodes.jl @@ -0,0 +1,10 @@ +module TestDecapodes + +using CatColabInterop +using Test + +const DecapodesExt = @ext DecapodesExt("../Project.toml") + +include("simulation.jl") + +end diff --git a/packages/algjulia-interop/test/test_decapodes/model_verification.jl b/packages/algjulia-interop/test/test_decapodes/model_verification.jl new file mode 100644 index 000000000..cd1250b77 --- /dev/null +++ b/packages/algjulia-interop/test/test_decapodes/model_verification.jl @@ -0,0 +1,88 @@ +const KEYS = Set([:mesh, :plotVariables, :initialConditions, :domain, :diagram, :model, :scalars, :duration]) + +# @testset "Text-to-Pode" begin +# @test ob_name(ThDecapode(), "0-form") == :Form0 +# @test ob_name(ThDecapode(), "1-form") == :Form1 +# @test ob_name(ThDecapode(), "2-form") == :Form2 +# @test ob_name(ThDecapode(), "dual 0-form") == :DualForm0 +# @test ob_name(ThDecapode(), "dual 1-form") == :DualForm1 +# @test ob_name(ThDecapode(), "dual 2-form") == :DualForm2 +# @test_throws CatColabInterop.ImplError ob_name(ThDecapode(), "Form3") +# @test mor_name(ThDecapode(), "∂t") == :∂ₜ +# @test mor_name(ThDecapode(), "Δ") == :Δ +# @test_throws CatColabInterop.ImplError mor_name(ThDecapode(), "∧") +# end + +@testset "Validate model" begin + + # Let's grab a model from one of our examples + payload = JSON3.read(read("data/diagrams/inverse_laplacian_longtrip/analysis.json", String), Analysis) + + # The types available to objects and morphisms in this model. + @test Set(nameof.(payload.model.obGenerators)) == Set(["0-form", "Primal 1-form", "Dual 1-form", "Dual 2-form"]) + @test Set(nameof.(payload.model.morGenerators)) == Set([:⋆₀⁻¹, :Δ⁻¹, :d₀, :⋆₁, :dpsw, :♭♯, :dual_d₁, :∂ₜ, :neg]) + +end + +@testset "Analysis - Inverse Laplacian" begin + handcrafted_pode = SummationDecapode(parse_decapode(quote end)) + add_part!(handcrafted_pode, :Var, name=:u, type=:Form0) + add_part!(handcrafted_pode, :Var, name=Symbol("du/dt"), type=:Form0) + add_part!(handcrafted_pode, :Op1, src=1, tgt=2, op1=:Δ⁻¹) + simulation = DecapodesExt.DecapodeSimulation("data/diagrams/inverse_laplacian_longtrip/analysis.json") + @test simulation.pode == handcrafted_pode +end + +@testset "Analysis - Inverse Laplacian, Long trip" begin + handcrafted_pode = SummationDecapode(parse_decapode(quote end)) + add_part!(handcrafted_pode, :Var, name=:u, type=:DualForm2) + add_part!(handcrafted_pode, :Var, name=:u̇, type=:DualForm2) + add_part!(handcrafted_pode, :Var, name=Symbol("•1"), type=:Form0) + add_part!(handcrafted_pode, :Var, name=Symbol("•2"), type=:Form1) + add_part!(handcrafted_pode, :Var, name=Symbol("•3"), type=:DualForm1) + add_part!(handcrafted_pode, :TVar, incl=2) + add_part!(handcrafted_pode, :Op1, src=1, tgt=2, op1=:∂ₜ) + add_part!(handcrafted_pode, :Op1, src=1, tgt=3, op1=:⋆₀⁻¹) + add_part!(handcrafted_pode, :Op1, src=3, tgt=4, op1=:d₀) + add_part!(handcrafted_pode, :Op1, src=4, tgt=5, op1=:⋆₁) + add_part!(handcrafted_pode, :Op1, src=5, tgt=2, op1=:dual_d₁) + # + simulation = DecapodeSimulation(read("data/diagrams/inverse_laplacian_longtrip/analysis.json", String)) + @test simulation.pode == handcrafted_pode +end + +@testset "Analysis - Laplacian, Scalar" begin end + +#= Vorticity =# +@testset "Analysis - NS Vorticity" begin + + handcrafted_pode = SummationDecapode(parse_decapode(quote end)) + add_part!(handcrafted_pode, :Var, name=:v, type=:DualForm1) + add_part!(handcrafted_pode, :Var, name=:dv, type=:DualForm2) + add_part!(handcrafted_pode, :Var, name=:ψ, type=:Form0) + # infer + add_part!(handcrafted_pode, :Var, name=Symbol("•1"), type=:Form0) + add_part!(handcrafted_pode, :Var, name=Symbol("•2"), type=:Form1) + add_part!(handcrafted_pode, :Var, name=Symbol("•3"), type=:infer) + add_part!(handcrafted_pode, :Var, name=Symbol("•4"), type=:infer) + add_part!(handcrafted_pode, :Var, name=Symbol("•5"), type=:infer) + add_part!(handcrafted_pode, :Var, name=Symbol("•6"), type=:infer) + add_part!(handcrafted_pode, :Var, name=Symbol("•7"), type=:infer) + # tvar + add_part!(handcrafted_pode, :TVar, incl=9) + # op1 + add_part!(handcrafted_pode, :Op1, src=2, tgt=4, op1=:⋆₀⁻¹) + add_part!(handcrafted_pode, :Op1, src=3, tgt=5, op1=:d₀) # simulation has this wrong + add_part!(handcrafted_pode, :Op1, src=5, tgt=1, op1=:⋆₁) + add_part!(handcrafted_pode, :Op1, src=1, tgt=6, op1=:dpsw) # TODO breaks infer_types + add_part!(handcrafted_pode, :Op1, src=6, tgt=7, op1=:♭♯) + add_part!(handcrafted_pode, :Op1, src=7, tgt=8, op1=:⋆₁) + add_part!(handcrafted_pode, :Op1, src=2, tgt=9, op1=:∂ₜ) + add_part!(handcrafted_pode, :Op1, src=8, tgt=10, op1=:dual_d₁) + add_part!(handcrafted_pode, :Op1, src=10, tgt=9, op1=:neg) + infer_types!(handcrafted_pode) + + simulation = DecapodeSimulation(read("data/diagrams/ns_vort/analysis.json", String)) + @test_broken simulation.pode == handcrafted_pode + +end diff --git a/packages/algjulia-interop/test/test_decapodes/simulation.jl b/packages/algjulia-interop/test/test_decapodes/simulation.jl new file mode 100644 index 000000000..3fa2b6fee --- /dev/null +++ b/packages/algjulia-interop/test/test_decapodes/simulation.jl @@ -0,0 +1,29 @@ +const KEYS = Set([:mesh, :plotVariables, :initialConditions, :domain, :diagram, :model, :scalars, :duration]) + +@testset "Simulation - ..." begin + simulation = DecapodesExt.DecapodeSimulation((@__DIR__)*"/data/diagrams/diffusivity_constant/diagram.json") + sim = DecapodesExt.evalsim(simulation.pode) + f = sim(simulation.geometry.dualmesh, simulation.generate, DiagonalHodge()) + result = run(f, simulation, ComponentArray(k=0.5,)) + @test result.retcode == ReturnCode.Success +end + +@testset "Simulation - Inverse Laplacian Longtrip" begin + simulation = DecapodeSimulation(@__DIR__ * "data/inverse_laplacian_longtrip/diagram_analysis.json") + sim = evalsim(simulation.pode) + f = sim(simulation.geometry.dualmesh, simulation.generate, DiagonalHodge()) + result = run(f, simulation, ComponentArray(k=0.5,)) + @test result.retcode == ReturnCode.Success +end + +# TODO not specifying initial boundary conditions for `B` on the front-end +# means that it will be automatically specified +# @testset "Simulation - Navier-Stokes Vorticity" begin +# payload = read("data/diagrams/ns_vort/analysis.json", String) +# simulation = DecapodeSimulation(payload) +# sim = evalsim(simulation.pode) +# f = sim(simulation.geometry.dualmesh, simulation.generate, DiagonalHodge()) +# result = run(f, simulation, ComponentArray(k=0.5,)) +# @test result.retcode == ReturnCode.Success +# @test typeof(result.state) == Dict{String, Vector{AbstractArray{SVector{3, Float64}}}} +# end diff --git a/packages/algjulia-interop/test/test_jsons/diagrams/diffusivity_constant/analysis.json b/packages/algjulia-interop/test/test_jsons/diagrams/diffusivity_constant/analysis.json deleted file mode 100644 index 5f986cf67..000000000 --- a/packages/algjulia-interop/test/test_jsons/diagrams/diffusivity_constant/analysis.json +++ /dev/null @@ -1,47 +0,0 @@ -{ - "analysisOf": { - "_id": "0196021c-dee3-75b3-bb79-2f940651a1a1", - "_server": "backend.catcolab.org", - "_version": null, - "type": "analysis-of" - }, - "analysisType": "diagram", - "name": "", - "notebook": { - "cells": [ - { - "content": { - "content": { - "domain": "Plane", - "duration": 10, - "initialConditions": { - "0196021c-f5fe-70f3-ac68-89ae212970ea": "Gaussian", - "0196021d-1aa4-776d-b4fb-05d24d0c6de4": "Gaussian" - }, - "mesh": "Rectangle", - "plotVariables": { - "0196021c-f5fe-70f3-ac68-89ae212970ea": true - }, - "scalars": { - "01960dde-1193-7132-b662-9bf24ed05264": 1 - } - }, - "id": "decapodes" - }, - "id": "0196021f-beef-74b0-9103-9ab1982255cf", - "tag": "formal" - }, - { - "content": { - "content": { - "layout": "graphviz-directed" - }, - "id": "graph" - }, - "id": "01960ddd-8fc3-7482-a2c8-a0a59ee85709", - "tag": "formal" - } - ] - }, - "type": "analysis" -} diff --git a/packages/algjulia-interop/test/test_jsons/diagrams/diffusivity_constant/diagram.json b/packages/algjulia-interop/test/test_jsons/diagrams/diffusivity_constant/diagram.json deleted file mode 100644 index 53d93e9fb..000000000 --- a/packages/algjulia-interop/test/test_jsons/diagrams/diffusivity_constant/diagram.json +++ /dev/null @@ -1,201 +0,0 @@ -{ - "diagramIn": { - "_id": "0196021c-d1ff-75b1-9f38-bdecdb7680d2", - "_server": "backend.catcolab.org", - "_version": null, - "type": "diagram-in" - }, - "name": "", - "notebook": { - "cells": [ - { - "content": { - "id": "0196021c-f5fe-70f3-ac68-89ae212970ea", - "name": "u", - "obType": { - "content": "Object", - "tag": "Basic" - }, - "over": { - "content": "0194d398-d0cb-7308-b7e0-eace5b21af24", - "tag": "Basic" - }, - "tag": "object" - }, - "id": "0196021c-f5fe-70f3-ac68-8f4da8bb79be", - "tag": "formal" - }, - { - "content": { - "id": "0196021d-1aa4-776d-b4fb-05d24d0c6de4", - "name": "du/dt", - "obType": { - "content": "Object", - "tag": "Basic" - }, - "over": { - "content": "0194d398-d0cb-7308-b7e0-eace5b21af24", - "tag": "Basic" - }, - "tag": "object" - }, - "id": "0196021d-1aa4-776d-b4fb-098aea19edd5", - "tag": "formal" - }, - { - "content": { - "cod": { - "content": "0196021e-9635-74de-845a-cee56d3e5cc5", - "tag": "Basic" - }, - "dom": { - "content": "0196021c-f5fe-70f3-ac68-89ae212970ea", - "tag": "Basic" - }, - "id": "0196021e-848d-704c-a45c-a325b63951e6", - "morType": { - "content": "Nonscalar", - "tag": "Basic" - }, - "name": "", - "over": { - "content": "0194d399-34f3-773c-91b9-857da9c4311f", - "tag": "Basic" - }, - "tag": "morphism" - }, - "id": "0196021e-848d-704c-a45c-a6b09dac0136", - "tag": "formal" - }, - { - "content": { - "cod": { - "content": "0196021e-e55e-764e-85c8-827f94d7f3bd", - "tag": "Basic" - }, - "dom": { - "content": "0196021e-9635-74de-845a-cee56d3e5cc5", - "tag": "Basic" - }, - "id": "0196021e-c8a6-74df-8194-3ec769ba3d1d", - "morType": { - "content": "Nonscalar", - "tag": "Basic" - }, - "name": "", - "over": { - "content": "0194d39a-6084-7537-aec1-caf560ba416b", - "tag": "Basic" - }, - "tag": "morphism" - }, - "id": "0196021e-c8a6-74df-8194-40ee060a7684", - "tag": "formal" - }, - { - "content": { - "cod": { - "content": "0196021f-0a11-7443-b5da-31175c628e3c", - "tag": "Basic" - }, - "dom": { - "content": "0196021e-e55e-764e-85c8-827f94d7f3bd", - "tag": "Basic" - }, - "id": "0196021e-ecf9-7408-b881-d981c4e85222", - "morType": { - "content": "Nonscalar", - "tag": "Basic" - }, - "name": "", - "over": { - "content": "0194d39a-ed25-710f-b53f-89541021281f", - "tag": "Basic" - }, - "tag": "morphism" - }, - "id": "0196021e-ecf9-7408-b881-ddb32ac3d85e", - "tag": "formal" - }, - { - "content": { - "cod": { - "content": "0196021f-4c93-70dc-8e61-24459f79f837", - "tag": "Basic" - }, - "dom": { - "content": "0196021f-0a11-7443-b5da-31175c628e3c", - "tag": "Basic" - }, - "id": "0196021f-1ba8-77a5-a635-8b3ca32ae99c", - "morType": { - "content": "Nonscalar", - "tag": "Basic" - }, - "name": "", - "over": { - "content": "0194d39d-d297-77a9-95a2-6ed7105fdca3", - "tag": "Basic" - }, - "tag": "morphism" - }, - "id": "0196021f-1ba8-77a5-a635-8f6c9f8b2c4c", - "tag": "formal" - }, - { - "content": { - "cod": { - "content": "0196021d-1aa4-776d-b4fb-05d24d0c6de4", - "tag": "Basic" - }, - "dom": { - "content": "0196021f-4c93-70dc-8e61-24459f79f837", - "tag": "Basic" - }, - "id": "0196021f-6b45-751e-8313-df1024cd9fa0", - "morType": { - "content": { - "content": "Object", - "tag": "Basic" - }, - "tag": "Hom" - }, - "name": "", - "over": { - "content": "01960dde-1193-7132-b662-9bf24ed05264", - "tag": "Basic" - }, - "tag": "morphism" - }, - "id": "0196021f-6b46-73b4-8b8a-1417d000ecfd", - "tag": "formal" - }, - { - "content": { - "cod": { - "content": "0196021d-1aa4-776d-b4fb-05d24d0c6de4", - "tag": "Basic" - }, - "dom": { - "content": "0196021c-f5fe-70f3-ac68-89ae212970ea", - "tag": "Basic" - }, - "id": "01960df4-b95f-7660-90b6-aaf1dc940a15", - "morType": { - "content": "Nonscalar", - "tag": "Basic" - }, - "name": "", - "over": { - "content": "0194d39c-622d-7599-bc5c-e7e8208d6cdd", - "tag": "Basic" - }, - "tag": "morphism" - }, - "id": "01960df4-b95f-7660-90b6-ae21afb022aa", - "tag": "formal" - } - ] - }, - "type": "diagram" -} diff --git a/packages/algjulia-interop/test/test_jsons/diagrams/inverse_laplacian/analysis.json b/packages/algjulia-interop/test/test_jsons/diagrams/inverse_laplacian/analysis.json deleted file mode 100644 index bcc7c72b3..000000000 --- a/packages/algjulia-interop/test/test_jsons/diagrams/inverse_laplacian/analysis.json +++ /dev/null @@ -1,54 +0,0 @@ -{ - "analysisOf": { - "_id": "0195c95c-b3eb-7142-8b38-b7287cf2c76f", - "_server": "backend.catcolab.org", - "_version": null, - "type": "analysis-of" - }, - "analysisType": "diagram", - "name": "", - "notebook": { - "cells": [ - { - "content": { - "content": { - "domain": "Sphere", - "duration": 1, - "initialConditions": { - "0195c95c-c200-73a0-bf58-1cc188ecd0c4": "TaylorVortex", - "0195c95c-d4b4-779b-ae65-a89269f63b43": "TaylorVortex" - }, - "mesh": "Icosphere6", - "plotVariables": { - "0195c95c-c200-73a0-bf58-1cc188ecd0c4": true, - "0195c95c-d4b4-779b-ae65-a89269f63b43": false - }, - "scalars": {} - }, - "id": "decapodes" - }, - "id": "0195c95d-3b6b-71cb-8bd2-9fbc90fc609f", - "tag": "formal" - }, - { - "id": "0195ca0d-166a-7179-87d8-b5cf9dd9eaf1", - "tag": "stem" - }, - { - "content": { - "content": { - "layout": "graphviz-directed" - }, - "id": "graph" - }, - "id": "0195ca0d-b210-72c5-a091-3e57ced85ed5", - "tag": "formal" - }, - { - "id": "0195dddf-faaa-76ea-a966-ba4b9be5b36e", - "tag": "stem" - } - ] - }, - "type": "analysis" -} diff --git a/packages/algjulia-interop/test/test_jsons/diagrams/inverse_laplacian/diagram.json b/packages/algjulia-interop/test/test_jsons/diagrams/inverse_laplacian/diagram.json deleted file mode 100644 index a0c3ae2c0..000000000 --- a/packages/algjulia-interop/test/test_jsons/diagrams/inverse_laplacian/diagram.json +++ /dev/null @@ -1,73 +0,0 @@ -{ - "diagramIn": { - "_id": "0195c95c-9917-7402-82b9-1b6c735258b7", - "_server": "backend.catcolab.org", - "_version": null, - "type": "diagram-in" - }, - "name": "", - "notebook": { - "cells": [ - { - "content": { - "id": "0195c95c-c200-73a0-bf58-1cc188ecd0c4", - "name": "A", - "obType": { - "content": "Object", - "tag": "Basic" - }, - "over": { - "content": "0194d398-a28e-7433-89f8-563bae6e6875", - "tag": "Basic" - }, - "tag": "object" - }, - "id": "0195c95c-c200-73a0-bf58-22914f83428d", - "tag": "formal" - }, - { - "content": { - "id": "0195c95c-d4b4-779b-ae65-a89269f63b43", - "name": "B", - "obType": { - "content": "Object", - "tag": "Basic" - }, - "over": { - "content": "0194d398-a28e-7433-89f8-563bae6e6875", - "tag": "Basic" - }, - "tag": "object" - }, - "id": "0195c95c-d4b4-779b-ae65-ad0a7af96410", - "tag": "formal" - }, - { - "content": { - "cod": { - "content": "0195c95c-d4b4-779b-ae65-a89269f63b43", - "tag": "Basic" - }, - "dom": { - "content": "0195c95c-c200-73a0-bf58-1cc188ecd0c4", - "tag": "Basic" - }, - "id": "0195dde5-27aa-72fa-9cde-ff6571346ca7", - "morType": { - "content": "Nonscalar", - "tag": "Basic" - }, - "name": "", - "over": { - "content": "0194d399-b2a2-73ff-aece-cb0f26644045", - "tag": "Basic" - }, - "tag": "morphism" - }, - "id": "0195dde5-27aa-72fa-9cdf-0313e512eb41", - "tag": "formal" - } - ] - }, - "type": "diagram" -} diff --git a/packages/algjulia-interop/test/test_jsons/diagrams/inverse_laplacian_longtrip/analysis.json b/packages/algjulia-interop/test/test_jsons/diagrams/inverse_laplacian_longtrip/analysis.json deleted file mode 100644 index f42780bee..000000000 --- a/packages/algjulia-interop/test/test_jsons/diagrams/inverse_laplacian_longtrip/analysis.json +++ /dev/null @@ -1 +0,0 @@ -{"analysisOf":{"_id":"0195ecdc-cf21-7091-94a3-7644d5103743","_server":"backend.catcolab.org","_version":null,"type":"analysis-of"},"analysisType":"diagram","name":"","notebook":{"cells":[{"id":"0195ed44-aa9e-730d-807d-57cf94417236","tag":"stem"},{"content":{"content":{"domain":"Plane","duration":10,"initialConditions":{"0195ecdc-d7e1-768a-8862-76a47f2f4e06":"Gaussian","0195ecdc-f625-71c8-a044-a6ce2fb3dd31":"Gaussian"},"mesh":"Rectangle","plotVariables":{"0195ecdc-d7e1-768a-8862-76a47f2f4e06":true},"scalars":{}},"id":"decapodes"},"id":"0195ed44-c260-755f-9c1f-80c13253e575","tag":"formal"}]},"type":"analysis"} diff --git a/packages/algjulia-interop/test/test_jsons/diagrams/ns_vort/analysis.json b/packages/algjulia-interop/test/test_jsons/diagrams/ns_vort/analysis.json deleted file mode 100644 index 8838d4941..000000000 --- a/packages/algjulia-interop/test/test_jsons/diagrams/ns_vort/analysis.json +++ /dev/null @@ -1 +0,0 @@ -{"analysisOf":{"_id":"0195ecc4-4c4d-70e2-bee7-18221e6c42e7","_server":"backend.catcolab.org","_version":null,"type":"analysis-of"},"analysisType":"diagram","name":"","notebook":{"cells":[{"content":{"content":{"domain":"Sphere","duration":1,"initialConditions":{"0195ecc5-9eaf-71dd-a9c8-621d888e2add":"TaylorVortex","0195ecc5-b1b0-746e-8a04-ebd359da2bfd":"TaylorVortex","0195ecc5-d39a-72bf-8cd3-236d5211e122":"TaylorVortex"},"mesh":"Icosphere6","plotVariables":{"0195ecc5-9eaf-71dd-a9c8-621d888e2add":true},"scalars":{}},"id":"decapodes"},"id":"0195ecca-f11e-74c8-8fa4-fb8b03a93274","tag":"formal"}]},"type":"analysis"} diff --git a/packages/algjulia-interop/test/test_jsons/diagrams/ns_vort/diagram.json b/packages/algjulia-interop/test/test_jsons/diagrams/ns_vort/diagram.json deleted file mode 100644 index 4e0f694ed..000000000 --- a/packages/algjulia-interop/test/test_jsons/diagrams/ns_vort/diagram.json +++ /dev/null @@ -1 +0,0 @@ -{"diagramIn":{"_id":"0195ecc4-309b-7742-b7d7-35f8ba9021f9","_server":"backend.catcolab.org","_version":null,"type":"diagram-in"},"name":"","notebook":{"cells":[{"content":{"id":"0195ecc5-9eaf-71dd-a9c8-621d888e2add","name":"v","obType":{"content":"Object","tag":"Basic"},"over":{"content":"0194d398-b3ef-728d-bd88-60b48fd7349a","tag":"Basic"},"tag":"object"},"id":"0195ecc5-9eb0-70f9-b2c0-36f0f3d4cd28","tag":"formal"},{"content":{"id":"0195ecc5-b1b0-746e-8a04-ebd359da2bfd","name":"dv","obType":{"content":"Object","tag":"Basic"},"over":{"content":"0194d398-d0cb-7308-b7e0-eace5b21af24","tag":"Basic"},"tag":"object"},"id":"0195ecc5-b1b0-746e-8a04-ef250a7afe00","tag":"formal"},{"content":{"id":"0195ecc5-d39a-72bf-8cd3-236d5211e122","name":"ψ","obType":{"content":"Object","tag":"Basic"},"over":{"content":"0194d398-a28e-7433-89f8-563bae6e6875","tag":"Basic"},"tag":"object"},"id":"0195ecc5-d39a-72bf-8cd3-26a9e71b49bf","tag":"formal"},{"content":{"cod":{"content":"0195ecc6-f2ab-719c-844b-b8413517e269","tag":"Basic"},"dom":{"content":"0195ecc5-b1b0-746e-8a04-ebd359da2bfd","tag":"Basic"},"id":"0195ecc6-ce3f-7607-bce9-cb3fa3ddb4a6","morType":{"content":"Nonscalar","tag":"Basic"},"name":"","over":{"content":"0194d399-34f3-773c-91b9-857da9c4311f","tag":"Basic"},"tag":"morphism"},"id":"0195ecc6-ce3f-7607-bce9-cf213389bf95","tag":"formal"},{"content":{"cod":{"content":"0195ecc7-388f-72c0-a4f1-3b89ed8aa6e0","tag":"Basic"},"dom":{"content":"0195ecc5-d39a-72bf-8cd3-236d5211e122","tag":"Basic"},"id":"0195ecc7-10a4-755e-8cc7-a3900d37dc93","morType":{"content":"Nonscalar","tag":"Basic"},"name":"","over":{"content":"0194d39a-6084-7537-aec1-caf560ba416b","tag":"Basic"},"tag":"morphism"},"id":"0195ecc7-10a4-755e-8cc7-a45b6cbd1cb8","tag":"formal"},{"content":{"cod":{"content":"0195ecc5-9eaf-71dd-a9c8-621d888e2add","tag":"Basic"},"dom":{"content":"0195ecc7-388f-72c0-a4f1-3b89ed8aa6e0","tag":"Basic"},"id":"0195ecc7-4faa-751f-951d-4d854f43a59d","morType":{"content":"Nonscalar","tag":"Basic"},"name":"","over":{"content":"0194d39a-ed25-710f-b53f-89541021281f","tag":"Basic"},"tag":"morphism"},"id":"0195ecc7-4faa-751f-951d-50a87eb7eb09","tag":"formal"},{"content":{"cod":{"content":"0195ecc7-8f7f-720e-b1ef-befd8deb0e78","tag":"Basic"},"dom":{"content":"0195ecc5-9eaf-71dd-a9c8-621d888e2add","tag":"Basic"},"id":"0195ecc7-7698-70a8-8847-3b021b1f48fa","morType":{"content":"Nonscalar","tag":"Basic"},"name":"","over":{"content":"0194d39b-587f-7559-a1ff-b6ed58899461","tag":"Basic"},"tag":"morphism"},"id":"0195ecc7-7698-70a8-8847-3d286c36d0e8","tag":"formal"},{"content":{"cod":{"content":"0195ecc7-c18e-7632-990d-33dd4afe1f87","tag":"Basic"},"dom":{"content":"0195ecc7-8f7f-720e-b1ef-befd8deb0e78","tag":"Basic"},"id":"0195ecc7-9a27-77fd-bbe3-320fa00047ed","morType":{"content":"Nonscalar","tag":"Basic"},"name":"","over":{"content":"0194d39b-a70a-77d5-8e89-66f0e767a9da","tag":"Basic"},"tag":"morphism"},"id":"0195ecc7-9a27-77fd-bbe3-36268ee77145","tag":"formal"},{"content":{"cod":{"content":"0195ecc7-f8e6-761b-a52e-3ecbe49ddaa1","tag":"Basic"},"dom":{"content":"0195ecc7-c18e-7632-990d-33dd4afe1f87","tag":"Basic"},"id":"0195ecc7-c925-74fb-9fa4-b172831ead97","morType":{"content":"Nonscalar","tag":"Basic"},"name":"","over":{"content":"0194d39a-ed25-710f-b53f-89541021281f","tag":"Basic"},"tag":"morphism"},"id":"0195ecc7-c925-74fb-9fa4-b74dfa39bba8","tag":"formal"},{"content":{"cod":{"content":"0195ecca-5a2c-71cd-998d-d0f25a79a266","tag":"Basic"},"dom":{"content":"0195ecc5-b1b0-746e-8a04-ebd359da2bfd","tag":"Basic"},"id":"0195ecc9-bcfd-7689-bc42-75a237fe9c2c","morType":{"content":"Nonscalar","tag":"Basic"},"name":"","over":{"content":"0194d39c-622d-7599-bc5c-e7e8208d6cdd","tag":"Basic"},"tag":"morphism"},"id":"0195ecc9-bcfd-7689-bc42-7a6c6e84d4f3","tag":"formal"},{"content":{"cod":{"content":"0195ecca-8dd0-7735-9d74-c73dc1c8eb9e","tag":"Basic"},"dom":{"content":"0195ecc7-f8e6-761b-a52e-3ecbe49ddaa1","tag":"Basic"},"id":"0195ecca-64d2-71e7-9f79-31cb7d8cb95e","morType":{"content":"Nonscalar","tag":"Basic"},"name":"","over":{"content":"0194d39d-d297-77a9-95a2-6ed7105fdca3","tag":"Basic"},"tag":"morphism"},"id":"0195ecca-64d2-71e7-9f79-3708a3062d71","tag":"formal"},{"content":{"cod":{"content":"0195ecca-5a2c-71cd-998d-d0f25a79a266","tag":"Basic"},"dom":{"content":"0195ecca-8dd0-7735-9d74-c73dc1c8eb9e","tag":"Basic"},"id":"0195ecca-98d7-73f7-9297-b8b693434f99","morType":{"content":"Nonscalar","tag":"Basic"},"name":"","over":{"content":"0194d39e-5d44-77cd-bc5e-156c5c56ae85","tag":"Basic"},"tag":"morphism"},"id":"0195ecca-98d7-73f7-9297-be3feb46d9b9","tag":"formal"}]},"type":"diagram"} diff --git a/packages/algjulia-interop/test/test_jsons/diffconst_payload1.json b/packages/algjulia-interop/test/test_jsons/diffconst_payload1.json deleted file mode 100644 index 1a0039420..000000000 --- a/packages/algjulia-interop/test/test_jsons/diffconst_payload1.json +++ /dev/null @@ -1,435 +0,0 @@ -{ - "diagram": [ - { - "tag": "object", - "name": "du/dt", - "id": "0196021d-1aa4-776d-b4fb-05d24d0c6de4", - "obType": { - "tag": "Basic", - "content": "Object" - }, - "over": { - "tag": "Basic", - "content": "0194d398-d0cb-7308-b7e0-eace5b21af24" - } - }, - { - "tag": "object", - "name": "", - "id": "0196021e-9635-74de-845a-cee56d3e5cc5", - "obType": { - "tag": "Basic", - "content": "Object" - }, - "over": { - "tag": "Basic", - "content": "0194d398-a28e-7433-89f8-563bae6e6875" - } - }, - { - "tag": "object", - "name": "", - "id": "0196021e-e55e-764e-85c8-827f94d7f3bd", - "obType": { - "tag": "Basic", - "content": "Object" - }, - "over": { - "tag": "Basic", - "content": "0194d39a-89cf-762b-9d2a-5678b878d6c7" - } - }, - { - "tag": "object", - "name": "", - "id": "0196021f-0a11-7443-b5da-31175c628e3c", - "obType": { - "tag": "Basic", - "content": "Object" - }, - "over": { - "tag": "Basic", - "content": "0194d398-b3ef-728d-bd88-60b48fd7349a" - } - }, - { - "tag": "object", - "name": "", - "id": "0196021f-4c93-70dc-8e61-24459f79f837", - "obType": { - "tag": "Basic", - "content": "Object" - }, - "over": { - "tag": "Basic", - "content": "0194d398-d0cb-7308-b7e0-eace5b21af24" - } - }, - { - "tag": "object", - "name": "u", - "id": "0196021c-f5fe-70f3-ac68-89ae212970ea", - "obType": { - "tag": "Basic", - "content": "Object" - }, - "over": { - "tag": "Basic", - "content": "0194d398-d0cb-7308-b7e0-eace5b21af24" - } - }, - { - "tag": "morphism", - "name": "", - "id": "0196021e-848d-704c-a45c-a325b63951e6", - "morType": { - "tag": "Basic", - "content": "Nonscalar" - }, - "over": { - "tag": "Basic", - "content": "0194d399-34f3-773c-91b9-857da9c4311f" - }, - "dom": { - "tag": "Basic", - "content": "0196021c-f5fe-70f3-ac68-89ae212970ea" - }, - "cod": { - "tag": "Basic", - "content": "0196021e-9635-74de-845a-cee56d3e5cc5" - } - }, - { - "tag": "morphism", - "name": "", - "id": "0196021e-ecf9-7408-b881-d981c4e85222", - "morType": { - "tag": "Basic", - "content": "Nonscalar" - }, - "over": { - "tag": "Basic", - "content": "0194d39a-ed25-710f-b53f-89541021281f" - }, - "dom": { - "tag": "Basic", - "content": "0196021e-e55e-764e-85c8-827f94d7f3bd" - }, - "cod": { - "tag": "Basic", - "content": "0196021f-0a11-7443-b5da-31175c628e3c" - } - }, - { - "tag": "morphism", - "name": "", - "id": "0196021f-6b45-751e-8313-df1024cd9fa0", - "morType": { - "tag": "Hom", - "content": { - "tag": "Basic", - "content": "Object" - } - }, - "over": { - "tag": "Basic", - "content": "01960dde-1193-7132-b662-9bf24ed05264" - }, - "dom": { - "tag": "Basic", - "content": "0196021f-4c93-70dc-8e61-24459f79f837" - }, - "cod": { - "tag": "Basic", - "content": "0196021d-1aa4-776d-b4fb-05d24d0c6de4" - } - }, - { - "tag": "morphism", - "name": "", - "id": "01960df4-b95f-7660-90b6-aaf1dc940a15", - "morType": { - "tag": "Basic", - "content": "Nonscalar" - }, - "over": { - "tag": "Basic", - "content": "0194d39c-622d-7599-bc5c-e7e8208d6cdd" - }, - "dom": { - "tag": "Basic", - "content": "0196021c-f5fe-70f3-ac68-89ae212970ea" - }, - "cod": { - "tag": "Basic", - "content": "0196021d-1aa4-776d-b4fb-05d24d0c6de4" - } - }, - { - "tag": "morphism", - "name": "", - "id": "0196021f-1ba8-77a5-a635-8b3ca32ae99c", - "morType": { - "tag": "Basic", - "content": "Nonscalar" - }, - "over": { - "tag": "Basic", - "content": "0194d39d-d297-77a9-95a2-6ed7105fdca3" - }, - "dom": { - "tag": "Basic", - "content": "0196021f-0a11-7443-b5da-31175c628e3c" - }, - "cod": { - "tag": "Basic", - "content": "0196021f-4c93-70dc-8e61-24459f79f837" - } - }, - { - "tag": "morphism", - "name": "", - "id": "0196021e-c8a6-74df-8194-3ec769ba3d1d", - "morType": { - "tag": "Basic", - "content": "Nonscalar" - }, - "over": { - "tag": "Basic", - "content": "0194d39a-6084-7537-aec1-caf560ba416b" - }, - "dom": { - "tag": "Basic", - "content": "0196021e-9635-74de-845a-cee56d3e5cc5" - }, - "cod": { - "tag": "Basic", - "content": "0196021e-e55e-764e-85c8-827f94d7f3bd" - } - } - ], - "model": [ - { - "id": "0194d398-a28e-7433-89f8-563bae6e6875", - "name": "0-form", - "obType": { - "content": "Object", - "tag": "Basic" - }, - "tag": "object" - }, - { - "id": "0194d398-b3ef-728d-bd88-60b48fd7349a", - "name": "Dual 1-form", - "obType": { - "content": "Object", - "tag": "Basic" - }, - "tag": "object" - }, - { - "id": "0194d398-d0cb-7308-b7e0-eace5b21af24", - "name": "Dual 2-form", - "obType": { - "content": "Object", - "tag": "Basic" - }, - "tag": "object" - }, - { - "id": "0194d39a-89cf-762b-9d2a-5678b878d6c7", - "name": "Primal 1-form", - "obType": { - "content": "Object", - "tag": "Basic" - }, - "tag": "object" - }, - { - "cod": { - "content": "0194d398-a28e-7433-89f8-563bae6e6875", - "tag": "Basic" - }, - "dom": { - "content": "0194d398-d0cb-7308-b7e0-eace5b21af24", - "tag": "Basic" - }, - "id": "0194d399-34f3-773c-91b9-857da9c4311f", - "morType": { - "content": "Nonscalar", - "tag": "Basic" - }, - "name": " ⋆₀⁻¹", - "tag": "morphism" - }, - { - "cod": { - "content": "0194d398-a28e-7433-89f8-563bae6e6875", - "tag": "Basic" - }, - "dom": { - "content": "0194d398-a28e-7433-89f8-563bae6e6875", - "tag": "Basic" - }, - "id": "0194d399-b2a2-73ff-aece-cb0f26644045", - "morType": { - "content": "Nonscalar", - "tag": "Basic" - }, - "name": "Δ⁻¹", - "tag": "morphism" - }, - { - "cod": { - "content": "0194d39a-89cf-762b-9d2a-5678b878d6c7", - "tag": "Basic" - }, - "dom": { - "content": "0194d398-a28e-7433-89f8-563bae6e6875", - "tag": "Basic" - }, - "id": "0194d39a-6084-7537-aec1-caf560ba416b", - "morType": { - "content": "Nonscalar", - "tag": "Basic" - }, - "name": "d₀", - "tag": "morphism" - }, - { - "cod": { - "content": "0194d398-b3ef-728d-bd88-60b48fd7349a", - "tag": "Basic" - }, - "dom": { - "content": "0194d39a-89cf-762b-9d2a-5678b878d6c7", - "tag": "Basic" - }, - "id": "0194d39a-ed25-710f-b53f-89541021281f", - "morType": { - "content": "Nonscalar", - "tag": "Basic" - }, - "name": "⋆₁", - "tag": "morphism" - }, - { - "cod": { - "content": "0194d398-b3ef-728d-bd88-60b48fd7349a", - "tag": "Basic" - }, - "dom": { - "content": "0194d398-b3ef-728d-bd88-60b48fd7349a", - "tag": "Basic" - }, - "id": "0194d39b-587f-7559-a1ff-b6ed58899461", - "morType": { - "content": "Nonscalar", - "tag": "Basic" - }, - "name": "lamb", - "tag": "morphism" - }, - { - "cod": { - "content": "0194d39a-89cf-762b-9d2a-5678b878d6c7", - "tag": "Basic" - }, - "dom": { - "content": "0194d398-b3ef-728d-bd88-60b48fd7349a", - "tag": "Basic" - }, - "id": "0194d39b-a70a-77d5-8e89-66f0e767a9da", - "morType": { - "content": "Nonscalar", - "tag": "Basic" - }, - "name": " ♭♯", - "tag": "morphism" - }, - { - "cod": { - "content": "0194d398-d0cb-7308-b7e0-eace5b21af24", - "tag": "Basic" - }, - "dom": { - "content": "0194d398-b3ef-728d-bd88-60b48fd7349a", - "tag": "Basic" - }, - "id": "0194d39d-d297-77a9-95a2-6ed7105fdca3", - "morType": { - "content": "Nonscalar", - "tag": "Basic" - }, - "name": "d̃₁", - "tag": "morphism" - }, - { - "cod": { - "content": "0194d398-d0cb-7308-b7e0-eace5b21af24", - "tag": "Basic" - }, - "dom": { - "content": "0194d398-d0cb-7308-b7e0-eace5b21af24", - "tag": "Basic" - }, - "id": "0194d39c-622d-7599-bc5c-e7e8208d6cdd", - "morType": { - "content": "Nonscalar", - "tag": "Basic" - }, - "name": "∂ₜ", - "tag": "morphism" - }, - { - "cod": { - "content": "0194d398-d0cb-7308-b7e0-eace5b21af24", - "tag": "Basic" - }, - "dom": { - "content": "0194d398-d0cb-7308-b7e0-eace5b21af24", - "tag": "Basic" - }, - "id": "0194d39e-5d44-77cd-bc5e-156c5c56ae85", - "morType": { - "content": "Nonscalar", - "tag": "Basic" - }, - "name": "-", - "tag": "morphism" - }, - { - "cod": { - "content": "0194d398-d0cb-7308-b7e0-eace5b21af24", - "tag": "Basic" - }, - "dom": { - "content": "0194d398-d0cb-7308-b7e0-eace5b21af24", - "tag": "Basic" - }, - "id": "01960dde-1193-7132-b662-9bf24ed05264", - "morType": { - "content": { - "content": "Object", - "tag": "Basic" - }, - "tag": "Hom" - }, - "name": "any_scalar", - "tag": "morphism" - } - ], - "domain": "Plane", - "mesh": "Rectangle", - "initialConditions": { - "0196021c-f5fe-70f3-ac68-89ae212970ea": "Gaussian", - "0196021d-1aa4-776d-b4fb-05d24d0c6de4": "Gaussian" - }, - "plotVariables": [ - "0196021c-f5fe-70f3-ac68-89ae212970ea" - ], - "scalars": { - "01960dde-1193-7132-b662-9bf24ed05264": 0.5 - }, - "duration": 10 -} diff --git a/packages/algjulia-interop/test/test_jsons/payload.json b/packages/algjulia-interop/test/test_jsons/payload.json deleted file mode 100644 index a8d46701e..000000000 --- a/packages/algjulia-interop/test/test_jsons/payload.json +++ /dev/null @@ -1,435 +0,0 @@ -{ - "diagram": [ - { - "tag": "object", - "name": "dv/dt", - "id": "0196021d-1aa4-776d-b4fb-05d24d0c6de4", - "obType": { - "tag": "Basic", - "content": "Object" - }, - "over": { - "tag": "Basic", - "content": "0194d398-d0cb-7308-b7e0-eace5b21af24" - } - }, - { - "tag": "object", - "name": "", - "id": "0196021e-9635-74de-845a-cee56d3e5cc5", - "obType": { - "tag": "Basic", - "content": "Object" - }, - "over": { - "tag": "Basic", - "content": "0194d398-a28e-7433-89f8-563bae6e6875" - } - }, - { - "tag": "object", - "name": "", - "id": "0196021e-e55e-764e-85c8-827f94d7f3bd", - "obType": { - "tag": "Basic", - "content": "Object" - }, - "over": { - "tag": "Basic", - "content": "0194d39a-89cf-762b-9d2a-5678b878d6c7" - } - }, - { - "tag": "object", - "name": "", - "id": "0196021f-0a11-7443-b5da-31175c628e3c", - "obType": { - "tag": "Basic", - "content": "Object" - }, - "over": { - "tag": "Basic", - "content": "0194d398-b3ef-728d-bd88-60b48fd7349a" - } - }, - { - "tag": "object", - "name": "", - "id": "0196021f-4c93-70dc-8e61-24459f79f837", - "obType": { - "tag": "Basic", - "content": "Object" - }, - "over": { - "tag": "Basic", - "content": "0194d398-d0cb-7308-b7e0-eace5b21af24" - } - }, - { - "tag": "object", - "name": "v", - "id": "0196021c-f5fe-70f3-ac68-89ae212970ea", - "obType": { - "tag": "Basic", - "content": "Object" - }, - "over": { - "tag": "Basic", - "content": "0194d398-d0cb-7308-b7e0-eace5b21af24" - } - }, - { - "tag": "morphism", - "name": "", - "id": "0196021e-848d-704c-a45c-a325b63951e6", - "morType": { - "tag": "Basic", - "content": "Nonscalar" - }, - "over": { - "tag": "Basic", - "content": "0194d399-34f3-773c-91b9-857da9c4311f" - }, - "dom": { - "tag": "Basic", - "content": "0196021c-f5fe-70f3-ac68-89ae212970ea" - }, - "cod": { - "tag": "Basic", - "content": "0196021e-9635-74de-845a-cee56d3e5cc5" - } - }, - { - "tag": "morphism", - "name": "", - "id": "0196021e-ecf9-7408-b881-d981c4e85222", - "morType": { - "tag": "Basic", - "content": "Nonscalar" - }, - "over": { - "tag": "Basic", - "content": "0194d39a-ed25-710f-b53f-89541021281f" - }, - "dom": { - "tag": "Basic", - "content": "0196021e-e55e-764e-85c8-827f94d7f3bd" - }, - "cod": { - "tag": "Basic", - "content": "0196021f-0a11-7443-b5da-31175c628e3c" - } - }, - { - "tag": "morphism", - "name": "", - "id": "0196021f-6b45-751e-8313-df1024cd9fa0", - "morType": { - "tag": "Hom", - "content": { - "tag": "Basic", - "content": "Object" - } - }, - "over": { - "tag": "Basic", - "content": "01960dde-1193-7132-b662-9bf24ed05264" - }, - "dom": { - "tag": "Basic", - "content": "0196021f-4c93-70dc-8e61-24459f79f837" - }, - "cod": { - "tag": "Basic", - "content": "0196021d-1aa4-776d-b4fb-05d24d0c6de4" - } - }, - { - "tag": "morphism", - "name": "", - "id": "01960df4-b95f-7660-90b6-aaf1dc940a15", - "morType": { - "tag": "Basic", - "content": "Nonscalar" - }, - "over": { - "tag": "Basic", - "content": "0194d39c-622d-7599-bc5c-e7e8208d6cdd" - }, - "dom": { - "tag": "Basic", - "content": "0196021c-f5fe-70f3-ac68-89ae212970ea" - }, - "cod": { - "tag": "Basic", - "content": "0196021d-1aa4-776d-b4fb-05d24d0c6de4" - } - }, - { - "tag": "morphism", - "name": "", - "id": "0196021f-1ba8-77a5-a635-8b3ca32ae99c", - "morType": { - "tag": "Basic", - "content": "Nonscalar" - }, - "over": { - "tag": "Basic", - "content": "0194d39d-d297-77a9-95a2-6ed7105fdca3" - }, - "dom": { - "tag": "Basic", - "content": "0196021f-0a11-7443-b5da-31175c628e3c" - }, - "cod": { - "tag": "Basic", - "content": "0196021f-4c93-70dc-8e61-24459f79f837" - } - }, - { - "tag": "morphism", - "name": "", - "id": "0196021e-c8a6-74df-8194-3ec769ba3d1d", - "morType": { - "tag": "Basic", - "content": "Nonscalar" - }, - "over": { - "tag": "Basic", - "content": "0194d39a-6084-7537-aec1-caf560ba416b" - }, - "dom": { - "tag": "Basic", - "content": "0196021e-9635-74de-845a-cee56d3e5cc5" - }, - "cod": { - "tag": "Basic", - "content": "0196021e-e55e-764e-85c8-827f94d7f3bd" - } - } - ], - "model": [ - { - "id": "0194d398-a28e-7433-89f8-563bae6e6875", - "name": "0-form", - "obType": { - "content": "Object", - "tag": "Basic" - }, - "tag": "object" - }, - { - "id": "0194d398-b3ef-728d-bd88-60b48fd7349a", - "name": "Dual 1-form", - "obType": { - "content": "Object", - "tag": "Basic" - }, - "tag": "object" - }, - { - "id": "0194d398-d0cb-7308-b7e0-eace5b21af24", - "name": "Dual 2-form", - "obType": { - "content": "Object", - "tag": "Basic" - }, - "tag": "object" - }, - { - "id": "0194d39a-89cf-762b-9d2a-5678b878d6c7", - "name": "Primal 1-form", - "obType": { - "content": "Object", - "tag": "Basic" - }, - "tag": "object" - }, - { - "cod": { - "content": "0194d398-a28e-7433-89f8-563bae6e6875", - "tag": "Basic" - }, - "dom": { - "content": "0194d398-d0cb-7308-b7e0-eace5b21af24", - "tag": "Basic" - }, - "id": "0194d399-34f3-773c-91b9-857da9c4311f", - "morType": { - "content": "Nonscalar", - "tag": "Basic" - }, - "name": " ⋆₀⁻¹", - "tag": "morphism" - }, - { - "cod": { - "content": "0194d398-a28e-7433-89f8-563bae6e6875", - "tag": "Basic" - }, - "dom": { - "content": "0194d398-a28e-7433-89f8-563bae6e6875", - "tag": "Basic" - }, - "id": "0194d399-b2a2-73ff-aece-cb0f26644045", - "morType": { - "content": "Nonscalar", - "tag": "Basic" - }, - "name": "Δ⁻¹", - "tag": "morphism" - }, - { - "cod": { - "content": "0194d39a-89cf-762b-9d2a-5678b878d6c7", - "tag": "Basic" - }, - "dom": { - "content": "0194d398-a28e-7433-89f8-563bae6e6875", - "tag": "Basic" - }, - "id": "0194d39a-6084-7537-aec1-caf560ba416b", - "morType": { - "content": "Nonscalar", - "tag": "Basic" - }, - "name": "d₀", - "tag": "morphism" - }, - { - "cod": { - "content": "0194d398-b3ef-728d-bd88-60b48fd7349a", - "tag": "Basic" - }, - "dom": { - "content": "0194d39a-89cf-762b-9d2a-5678b878d6c7", - "tag": "Basic" - }, - "id": "0194d39a-ed25-710f-b53f-89541021281f", - "morType": { - "content": "Nonscalar", - "tag": "Basic" - }, - "name": "⋆₁", - "tag": "morphism" - }, - { - "cod": { - "content": "0194d398-b3ef-728d-bd88-60b48fd7349a", - "tag": "Basic" - }, - "dom": { - "content": "0194d398-b3ef-728d-bd88-60b48fd7349a", - "tag": "Basic" - }, - "id": "0194d39b-587f-7559-a1ff-b6ed58899461", - "morType": { - "content": "Nonscalar", - "tag": "Basic" - }, - "name": "lamb", - "tag": "morphism" - }, - { - "cod": { - "content": "0194d39a-89cf-762b-9d2a-5678b878d6c7", - "tag": "Basic" - }, - "dom": { - "content": "0194d398-b3ef-728d-bd88-60b48fd7349a", - "tag": "Basic" - }, - "id": "0194d39b-a70a-77d5-8e89-66f0e767a9da", - "morType": { - "content": "Nonscalar", - "tag": "Basic" - }, - "name": " ♭♯", - "tag": "morphism" - }, - { - "cod": { - "content": "0194d398-d0cb-7308-b7e0-eace5b21af24", - "tag": "Basic" - }, - "dom": { - "content": "0194d398-b3ef-728d-bd88-60b48fd7349a", - "tag": "Basic" - }, - "id": "0194d39d-d297-77a9-95a2-6ed7105fdca3", - "morType": { - "content": "Nonscalar", - "tag": "Basic" - }, - "name": "d̃₁", - "tag": "morphism" - }, - { - "cod": { - "content": "0194d398-d0cb-7308-b7e0-eace5b21af24", - "tag": "Basic" - }, - "dom": { - "content": "0194d398-d0cb-7308-b7e0-eace5b21af24", - "tag": "Basic" - }, - "id": "0194d39c-622d-7599-bc5c-e7e8208d6cdd", - "morType": { - "content": "Nonscalar", - "tag": "Basic" - }, - "name": "∂ₜ", - "tag": "morphism" - }, - { - "cod": { - "content": "0194d398-d0cb-7308-b7e0-eace5b21af24", - "tag": "Basic" - }, - "dom": { - "content": "0194d398-d0cb-7308-b7e0-eace5b21af24", - "tag": "Basic" - }, - "id": "0194d39e-5d44-77cd-bc5e-156c5c56ae85", - "morType": { - "content": "Nonscalar", - "tag": "Basic" - }, - "name": "-", - "tag": "morphism" - }, - { - "cod": { - "content": "0194d398-d0cb-7308-b7e0-eace5b21af24", - "tag": "Basic" - }, - "dom": { - "content": "0194d398-d0cb-7308-b7e0-eace5b21af24", - "tag": "Basic" - }, - "id": "01960dde-1193-7132-b662-9bf24ed05264", - "morType": { - "content": { - "content": "Object", - "tag": "Basic" - }, - "tag": "Hom" - }, - "name": "any_scalar", - "tag": "morphism" - } - ], - "domain": "Plane", - "mesh": "Rectangle", - "initialConditions": { - "0196021c-f5fe-70f3-ac68-89ae212970ea": "Gaussian", - "0196021d-1aa4-776d-b4fb-05d24d0c6de4": "Gaussian" - }, - "plotVariables": [ - "0196021c-f5fe-70f3-ac68-89ae212970ea" - ], - "scalars": { - "01960dde-1193-7132-b662-9bf24ed05264": 1 - }, - "duration": 10 -} diff --git a/packages/catlog-wasm/src/lib.rs b/packages/catlog-wasm/src/lib.rs index 11fea1f65..5bc99f51d 100644 --- a/packages/catlog-wasm/src/lib.rs +++ b/packages/catlog-wasm/src/lib.rs @@ -16,7 +16,9 @@ pub mod result; pub mod model; pub mod model_diagram; +pub mod model_diagram_presentation; pub mod model_morphism; +pub mod model_presentation; pub mod theory; pub mod analyses; diff --git a/packages/catlog-wasm/src/model.rs b/packages/catlog-wasm/src/model.rs index edb172486..50003b5bc 100644 --- a/packages/catlog-wasm/src/model.rs +++ b/packages/catlog-wasm/src/model.rs @@ -20,6 +20,7 @@ use catlog::validate::Validate; use catlog::zero::{NameLookup, Namespace, QualifiedLabel, QualifiedName}; use notebook_types::current::{path as notebook_path, *}; +use super::model_presentation::*; use super::notation::*; use super::result::JsResult; use super::theory::{ @@ -431,26 +432,6 @@ impl DblModel { }) } - /// Gets the domain of a morphism generator, if it is set. - #[wasm_bindgen(js_name = "getDom")] - pub fn get_dom(&self, id: &QualifiedName) -> Result, String> { - all_the_same!(match &self.model { - DblModelBox::[Discrete, DiscreteTab, Modal](model) => { - Ok(model.get_dom(id).map(|ob| Quoter.quote(ob))) - } - }) - } - - /// Gets the codomain of a morphism generator, if it is set. - #[wasm_bindgen(js_name = "getCod")] - pub fn get_cod(&self, id: &QualifiedName) -> Result, String> { - all_the_same!(match &self.model { - DblModelBox::[Discrete, DiscreteTab, Modal](model) => { - Ok(model.get_cod(id).map(|ob| Quoter.quote(ob))) - } - }) - } - /// Gets the object type of an object in the model. #[wasm_bindgen(js_name = "obType")] pub fn ob_type(&self, ob: Ob) -> Result { @@ -540,6 +521,55 @@ impl DblModel { self.mor_namespace.name_with_label(label) } + /// Gets an object generator as it appears in the model's presentation. + #[wasm_bindgen(js_name = "obPresentation")] + pub fn ob_presentation(&self, id: QualifiedName) -> ObGenerator { + let label = self.ob_generator_label(&id); + let ob_type = all_the_same!(match &self.model { + DblModelBox::[Discrete, DiscreteTab, Modal](model) => { + Quoter.quote(&model.ob_generator_type(&id)) + } + }); + ObGenerator { id, label, ob_type } + } + + /// Gets a morphism generators as it appears in the model's presentation. + #[wasm_bindgen(js_name = "morPresentation")] + pub fn mor_presentation(&self, id: QualifiedName) -> Option { + let label = self.mor_generator_label(&id); + let (mor_type, dom, cod) = all_the_same!(match &self.model { + DblModelBox::[Discrete, DiscreteTab, Modal](model) => { + (Quoter.quote(&model.mor_generator_type(&id)), + Quoter.quote(model.get_dom(&id)?), + Quoter.quote(model.get_cod(&id)?)) + } + }); + Some(MorGenerator { + id, + label, + mor_type, + dom, + cod, + }) + } + + /// Constructs a serializable presentation of the model. + #[wasm_bindgen] + pub fn presentation(&self) -> ModelPresentation { + all_the_same!(match &self.model { + DblModelBox::[Discrete, DiscreteTab, Modal](model) => { + ModelPresentation { + ob_generators: { + model.ob_generators().map(|id| self.ob_presentation(id)).collect() + }, + mor_generators: { + model.mor_generators().filter_map(|id| self.mor_presentation(id)).collect() + } + } + } + }) + } + /// Validates the model, returning any validation failures. pub fn validate(&self) -> ModelValidationResult { let result = all_the_same!(match &self.model { @@ -665,8 +695,6 @@ pub(crate) mod tests { assert_eq!(model.has_mor(a.clone()), Ok(true)); assert_eq!(model.dom(a.clone()), Ok(x.clone())); assert_eq!(model.cod(a.clone()), Ok(y.clone())); - assert_eq!(model.get_dom(&a_id.into()), Ok(Some(x.clone()))); - assert_eq!(model.get_cod(&a_id.into()), Ok(Some(y.clone()))); assert_eq!(model.ob_type(x.clone()), Ok(ObType::Basic("Entity".into()))); assert_eq!(model.mor_type(a.clone()), Ok(MorType::Basic("Attr".into()))); assert_eq!(model.ob_generators().len(), 2); @@ -683,6 +711,10 @@ pub(crate) mod tests { assert_eq!(model.mor_generator_label(&a_id.into()), Some("attr".into())); assert_eq!(model.validate().0, JsResult::Ok(())); + let presentation = model.presentation(); + assert_eq!(presentation.ob_generators.len(), 2); + assert_eq!(presentation.mor_generators.len(), 1); + let mut model = DblModel::new(&th); assert!( model diff --git a/packages/catlog-wasm/src/model_diagram.rs b/packages/catlog-wasm/src/model_diagram.rs index 66958768c..22da749d5 100644 --- a/packages/catlog-wasm/src/model_diagram.rs +++ b/packages/catlog-wasm/src/model_diagram.rs @@ -6,19 +6,17 @@ use all_the_same::all_the_same; use derive_more::From; use serde::{Deserialize, Serialize}; use tsify::Tsify; -use uuid::Uuid; use wasm_bindgen::prelude::*; use catlog::dbl::model::{DblModel as _, DiscreteDblModel, FgDblModel, MutDblModel}; use catlog::dbl::model_diagram as diagram; use catlog::dbl::model_morphism::DiscreteDblModelMapping; use catlog::one::FgCategory; -use catlog::zero::{ - Mapping, MutMapping, NameLookup, NameSegment, Namespace, QualifiedLabel, QualifiedName, -}; +use catlog::zero::{MutMapping, NameLookup, NameSegment, Namespace, QualifiedLabel, QualifiedName}; use notebook_types::current::*; use super::model::DblModel; +use super::model_diagram_presentation::*; use super::notation::*; use super::result::JsResult; use super::theory::{DblTheory, DblTheoryBox}; @@ -104,50 +102,6 @@ impl DblModelDiagram { #[wasm_bindgen] impl DblModelDiagram { - /// Gets domain of a morphism generator for the diagram's indexing model. - #[wasm_bindgen(js_name = "getDom")] - pub fn get_dom(&self, id: &QualifiedName) -> Option { - all_the_same!(match &self.diagram { - DblModelDiagramBox::[Discrete](diagram) => { - let (_, model) = diagram.into(); - model.get_dom(id).map(|ob| Quoter.quote(ob)) - } - }) - } - - /// Gets codomain of a morphism generator for the diagram's indexing model. - #[wasm_bindgen(js_name = "getCod")] - pub fn get_cod(&self, id: &QualifiedName) -> Option { - all_the_same!(match &self.diagram { - DblModelDiagramBox::[Discrete](diagram) => { - let (_, model) = diagram.into(); - model.get_cod(id).map(|ob| Quoter.quote(ob)) - } - }) - } - - /// Gets the object that the given object generator is over. - #[wasm_bindgen(js_name = "getObOver")] - pub fn get_ob_over(&self, id: &QualifiedName) -> Option { - all_the_same!(match &self.diagram { - DblModelDiagramBox::[Discrete](diagram) => { - let (mapping, _) = diagram.into(); - mapping.0.ob_generator_map.apply_to_ref(id).map(|ob| Quoter.quote(&ob)) - } - }) - } - - /// Gets the morphism that the given morphism generator is over. - #[wasm_bindgen(js_name = "getMorOver")] - pub fn get_mor_over(&self, id: &QualifiedName) -> Option { - all_the_same!(match &self.diagram { - DblModelDiagramBox::[Discrete](diagram) => { - let (mapping, _) = diagram.into(); - mapping.0.mor_generator_map.apply_to_ref(id).map(|mor| Quoter.quote(&mor)) - } - }) - } - /// Gets the object type of an object in the diagram's indexing model. #[wasm_bindgen(js_name = "obType")] pub fn ob_type(&self, ob: Ob) -> Result { @@ -231,49 +185,60 @@ impl DblModelDiagram { self.ob_namespace.name_with_label(label) } - /// Returns array of diagram judgments that would define the diagram. - #[wasm_bindgen] - pub fn judgments(&self) -> Vec { - let ob_decls = self.ob_declarations().into_iter().map(DiagramJudgment::Object); - let mor_decls = self.mor_declarations().into_iter().map(DiagramJudgment::Morphism); - ob_decls.chain(mor_decls).collect() + /// Gets an object generator as it appears in the diagram's presentation. + #[wasm_bindgen(js_name = "obPresentation")] + pub fn ob_presentation(&self, id: QualifiedName) -> Option { + let label = self.ob_generator_label(&id); + let (ob_type, over) = all_the_same!(match &self.diagram { + DblModelDiagramBox::[Discrete](diagram) => { + let (mapping, model) = diagram.into(); + (Quoter.quote(&model.ob_generator_type(&id)), + Quoter.quote(mapping.0.ob_generator_map.get(&id)?)) + } + }); + Some(DiagramObGenerator { + id, + label, + ob_type, + over, + }) } - /// Returns array of declarations of basic objects. - fn ob_declarations(&self) -> Vec { - all_the_same!(match &self.diagram { + /// Gets a morphism generator as it appears in the diagram's presentation. + #[wasm_bindgen(js_name = "morPresentation")] + pub fn mor_presentation(&self, id: QualifiedName) -> Option { + let (mor_type, over, dom, cod) = all_the_same!(match &self.diagram { DblModelDiagramBox::[Discrete](diagram) => { let (mapping, model) = diagram.into(); - let decls = model.ob_generators().map(|x| { - let maybe_label = self.ob_namespace.label(&x); - DiagramObDecl { - name: maybe_label.map(|label| label.to_string()).unwrap_or_default(), - id: expect_single_uuid(&x), - ob_type: Quoter.quote(&model.ob_generator_type(&x)), - over: mapping.0.ob_generator_map.get(&x).map(|ob| Quoter.quote(ob)) - } - }); - decls.collect() + (Quoter.quote(&model.mor_generator_type(&id)), + Quoter.quote(mapping.0.mor_generator_map.get(&id)?), + Quoter.quote(model.get_dom(&id)?), + Quoter.quote(model.get_cod(&id)?)) } + }); + Some(DiagramMorGenerator { + id, + mor_type, + over, + dom, + cod, }) } - /// Returns array of declarations of basic morphisms. - fn mor_declarations(&self) -> Vec { + /// Constructs a serializable presentation of the diagram. + #[wasm_bindgen] + pub fn presentation(&self) -> ModelDiagramPresentation { all_the_same!(match &self.diagram { DblModelDiagramBox::[Discrete](diagram) => { - let (mapping, model) = diagram.into(); - let decls = model.mor_generators().map(|f| { - DiagramMorDecl { - name: "".into(), - id: expect_single_uuid(&f), - mor_type: Quoter.quote(&model.mor_generator_type(&f)), - over: mapping.0.mor_generator_map.get(&f).map(|mor| Quoter.quote(mor)), - dom: model.get_dom(&f).map(|ob| Quoter.quote(ob)), - cod: model.get_cod(&f).map(|ob| Quoter.quote(ob)), + let (_, model) = diagram.into(); + ModelDiagramPresentation { + ob_generators: { + model.ob_generators().filter_map(|id| self.ob_presentation(id)).collect() + }, + mor_generators: { + model.mor_generators().filter_map(|id| self.mor_presentation(id)).collect() } - }); - decls.collect() + } } }) } @@ -293,8 +258,11 @@ impl DblModelDiagram { let mut nanon = 0; for id in self.ob_generators() { if self.ob_namespace.label(&id).is_none() { + let Some(NameSegment::Uuid(uuid)) = id.only() else { + todo!("Imputation for diagrams with instantiations"); + }; nanon += 1; - self.ob_namespace.set_label(expect_single_uuid(&id), nanon.into()); + self.ob_namespace.set_label(uuid, nanon.into()); } } @@ -315,15 +283,6 @@ impl DblModelDiagram { } } -/// XXX: We only use this in `DblModelDiagram.judgments`, which probably -/// shouldn't need anyway but is currently used in the Decapodes interop. -fn expect_single_uuid(name: &QualifiedName) -> Uuid { - match name.only() { - Some(NameSegment::Uuid(uuid)) => uuid, - _ => panic!("Only names that are single UUIDs are currently supported in notebook types"), - } -} - /// Result of validating a diagram in a model. #[derive(Serialize, Deserialize, Tsify)] #[tsify(into_wasm_abi, from_wasm_abi)] @@ -398,15 +357,14 @@ mod tests { .is_ok() ); } - assert_eq!(diagram.get_dom(&a.into()), Some(Ob::Basic(x.into()))); - assert_eq!(diagram.get_cod(&a.into()), Some(Ob::Basic(var.into()))); - assert_eq!(diagram.get_ob_over(&x.into()), Some(Ob::Basic(entity.into()))); - assert_eq!(diagram.get_mor_over(&a.into()), Some(Mor::Basic(attr.into()))); assert_eq!(diagram.ob_generator_label(&var.into()), Some("var".into())); assert_eq!(diagram.ob_generator_with_label(&"var".into()), NameLookup::Unique(var.into())); assert_eq!(diagram.ob_generators().len(), 3); assert_eq!(diagram.mor_generators().len(), 2); - assert_eq!(diagram.judgments().len(), 5); assert_eq!(diagram.validate_in(&model).unwrap().0, JsResult::Ok(())); + + let presentation = diagram.presentation(); + assert_eq!(presentation.ob_generators.len(), 3); + assert_eq!(presentation.mor_generators.len(), 2); } } diff --git a/packages/catlog-wasm/src/model_diagram_presentation.rs b/packages/catlog-wasm/src/model_diagram_presentation.rs new file mode 100644 index 000000000..e7e89dd75 --- /dev/null +++ b/packages/catlog-wasm/src/model_diagram_presentation.rs @@ -0,0 +1,59 @@ +//! Serialization of elaborated diagrams. + +use serde::{Deserialize, Serialize}; +use tsify::Tsify; + +use catlog::zero::{QualifiedLabel, QualifiedName}; +use notebook_types::current::{Mor, MorType, Ob, ObType}; + +/// Presentation of a free diagram in a model. +#[derive(Serialize, Deserialize, Tsify)] +#[tsify(into_wasm_abi, from_wasm_abi)] +pub struct ModelDiagramPresentation { + /// Generating objects. + #[serde(rename = "obGenerators")] + pub ob_generators: Vec, + + /// Generating morphisms. + #[serde(rename = "morGenerators")] + pub mor_generators: Vec, +} + +/// Object generator in a diagram in a model. +#[derive(Serialize, Deserialize, Tsify)] +#[tsify(into_wasm_abi, from_wasm_abi)] +pub struct DiagramObGenerator { + /// Unique identifier of object. + pub id: QualifiedName, + + /// Human-readable label for object. + pub label: Option, + + /// The object's type in the double theory. + #[serde(rename = "obType")] + pub ob_type: ObType, + + /// Object in the model that this object is over. + pub over: Ob, +} + +/// Morphism generator in a diagram in a model. +#[derive(Serialize, Deserialize, Tsify)] +#[tsify(into_wasm_abi, from_wasm_abi)] +pub struct DiagramMorGenerator { + /// Unique identifier of morphism. + pub id: QualifiedName, + + /// The morphism's type in the double theory. + #[serde(rename = "morType")] + pub mor_type: MorType, + + /// Morphism in the model that this morphism is over. + pub over: Mor, + + /// Domain of this morphism. + pub dom: Ob, + + /// Codomain of this morphism. + pub cod: Ob, +} diff --git a/packages/catlog-wasm/src/model_presentation.rs b/packages/catlog-wasm/src/model_presentation.rs new file mode 100644 index 000000000..64a5bd4bc --- /dev/null +++ b/packages/catlog-wasm/src/model_presentation.rs @@ -0,0 +1,63 @@ +//! Serialization of elaborated models. +//! +//! In contrast to a [model +//! notebook](notebook_types::current::ModelDocumentContent), which is mere +//! *notation*, these data types serialize a fully *elaborated* model. The +//! serialization is as a presentation in terms of generators and relations. + +use serde::{Deserialize, Serialize}; +use tsify::Tsify; + +use catlog::zero::{QualifiedLabel, QualifiedName}; +use notebook_types::current::{MorType, Ob, ObType}; + +/// Presentation of a model of a double theory. +/// +/// TODO: Include equations between morphisms. +#[derive(Serialize, Deserialize, Tsify)] +#[tsify(into_wasm_abi, from_wasm_abi)] +pub struct ModelPresentation { + /// Generating objects. + #[serde(rename = "obGenerators")] + pub ob_generators: Vec, + + /// Generating morphisms. + #[serde(rename = "morGenerators")] + pub mor_generators: Vec, +} + +/// Object generator in a model of a double theory. +#[derive(Serialize, Deserialize, Tsify)] +#[tsify(into_wasm_abi, from_wasm_abi)] +pub struct ObGenerator { + /// Unique identifier of object. + pub id: QualifiedName, + + /// Human-readable label for object. + pub label: Option, + + /// The object's type in the double theory. + #[serde(rename = "obType")] + pub ob_type: ObType, +} + +/// Morphism generator in a model of a double theory. +#[derive(Serialize, Deserialize, Tsify)] +#[tsify(into_wasm_abi, from_wasm_abi)] +pub struct MorGenerator { + /// Unique identifier of morphism. + pub id: QualifiedName, + + /// Human-readable label for morphism. + pub label: Option, + + /// The morphism's type in the double theory. + #[serde(rename = "morType")] + pub mor_type: MorType, + + /// Domain of morphism. + pub dom: Ob, + + /// Codomain of morphism. + pub cod: Ob, +} diff --git a/packages/frontend/package.json b/packages/frontend/package.json index e0afb625e..2f14c4284 100644 --- a/packages/frontend/package.json +++ b/packages/frontend/package.json @@ -45,6 +45,7 @@ "@solid-primitives/timer": "^1.4.1", "@solidjs/router": "^0.15.3", "@viz-js/viz": "^3.15.0", + "axios": "^1.13.2", "catcolab-api": "link:../backend/pkg", "catlog-wasm": "link:../catlog-wasm/dist/pkg-browser", "echarts": "^5.5.1", diff --git a/packages/frontend/pnpm-lock.yaml b/packages/frontend/pnpm-lock.yaml index 4848f840c..25ae8e8e0 100644 --- a/packages/frontend/pnpm-lock.yaml +++ b/packages/frontend/pnpm-lock.yaml @@ -83,6 +83,9 @@ importers: '@viz-js/viz': specifier: ^3.15.0 version: 3.15.0 + axios: + specifier: ^1.13.2 + version: 1.13.2 catcolab-api: specifier: link:../backend/pkg version: link:../backend/pkg @@ -1312,9 +1315,15 @@ packages: resolution: {integrity: sha512-LElXdjswlqjWrPpJFg1Fx4wpkOCxj1TDHlSV4PlaRxHGWko024xICaa97ZkMfs6DRKlCguiAI+rbXv5GWwXIkg==} hasBin: true + asynckit@0.4.0: + resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} + axios@0.26.1: resolution: {integrity: sha512-fPwcX4EvnSHuInCMItEhAGnaSEXRBjtzh9fOtsE6E1G6p7vl7edEeZe11QHf18+6+9gR5PbKV/sGKNaD8YaMeA==} + axios@1.13.2: + resolution: {integrity: sha512-VPk9ebNqPcy5lRGuSlKx752IlDatOjT9paPlm8A7yOuW2Fbvp4X3JznJtT4f0GzGLLiWE9W8onz51SqLYwzGaA==} + babel-plugin-jsx-dom-expressions@0.39.2: resolution: {integrity: sha512-rCkSYFuLl5/XD+BXjZk1XxFAsIBgNe9WZ7xBHjQV1dBliI64kO+EWktAD3b6Bj/SXk+LpVXFyMVydhnI35svWQ==} peerDependencies: @@ -1370,6 +1379,10 @@ packages: resolution: {integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==} engines: {node: '>=8'} + call-bind-apply-helpers@1.0.2: + resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==} + engines: {node: '>= 0.4'} + camelcase@6.3.0: resolution: {integrity: sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==} engines: {node: '>=10'} @@ -1443,6 +1456,10 @@ packages: color-name@1.1.4: resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} + combined-stream@1.0.8: + resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} + engines: {node: '>= 0.8'} + comma-separated-tokens@2.0.3: resolution: {integrity: sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==} @@ -1508,6 +1525,10 @@ packages: resolution: {integrity: sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==} engines: {node: '>=6'} + delayed-stream@1.0.0: + resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} + engines: {node: '>=0.4.0'} + dequal@2.0.3: resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==} engines: {node: '>=6'} @@ -1527,6 +1548,10 @@ packages: resolution: {integrity: sha512-uIFDxqpRZGZ6ThOk84hEfqWoHx2devRFvpTZcTHur85vImfaxUbTW9Ryh4CpCuDnToOP1CEtXKIgytHBPVff5A==} engines: {node: '>=0.3.1'} + dunder-proto@1.0.1: + resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==} + engines: {node: '>= 0.4'} + eastasianwidth@0.2.0: resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} @@ -1553,9 +1578,25 @@ packages: resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==} engines: {node: '>=0.12'} + es-define-property@1.0.1: + resolution: {integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==} + engines: {node: '>= 0.4'} + + es-errors@1.3.0: + resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} + engines: {node: '>= 0.4'} + es-module-lexer@1.7.0: resolution: {integrity: sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==} + es-object-atoms@1.1.1: + resolution: {integrity: sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==} + engines: {node: '>= 0.4'} + + es-set-tostringtag@2.1.0: + resolution: {integrity: sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==} + engines: {node: '>= 0.4'} + esast-util-from-estree@2.0.0: resolution: {integrity: sha512-4CyanoAudUSBAn5K13H4JhsMH6L9ZP7XbLVe/dKybkxMO7eDyLsT8UHl9TRNrU2Gr9nz+FovfSIjuXWJ81uVwQ==} @@ -1673,6 +1714,10 @@ packages: resolution: {integrity: sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg==} engines: {node: '>=14'} + form-data@4.0.4: + resolution: {integrity: sha512-KrGhL9Q4zjj0kiUt5OO4Mr/A/jlI2jDYs5eHBpYHPcBEVSiipAvn2Ko2HnPe20rmcuuvMHNdZFp+4IlGTMF0Ow==} + engines: {node: '>= 6'} + fs-minipass@2.1.0: resolution: {integrity: sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==} engines: {node: '>= 8'} @@ -1685,6 +1730,9 @@ packages: engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} os: [darwin] + function-bind@1.1.2: + resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} + gensync@1.0.0-beta.2: resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} engines: {node: '>=6.9.0'} @@ -1693,6 +1741,14 @@ packages: resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} engines: {node: 6.* || 8.* || >= 10.*} + get-intrinsic@1.3.0: + resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==} + engines: {node: '>= 0.4'} + + get-proto@1.0.1: + resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==} + engines: {node: '>= 0.4'} + glob-parent@5.1.2: resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} engines: {node: '>= 6'} @@ -1709,6 +1765,10 @@ packages: resolution: {integrity: sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==} engines: {node: '>=4'} + gopd@1.2.0: + resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==} + engines: {node: '>= 0.4'} + has-flag@3.0.0: resolution: {integrity: sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==} engines: {node: '>=4'} @@ -1717,6 +1777,18 @@ packages: resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} engines: {node: '>=8'} + has-symbols@1.1.0: + resolution: {integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==} + engines: {node: '>= 0.4'} + + has-tostringtag@1.0.2: + resolution: {integrity: sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==} + engines: {node: '>= 0.4'} + + hasown@2.0.2: + resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} + engines: {node: '>= 0.4'} + hast-util-from-dom@5.0.1: resolution: {integrity: sha512-N+LqofjR2zuzTjCPzyDUdSshy4Ma6li7p/c3pA78uTwzFgENbgbUrm2ugwsOdcjI1muO+o6Dgzp9p8WHtn/39Q==} @@ -1977,6 +2049,10 @@ packages: resolution: {integrity: sha512-a54IwgWPaeBCAAsv13YgmALOF1elABB08FxO9i+r4VFk5Vl4pKokRPeX8u5TCgSsPi6ec1otfLjdOpVcgbpshg==} hasBin: true + math-intrinsics@1.1.0: + resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==} + engines: {node: '>= 0.4'} + mdast-util-definitions@5.1.2: resolution: {integrity: sha512-8SVPMuHqlPME/z3gqVwWY4zVXn8lqKv/pAhC57FuJ40ImXyBpmO5ukh98zB2v7Blql2FiHjHv9LVztSIqjY+MA==} @@ -2215,6 +2291,14 @@ packages: micromark@4.0.2: resolution: {integrity: sha512-zpe98Q6kvavpCr1NPVSCMebCKfD7CA2NqZ+rykeNhONIJBpc1tFKt9hucLGwha3jNTNI8lHpctWJWoimVF4PfA==} + mime-db@1.52.0: + resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==} + engines: {node: '>= 0.6'} + + mime-types@2.1.35: + resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==} + engines: {node: '>= 0.6'} + minimatch@3.1.2: resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} @@ -2417,6 +2501,9 @@ packages: resolution: {integrity: sha512-mRUWCc3KUU4w1jU8sGxICXH/gNS94DvI1gxqDvBzhj1JpcsimQkYiOJfwsPUykUI5ZaspFbSgmBLER8IrQ3tqw==} engines: {node: '>=12.0.0'} + proxy-from-env@1.1.0: + resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==} + punycode.js@2.3.1: resolution: {integrity: sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA==} engines: {node: '>=6'} @@ -4379,12 +4466,22 @@ snapshots: astring@1.9.0: {} + asynckit@0.4.0: {} + axios@0.26.1: dependencies: follow-redirects: 1.15.9 transitivePeerDependencies: - debug + axios@1.13.2: + dependencies: + follow-redirects: 1.15.9 + form-data: 4.0.4 + proxy-from-env: 1.1.0 + transitivePeerDependencies: + - debug + babel-plugin-jsx-dom-expressions@0.39.2(@babel/core@7.25.7): dependencies: '@babel/core': 7.25.7 @@ -4450,6 +4547,11 @@ snapshots: cac@6.7.14: {} + call-bind-apply-helpers@1.0.2: + dependencies: + es-errors: 1.3.0 + function-bind: 1.1.2 + camelcase@6.3.0: {} caniuse-lite@1.0.30001667: {} @@ -4535,6 +4637,10 @@ snapshots: color-name@1.1.4: {} + combined-stream@1.0.8: + dependencies: + delayed-stream: 1.0.0 + comma-separated-tokens@2.0.3: {} commander@8.3.0: {} @@ -4584,6 +4690,8 @@ snapshots: deep-eql@5.0.2: {} + delayed-stream@1.0.0: {} + dequal@2.0.3: {} detect-libc@2.0.4: @@ -4597,6 +4705,12 @@ snapshots: diff@5.2.0: {} + dunder-proto@1.0.1: + dependencies: + call-bind-apply-helpers: 1.0.2 + es-errors: 1.3.0 + gopd: 1.2.0 + eastasianwidth@0.2.0: {} echarts-solid@0.2.0(echarts@5.5.1)(solid-js@1.9.7): @@ -4619,8 +4733,23 @@ snapshots: entities@4.5.0: {} + es-define-property@1.0.1: {} + + es-errors@1.3.0: {} + es-module-lexer@1.7.0: {} + es-object-atoms@1.1.1: + dependencies: + es-errors: 1.3.0 + + es-set-tostringtag@2.1.0: + dependencies: + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + has-tostringtag: 1.0.2 + hasown: 2.0.2 + esast-util-from-estree@2.0.0: dependencies: '@types/estree-jsx': 1.0.5 @@ -4791,6 +4920,14 @@ snapshots: cross-spawn: 7.0.3 signal-exit: 4.1.0 + form-data@4.0.4: + dependencies: + asynckit: 0.4.0 + combined-stream: 1.0.8 + es-set-tostringtag: 2.1.0 + hasown: 2.0.2 + mime-types: 2.1.35 + fs-minipass@2.1.0: dependencies: minipass: 3.3.6 @@ -4800,10 +4937,30 @@ snapshots: fsevents@2.3.3: optional: true + function-bind@1.1.2: {} + gensync@1.0.0-beta.2: {} get-caller-file@2.0.5: {} + get-intrinsic@1.3.0: + dependencies: + call-bind-apply-helpers: 1.0.2 + es-define-property: 1.0.1 + es-errors: 1.3.0 + es-object-atoms: 1.1.1 + function-bind: 1.1.2 + get-proto: 1.0.1 + gopd: 1.2.0 + has-symbols: 1.1.0 + hasown: 2.0.2 + math-intrinsics: 1.1.0 + + get-proto@1.0.1: + dependencies: + dunder-proto: 1.0.1 + es-object-atoms: 1.1.1 + glob-parent@5.1.2: dependencies: is-glob: 4.0.3 @@ -4828,10 +4985,22 @@ snapshots: globals@11.12.0: {} + gopd@1.2.0: {} + has-flag@3.0.0: {} has-flag@4.0.0: {} + has-symbols@1.1.0: {} + + has-tostringtag@1.0.2: + dependencies: + has-symbols: 1.1.0 + + hasown@2.0.2: + dependencies: + function-bind: 1.1.2 + hast-util-from-dom@5.0.1: dependencies: '@types/hast': 3.0.4 @@ -5173,6 +5342,8 @@ snapshots: punycode.js: 2.3.1 uc.micro: 2.1.0 + math-intrinsics@1.1.0: {} + mdast-util-definitions@5.1.2: dependencies: '@types/mdast': 3.0.15 @@ -5813,6 +5984,12 @@ snapshots: transitivePeerDependencies: - supports-color + mime-db@1.52.0: {} + + mime-types@2.1.35: + dependencies: + mime-db: 1.52.0 + minimatch@3.1.2: dependencies: brace-expansion: 1.1.11 @@ -6029,6 +6206,8 @@ snapshots: '@types/node': 22.7.4 long: 5.2.3 + proxy-from-env@1.1.0: {} + punycode.js@2.3.1: {} querystringify@2.2.0: {} diff --git a/packages/frontend/src/model/types.ts b/packages/frontend/src/model/types.ts index 42f2b0fdd..5d1f6320e 100644 --- a/packages/frontend/src/model/types.ts +++ b/packages/frontend/src/model/types.ts @@ -48,23 +48,23 @@ export const duplicateModelJudgment = (jgmt: ModelJudgment): ModelJudgment => ({ id: v7(), }); -/** Return the label of a morphism if it exists, otherwise a label of the form "src->tgt" */ -export function morLabelOrDefault(id: QualifiedName, model?: DblModel): string { - const label = model?.morGeneratorLabel(id); - if (label) { - return label.join("."); +/** Get the label of a morphism if it exists, otherwise a label of the form "src->tgt" */ +export function morLabelOrDefault(id: QualifiedName, model?: DblModel): string | undefined { + if (!model) { + return; } - const [dom, cod] = [model?.getDom(id), model?.getCod(id)]; - if (dom?.tag !== "Basic" || cod?.tag !== "Basic") { - return ""; + const label = model.morGeneratorLabel(id); + if (label) { + return label.join("."); } - const source = model?.obGeneratorLabel(dom.content); - const target = model?.obGeneratorLabel(cod.content); - if (source && target) { - return `${source.join(".")}→${target.join(".")}`; + const mor = model.morPresentation(id); + if (mor && mor.dom.tag === "Basic" && mor.cod.tag === "Basic") { + const src = model.obGeneratorLabel(mor.dom.content); + const tgt = model.obGeneratorLabel(mor.cod.content); + if (src && tgt) { + return `${src.join(".")}→${tgt.join(".")}`; + } } - - return ""; } diff --git a/packages/frontend/src/stdlib/analyses.tsx b/packages/frontend/src/stdlib/analyses.tsx index d96922489..ac6b0f89c 100644 --- a/packages/frontend/src/stdlib/analyses.tsx +++ b/packages/frontend/src/stdlib/analyses.tsx @@ -40,6 +40,16 @@ export const diagramGraph = ( const DiagramGraph = lazy(() => import("./analyses/diagram_graph")); +export const tabularView = ( + options: AnalysisOptions, +): DiagramAnalysisMeta => ({ + ...options, + component: (props) => , + initialContent: GraphLayoutConfig.defaultConfig, +}); + +const TabularView = lazy(() => import("./analyses/tabular_view")); + export function linearODE( options: Partial & { simulate: Simulators.LinearODESimulator; @@ -100,8 +110,8 @@ const LotkaVolterra = lazy(() => import("./analyses/lotka_volterra")); export function massAction( options: Partial & { simulate: Simulators.MassActionSimulator; - isState?: (obType: ObType) => boolean; - isTransition?: (morType: MorType) => boolean; + stateType?: ObType; + transitionType?: MorType; }, ): ModelAnalysisMeta { const { diff --git a/packages/frontend/src/stdlib/analyses/decapodes.tsx b/packages/frontend/src/stdlib/analyses/decapodes.tsx index 0735a601f..838f32888 100644 --- a/packages/frontend/src/stdlib/analyses/decapodes.tsx +++ b/packages/frontend/src/stdlib/analyses/decapodes.tsx @@ -1,6 +1,6 @@ import { For, Match, Show, Switch, createMemo } from "solid-js"; -import type { DiagramJudgment, ModelJudgment, QualifiedName } from "catlog-wasm"; +import type { ModelDiagramPresentation, ModelPresentation, QualifiedName } from "catlog-wasm"; import type { DiagramAnalysisProps } from "../../analysis"; import { type ColumnSchema, @@ -12,7 +12,6 @@ import { createNumericalColumn, } from "../../components"; import type { LiveDiagramDocument } from "../../diagram"; -import { NotebookUtils } from "../../notebook"; import { uniqueIndexArray } from "../../util/indexing"; import { PDEPlot2D, type PDEPlotData2D } from "../../visualization"; import { createJuliaKernel, executeAndRetrieve } from "./jupyter"; @@ -51,6 +50,7 @@ export default function Decapodes(props: DiagramAnalysisProps { const simulationData = makeSimulationData(props.liveDiagram, props.content); + console.log(simulationData); if (!simulationData) { return undefined; } @@ -269,13 +269,19 @@ type Domain = { /** Data sent to the Julia kernel defining a simulation. */ type SimulationData = { - /** Judgments defining the diagram, including inferred ones. */ - diagram: Array; + /** Diagram defining the system of equations to simulate. */ + diagram: ModelDiagramPresentation; - /** Judgments defining the model. */ - model: Array; + /** Model that the diagram is in. */ + model: ModelPresentation; - /** The geometric domain to use for the simulation. */ + /** */ + analysis: SimulationAnalysis; +}; + +type SimulationAnalysis = { + + /** The geometric domain to use for the simulation. */ domain: string; /** The mesh to use for the simulation. */ @@ -292,7 +298,8 @@ type SimulationData = { /** Duration */ duration: number; -}; + +} /** Julia code run after kernel is started. */ const makeInitCode = () => @@ -315,14 +322,14 @@ const makeSimulationCode = (data: SimulationData) => # needed for returning large amounts of data, should be paired with a similar setting on the jupyter server IJulia.set_max_stdio(1_000_000_000) - system = Analysis(ThDecapode(), raw"""${JSON.stringify(data)}"""); - simulator = evalsim(system.pode); + simulation = DecapodeSimulation(raw"""${JSON.stringify(data)}"""); + simulator = evalsim(simulation.pode); - f = simulator(system.geometry.dualmesh, system.generate, DiagonalHodge()); + f = simulator(simulation.geometry.dualmesh, simulation.generate, DiagonalHodge()); - soln = run_sim(f, system.init, system.duration, ComponentArray(k=0.5,)); + result = run(f, simulation, ComponentArray(k=0.5,)) - JSON3.write(stdout, SimResult(soln, system)) + JSON3.write(stdout, result) `; /** Create data to send to the Julia kernel. */ @@ -330,8 +337,9 @@ const makeSimulationData = ( liveDiagram: LiveDiagramDocument, content: DecapodesAnalysisContent, ): SimulationData | undefined => { + const validatedModel = liveDiagram.liveModel.validatedModel(); const validatedDiagram = liveDiagram.validatedDiagram(); - if (validatedDiagram?.tag !== "Valid") { + if (!(validatedModel?.tag === "Valid" && validatedDiagram?.tag === "Valid")) { return undefined; } @@ -341,15 +349,15 @@ const makeSimulationData = ( } return { - diagram: validatedDiagram.diagram.judgments(), - // FIXME: Depending on judgments from notebook means that model cannot - // be composed of other models. - model: NotebookUtils.getFormalContent(liveDiagram.liveModel.liveDoc.doc.notebook), - domain, - mesh, - initialConditions, - plotVariables: Object.keys(plotVariables).filter((v) => plotVariables[v]), - scalars, - duration, + diagram: validatedDiagram.diagram.presentation(), + model: validatedModel.model.presentation(), + analysis: { + domain, + mesh, + initialConditions, + plotVariables: Object.keys(plotVariables).filter((v) => plotVariables[v]), + scalars, + duration, + } }; }; diff --git a/packages/frontend/src/stdlib/analyses/diagram_graph.tsx b/packages/frontend/src/stdlib/analyses/diagram_graph.tsx index a1ccfad26..cc926fcea 100644 --- a/packages/frontend/src/stdlib/analyses/diagram_graph.tsx +++ b/packages/frontend/src/stdlib/analyses/diagram_graph.tsx @@ -20,9 +20,9 @@ export default function DiagramGraph( const graph = () => { const theory = props.liveDiagram.liveModel.theory(); const model = props.liveDiagram.liveModel.elaboratedModel(); - const validatedDiagram = props.liveDiagram.validatedDiagram(); - if (theory && model && validatedDiagram?.tag === "Valid") { - return diagramToGraphviz(validatedDiagram.diagram, model, theory); + const diagram = props.liveDiagram.elaboratedDiagram(); + if (theory && model && diagram) { + return diagramToGraphviz(diagram, model, theory); } }; @@ -45,14 +45,13 @@ export function diagramToGraphviz( ): Viz.Graph { const nodes = new Map["nodes"][0]>(); for (const id of diagram.obGenerators()) { - const over = diagram.getObOver(id); - if (over?.tag !== "Basic") { + const ob = diagram.obPresentation(id); + if (!(ob && ob.over.tag === "Basic")) { continue; } - const obType = diagram.obType({ tag: "Basic", content: id }); - const meta = theory.instanceObTypeMeta(obType); - const label = diagram.obGeneratorLabel(id)?.join("."); - const overLabel = model.obGeneratorLabel(over.content)?.join("."); + const meta = theory.instanceObTypeMeta(ob.obType); + const label = ob.label?.join("."); + const overLabel = model.obGeneratorLabel(ob.over.content)?.join("."); nodes.set(id, { name: id, attributes: { @@ -66,16 +65,17 @@ export function diagramToGraphviz( const edges: Required["edges"] = []; for (const id of diagram.morGenerators()) { - const [dom, cod, over] = [diagram.getDom(id), diagram.getCod(id), diagram.getMorOver(id)]; - if (dom?.tag !== "Basic" || cod?.tag !== "Basic" || over?.tag !== "Basic") { + const mor = diagram.morPresentation(id); + if ( + !(mor && mor.dom.tag === "Basic" && mor.cod.tag === "Basic" && mor.over.tag === "Basic") + ) { continue; } - const morType = diagram.morType({ tag: "Basic", content: id }); - const meta = theory.instanceMorTypeMeta(morType); - const overLabel = model.morGeneratorLabel(over.content)?.join("."); + const meta = theory.instanceMorTypeMeta(mor.morType); + const overLabel = model.morGeneratorLabel(mor.over.content)?.join("."); edges.push({ - head: cod.content, - tail: dom.content, + head: mor.cod.content, + tail: mor.dom.content, attributes: { id, label: overLabel ?? "", diff --git a/packages/frontend/src/stdlib/analyses/linear_ode.tsx b/packages/frontend/src/stdlib/analyses/linear_ode.tsx index 8c235d941..a74d07a0d 100644 --- a/packages/frontend/src/stdlib/analyses/linear_ode.tsx +++ b/packages/frontend/src/stdlib/analyses/linear_ode.tsx @@ -43,7 +43,7 @@ export default function LinearODE( { contentType: "string", header: true, - content: (id) => morLabelOrDefault(id, elaboratedModel()), + content: (id) => morLabelOrDefault(id, elaboratedModel()) ?? "", }, createNumericalColumn({ name: "Coefficient", diff --git a/packages/frontend/src/stdlib/analyses/lotka_volterra.tsx b/packages/frontend/src/stdlib/analyses/lotka_volterra.tsx index 4448eba81..2fd5ef28c 100644 --- a/packages/frontend/src/stdlib/analyses/lotka_volterra.tsx +++ b/packages/frontend/src/stdlib/analyses/lotka_volterra.tsx @@ -51,7 +51,7 @@ export default function LotkaVolterra( { contentType: "string", header: true, - content: (id) => morLabelOrDefault(id, elaboratedModel()), + content: (id) => morLabelOrDefault(id, elaboratedModel()) ?? "", }, createNumericalColumn({ name: "Interaction", diff --git a/packages/frontend/src/stdlib/analyses/mass_action.tsx b/packages/frontend/src/stdlib/analyses/mass_action.tsx index d87b6e235..36330c399 100644 --- a/packages/frontend/src/stdlib/analyses/mass_action.tsx +++ b/packages/frontend/src/stdlib/analyses/mass_action.tsx @@ -19,31 +19,29 @@ import "./simulation.css"; export default function MassAction( props: ModelAnalysisProps & { simulate: MassActionSimulator; - isState?: (obType: ObType) => boolean; - isTransition?: (morType: MorType) => boolean; + stateType?: ObType; + transitionType?: MorType; title?: string; }, ) { const elaboratedModel = () => props.liveModel.elaboratedModel(); const obGenerators = createMemo(() => { - const [model, pred] = [elaboratedModel(), props.isState]; + const model = elaboratedModel(); if (!model) { return []; } - return model - .obGenerators() - .filter((id) => !pred || pred(model.obType({ tag: "Basic", content: id }))); + return props.stateType ? model.obGeneratorsWithType(props.stateType) : model.obGenerators(); }, []); const morGenerators = createMemo(() => { - const [model, pred] = [elaboratedModel(), props.isTransition]; + const model = elaboratedModel(); if (!model) { return []; } - return model - .morGenerators() - .filter((id) => !pred || pred(model.morType({ tag: "Basic", content: id }))); + return props.transitionType + ? model.morGeneratorsWithType(props.transitionType) + : model.morGenerators(); }, []); const obSchema: ColumnSchema[] = [ @@ -67,7 +65,7 @@ export default function MassAction( { contentType: "string", header: true, - content: (id) => morLabelOrDefault(id, elaboratedModel()), + content: (id) => morLabelOrDefault(id, elaboratedModel()) ?? "", }, createNumericalColumn({ name: "Rate", diff --git a/packages/frontend/src/stdlib/analyses/model_graph.tsx b/packages/frontend/src/stdlib/analyses/model_graph.tsx index 6ab27d16d..9d696a4ad 100644 --- a/packages/frontend/src/stdlib/analyses/model_graph.tsx +++ b/packages/frontend/src/stdlib/analyses/model_graph.tsx @@ -47,13 +47,13 @@ export function modelToGraphviz( ): Viz.Graph { const nodes: Required["nodes"] = []; for (const id of obGenerators ?? model.obGenerators()) { - const obType = model.obType({ tag: "Basic", content: id }); - const meta = theory.modelObTypeMeta(obType); + const ob = model.obPresentation(id); + const meta = theory.modelObTypeMeta(ob.obType); nodes.push({ name: id, attributes: { id, - label: model.obGeneratorLabel(id)?.join(".") ?? "", + label: ob.label?.join(".") ?? "", class: graphStyles.svgCssClasses(meta).join(" "), fontname: graphStyles.graphvizFontname(meta), }, @@ -62,18 +62,17 @@ export function modelToGraphviz( const edges: Required["edges"] = []; for (const id of morGenerators ?? model.morGenerators()) { - const [dom, cod] = [model.getDom(id), model.getCod(id)]; - if (!(dom?.tag === "Basic" && cod?.tag === "Basic")) { + const mor = model.morPresentation(id); + if (!(mor && mor.dom.tag === "Basic" && mor.cod.tag === "Basic")) { continue; } - const morType = model.morType({ tag: "Basic", content: id }); - const meta = theory.modelMorTypeMeta(morType); + const meta = theory.modelMorTypeMeta(mor.morType); edges.push({ - head: cod.content, - tail: dom.content, + head: mor.cod.content, + tail: mor.dom.content, attributes: { id: id, - label: model.morGeneratorLabel(id)?.join(".") ?? "", + label: mor.label?.join(".") ?? "", class: graphStyles.svgCssClasses(meta).join(" "), fontname: graphStyles.graphvizFontname(meta), // Not recognized by Graphviz but will be passed through! diff --git a/packages/frontend/src/stdlib/analyses/petri_net_visualization.tsx b/packages/frontend/src/stdlib/analyses/petri_net_visualization.tsx index 2604e9c14..0d9b5ded8 100644 --- a/packages/frontend/src/stdlib/analyses/petri_net_visualization.tsx +++ b/packages/frontend/src/stdlib/analyses/petri_net_visualization.tsx @@ -1,4 +1,5 @@ import type * as Viz from "@viz-js/viz"; +import invariant from "tiny-invariant"; import { type DblModel, collectProduct } from "catlog-wasm"; import type { ModelAnalysisProps } from "../../analysis"; @@ -34,11 +35,12 @@ export function petriNetToGraphviz(model: DblModel): Viz.Graph { // Add nodes for places. const nodes: Required["nodes"] = []; for (const id of model.obGenerators()) { + const ob = model.obPresentation(id); nodes.push({ name: id, attributes: { id, - label: model.obGeneratorLabel(id)?.join(".") ?? "", + label: ob.label?.join(".") ?? "", class: svgStyles["place"], width: "0.5", height: "0.5", @@ -49,31 +51,30 @@ export function petriNetToGraphviz(model: DblModel): Viz.Graph { /// Add nodes for transitions and edges for arcs. const edges: Required["edges"] = []; for (const id of model.morGenerators()) { + const mor = model.morPresentation(id); + if (!mor) { + continue; + } nodes.push({ name: id, attributes: { id, - label: model.morGeneratorLabel(id)?.join(".") ?? "", + label: mor.label?.join(".") ?? "", class: svgStyles["transition"], width: "1", height: "0.25", }, }); - const [dom, cod] = [model.getDom(id), model.getCod(id)]; - for (const ob of dom ? collectProduct(dom) : []) { - if (ob.tag !== "Basic") { - continue; - } + for (const ob of collectProduct(mor.dom)) { + invariant(ob.tag === "Basic"); edges.push({ head: id, tail: ob.content, }); } - for (const ob of cod ? collectProduct(cod) : []) { - if (ob.tag !== "Basic") { - continue; - } + for (const ob of collectProduct(mor.cod)) { + invariant(ob.tag === "Basic"); edges.push({ head: ob.content, tail: id, diff --git a/packages/frontend/src/stdlib/analyses/stock_flow_diagram.tsx b/packages/frontend/src/stdlib/analyses/stock_flow_diagram.tsx index b5031ac87..50813c568 100644 --- a/packages/frontend/src/stdlib/analyses/stock_flow_diagram.tsx +++ b/packages/frontend/src/stdlib/analyses/stock_flow_diagram.tsx @@ -106,13 +106,18 @@ function StockFlowSVG(props: { const nodeMap = uniqueIndexArray(props.layout?.nodes ?? [], (node) => node.id); const edgeMap = uniqueIndexArray(props.layout?.edges ?? [], (edge) => edge.id); for (const id of model.morGenerators()) { - const [dom, cod] = [model.getDom(id), model.getCod(id)]; + const mor = model.morPresentation(id); if ( - !(dom?.tag === "Basic" && cod?.tag === "Tabulated" && cod.content.tag === "Basic") + !( + mor && + mor.dom.tag === "Basic" && + mor.cod.tag === "Tabulated" && + mor.cod.content.tag === "Basic" + ) ) { continue; } - const [srcId, tgtId] = [dom.content, cod.content.content]; + const [srcId, tgtId] = [mor.dom.content, mor.cod.content.content]; const [srcNode, tgtEdge] = [nodeMap.get(srcId), edgeMap.get(tgtId)]; if (!srcNode || !tgtEdge) { continue; diff --git a/packages/frontend/src/stdlib/analyses/tabular_view.tsx b/packages/frontend/src/stdlib/analyses/tabular_view.tsx new file mode 100644 index 000000000..fa09054c2 --- /dev/null +++ b/packages/frontend/src/stdlib/analyses/tabular_view.tsx @@ -0,0 +1,60 @@ + +import type { DiagramAnalysisProps } from "../../analysis"; +import type { GraphLayoutConfig } from "../../visualization"; +// import { GraphVisualization } from "./graph_visualization"; +// import { diagramToGraphviz } from "./diagram_graph"; +import { createResource, Switch, Match } from "solid-js"; + +import axios from 'axios'; + +const config = { + url:"http://127.0.0.1:8080", + method: "post", + headers: { + 'Access-Control-Allow-Origin': '*', + 'Access-Control-Allow-Methods': 'POST, PUT, DELETE, GET, OPTIONS', + 'Access-Control-Allow-Headers': '*', + 'Access-Control-Allow-Credentials': 'false' + } +}; + + +/** Visualize a diagram in a model as a graph. + +Such a visualization makes sense for any discrete double theory and is in +general restricted to basic objects. See `ModelGraph` for more. + */ +export default function TabularView( + props: DiagramAnalysisProps & { + title?: string; + }, +) { + + const [res] = createResource( + () => { + const model = props.liveDiagram.liveModel.elaboratedModel(); + const diagram = props.liveDiagram.elaboratedDiagram(); + return model && diagram && [model, diagram]; + }, + async ([model, diagram]) => { + const response = await axios.post("http://127.0.0.1:8080/acsetcolim", { + model: model?.presentation(), diagram: diagram?.presentation() + }, config); + // console.log(response.data); + return response.data; + } + ); + return ( + + +
⏳ Loading model...
+
+ +
❌ Error loading model: {res.error?.message || "Unknown error"}
+
+ + {(res) =>
Tabular Instance: {JSON.stringify(res())}
} +
+
+ ); +} diff --git a/packages/frontend/src/stdlib/theories/primitive-stock-flow.ts b/packages/frontend/src/stdlib/theories/primitive-stock-flow.ts index 9ff9f2b15..471d13796 100644 --- a/packages/frontend/src/stdlib/theories/primitive-stock-flow.ts +++ b/packages/frontend/src/stdlib/theories/primitive-stock-flow.ts @@ -53,8 +53,9 @@ export default function createPrimitiveStockFlowTheory(theoryMeta: TheoryMeta): simulate(model, data) { return thCategoryLinks.massAction(model, data); }, - isTransition(morType) { - return morType.tag === "Hom"; + transitionType: { + tag: "Hom", + content: { tag: "Basic", content: "Object" }, }, }), ], diff --git a/packages/frontend/src/stdlib/theories/simple-schema.ts b/packages/frontend/src/stdlib/theories/simple-schema.ts index 97e39f1d5..5d9db54b7 100644 --- a/packages/frontend/src/stdlib/theories/simple-schema.ts +++ b/packages/frontend/src/stdlib/theories/simple-schema.ts @@ -113,6 +113,13 @@ export default function createSchemaTheory(theoryMeta: TheoryMeta): Theory { description: "Visualize the instance as a graph", help: "visualization", }), + analyses.tabularView({ + id: "tabularview", + name: "Tabular Visualization", + description: "Visualize the instance as a table", + help: "tabularview", + }), + ], }); }