Skip to content

Commit

Permalink
Do not always compose intermediates by default
Browse files Browse the repository at this point in the history
  • Loading branch information
lukem12345 committed Jun 24, 2024
1 parent f2ff150 commit 5b5a5ba
Show file tree
Hide file tree
Showing 2 changed files with 46 additions and 11 deletions.
28 changes: 19 additions & 9 deletions src/composition.jl
Original file line number Diff line number Diff line change
Expand Up @@ -220,31 +220,41 @@ oapply(r::RelationDiagram, pode::OpenSummationDecapode) = oapply(r, [pode])
# Default composition
# -------------------

# TODO: Upstream this to Catlab?
function construct_relation_diagram(boxes::Vector{Symbol}, junctions::Vector{Vector{Symbol}})
tables = map(boxes, junctions) do b, j
Expr(:call, b, j...)
end
quote @relation () begin $(tables...) end end |> eval
end

# TODO: Add a macro which provides names for boxes via the Symbol of the Decapode.
""" function default_composition_diagram(podes::Vector{D}, names::Vector{Symbol}) where {D<:SummationDecapode}
Given a list of Decapodes and their names, return a composition diagram which assumes that variables sharing the same name ought to be composed.
Only variables which are found in multiple Decapodes are exposed. No Literals are exposed.
No Literals are exposed. Use [`unique_lits!`](@ref) after composing.
Throw an error if any individual Decapode already contains a repeated name (except for Literals).
If `only_states_terminals` is `true`, only expose state and terminal variables. Defaults to `false`.
Note that composing immediately with [`oapply`](@ref) will fail if types do not match (e.g. (:infer, :Form0) or (:Form0, :Form1)). So, use the function [`infer_types_from_diagram!`](@ref) after this if needed.
"""
function default_composition_diagram(podes::Vector{D}, names::Vector{Symbol}) where {D<:SummationDecapode}
function default_composition_diagram(podes::Vector{D}, names::Vector{Symbol}, only_states_terminals=false) where {D<:SummationDecapode}
non_lit_names = map(podes) do pode
pode[findall(!=(:Literal), pode[:type]), :name]
end
for (nln, name) in zip(non_lit_names, names)
allunique(nln) || error("Decapode $name contains a repeated variable name.")
allunique(nln) || error("Decapode $name contains repeated variable names: $nln.")
end
all_names = union(non_lit_names...)
tables = map(names, non_lit_names) do name, nln
Expr(:call, name, intersect(all_names, nln)...)
if only_states_terminals
foreach(non_lit_names, podes) do nln, pode
outers = infer_state_names(pode) pode[infer_terminals(pode), :name]
filter!(x -> x outers, nln)
end
end
# XXX: The only means of creating a RelationDiagram is via the DSL or
# tracking your own indices via @acset/ imperatively.
quote @relation () begin $(tables...) end end |> eval
construct_relation_diagram(names, non_lit_names)
end

""" function infer_types_from_diagram!(r::RelationDiagram, podes::Vector{D}) where {D<:SummationDecapode}
Expand Down
29 changes: 27 additions & 2 deletions test/composition.jl
Original file line number Diff line number Diff line change
Expand Up @@ -222,8 +222,33 @@ end
Advection(C,V,ϕ₂)
Superposition(C,ϕ₁,ϕ₂,Ċ,ϕ)
end
@test default_composition_diagram(
[Diffusion, Advection, Superposition], [:Diffusion, :Advection, :Superposition]) == expected
@test is_isomorphic(expected, default_composition_diagram(
[Diffusion, Advection, Superposition],
[:Diffusion, :Advection, :Superposition]))

# Compose Halfar's equation with Glen's law.
GlensLaw = @decapode begin
Γ::Form1
(A,ρ,g,n)::Constant

Γ == (2/(n+2))*A**g)^n
end
HalfarsEquation = @decapode begin
h::Form0
Γ::Form1
n::Constant

∂ₜ(h) == (, d, )(Γ * d(h) (mag((d(h)))^(n-1)) (h^(n+2)))
end
expected =
@relation () begin
GlensLaw(Γ,A,ρ,g,n)
HalfarsEquation(h,Γ,n,ḣ)
end
@test is_isomorphic(expected, default_composition_diagram(
[GlensLaw, HalfarsEquation],
[:GlensLaw, :HalfarsEquation],
true))
end

# end

0 comments on commit 5b5a5ba

Please sign in to comment.